Redis是什麼?看這一篇就夠了

来源:https://www.cnblogs.com/powertoolsteam/archive/2019/11/26/redis.html

在Web應用發展的初期,那時關係型資料庫受到了較為廣泛的關註和應用,原因是因為那時候Web站點基本上訪問和併發不高、交互也較少。而在後來,隨著訪問量的提升,使用關係型資料庫的Web站點多多少少都開始在性能上出現了一些瓶頸,為了剋服這一問題,Redis應運而生,讓我們通過本文一起來瞭解下Redis 是... ...


本文由葡萄城技術團隊編撰並首發

轉載請註明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。

引言

在Web應用發展的初期,那時關係型資料庫受到了較為廣泛的關註和應用,原因是因為那時候Web站點基本上訪問和併發不高、交互也較少。而在後來,隨著訪問量的提升,使用關係型資料庫的Web站點多多少少都開始在性能上出現了一些瓶頸,而瓶頸的源頭一般是在磁碟的I/O上。而隨著互聯網技術的進一步發展,各種類型的應用層出不窮,這導致在當今雲計算、大數據盛行的時代,對性能有了更多的需求,主要體現在以下四個方面:

  1. 低延遲的讀寫速度:應用快速地反應能極大地提升用戶的滿意度
  2. 支撐海量的數據和流量:對於搜索這樣大型應用而言,需要利用PB級別的數據和能應對百萬級的流量
  3. 大規模集群的管理:系統管理員希望分散式應用能更簡單的部署和管理
  4. 龐大運營成本的考量:IT部門希望在硬體成本、軟體成本和人力成本能夠有大幅度地降低

為了剋服這一問題,NoSQL應運而生,它同時具備了高性能、可擴展性強、高可用等優點,受到廣泛開發人員和倉庫管理人員的青睞。

Redis是什麼

Redis是現在最受歡迎的NoSQL資料庫之一,Redis是一個使用ANSI C編寫的開源、包含多種數據結構、支持網路、基於記憶體、可選持久性的鍵值對存儲資料庫,其具備如下特性:

  • 基於記憶體運行,性能高效
  • 支持分散式,理論上可以無限擴展
  • key-value存儲系統
  • 開源的使用ANSI C語言編寫、遵守BSD協議、支持網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API

相比於其他資料庫類型,Redis具備的特點是:

  • C/S通訊模型
  • 單進程單線程模型
  • 豐富的數據類型
  • 操作具有原子性
  • 持久化
  • 高併發讀寫
  • 支持lua腳本

哪些大廠在使用Redis?

  • github
  • twitter
  • 微博
  • Stack Overflow
  • 阿裡巴巴
  • 百度
  • 美團
  • 搜狐

Redis的應用場景有哪些?

Redis 的應用場景包括:緩存系統(“熱點”數據:高頻讀、低頻寫)、計數器、消息隊列系統、排行榜、社交網路和實時系統。

 

Redis的數據類型及主要特性

Redis提供的數據類型主要分為5種自有類型和一種自定義類型,這5種自有類型包括:String類型、哈希類型、列表類型、集合類型和順序集合類型。

String類型:

它是一個二進位安全的字元串,意味著它不僅能夠存儲字元串、還能存儲圖片、視頻等多種類型, 最大長度支持512M。

對每種數據類型,Redis都提供了豐富的操作命令,如:

  • GET/MGET
  • SET/SETEX/MSET/MSETNX
  • INCR/DECR
  • GETSET
  • DEL

哈希類型:

該類型是由field和關聯的value組成的map。其中,field和value都是字元串類型的。

Hash的操作命令如下:

  • HGET/HMGET/HGETALL
  • HSET/HMSET/HSETNX
  • HEXISTS/HLEN
  • HKEYS/HDEL
  • HVALS

列表類型:

該類型是一個插入順序排序的字元串元素集合, 基於雙鏈表實現。

List的操作命令如下:

  • LPUSH/LPUSHX/LPOP/RPUSH/RPUSHX/RPOP/LINSERT/LSET
  • LINDEX/LRANGE
  • LLEN/LTRIM

集合類型:

Set類型是一種無順序集合, 它和List類型最大的區別是:集合中的元素沒有順序, 且元素是唯一的。

Set類型的底層是通過哈希表實現的,其操作命令為:

  • SADD/SPOP/SMOVE/SCARD
  • SINTER/SDIFF/SDIFFSTORE/SUNION

Set類型主要應用於:在某些場景,如社交場景中,通過交集、並集和差集運算,通過Set類型可以非常方便地查找共同好友、共同關註和共同偏好等社交關係。

順序集合類型:

ZSet是一種有序集合類型,每個元素都會關聯一個double類型的分數權值,通過這個權值來為集合中的成員進行從小到大的排序。與Set類型一樣,其底層也是通過哈希表實現的。

ZSet命令:

  • ZADD/ZPOP/ZMOVE/ZCARD/ZCOUNT
  • ZINTER/ZDIFF/ZDIFFSTORE/ZUNION

Redis的數據結構

Redis的數據結構如下圖所示:

關於上表中的部分釋義:

  1. 壓縮列表是列表鍵和哈希鍵的底層實現之一。當一個列表鍵只包含少量列表項,並且每個列表項要麼就是小整數,要麼就是長度比較短的字元串,Redis就會使用壓縮列表來做列表鍵的底層實現
  2. 整數集合是集合鍵的底層實現之一,當一個集合只包含整數值元素,並且這個集合的元素數量不多時,Redis就會使用整數集合作為集合鍵的底層實現

如下是定義一個Struct數據結構的例子:

 

簡單動態字元串SDS (Simple Dynamic String)

基於C語言中傳統字元串的缺陷,Redis自己構建了一種名為簡單動態字元串的抽象類型,簡稱SDS,其結構如下:

SDS幾乎貫穿了Redis的所有數據結構,應用十分廣泛。

SDS的特點

和C字元串相比,SDS的特點如下:

  1. 常數複雜度獲取字元串長度

    Redis中利用SDS字元串的len屬性可以直接獲取到所保存的字元串的長
    度,直接將獲取字元串長度所需的複雜度從C字元串的O(N)降低到了O(1)。

  2. 減少修改字元串時導致的記憶體重新分配次數

    通過C字元串的特性,我們知道對於一個包含了N個字元的C字元串來說,其底層實現總是N+1個字元長的數組(額外一個空字元結尾)

    那麼如果這個時候需要對字元串進行修改,程式就需要提前對這個C字元串數組進行一次記憶體重分配(可能是擴展或者釋放) 

    而記憶體重分配就意味著是一個耗時的操作。

Redis巧妙的使用了SDS避免了C字元串的缺陷。在SDS中,buf數組的長度不一定就是字元串的字元數量加一,buf數組裡面可以包含未使用的位元組,而這些未使用的位元組由free屬性記錄。

與此同時,SDS採用了空間預分配的策略,避免C字元串每一次修改時都需要進行記憶體重分配的耗時操作,將記憶體重分配從原來的每修改N次就分配N次——>降低到了修改N次最多分配N次。

如下是Redis對SDS的簡單定義:

  

Redis特性1:事務

  • 命令序列化,按順序執行
  • 原子性
  • 三階段: 開始事務 - 命令入隊 - 執行事務
  • 命令:MULTI/EXEC/DISCARD

Redis特性2:發佈訂閱(Pub/Sub)

  • Pub/sub是一種消息通訊模式
  • Pub發送消息, Sub接受消息
  • Redis客戶端可以訂閱任意數量的頻道
  • “fire and forgot”, 發送即遺忘
  • 命令:Publish/Subscribe/Psubscribe/UnSub

  

Redis特性3:Stream

  • Redis 5.0新增
  • 等待消費
  • 消費組(組內競爭)
  • 消費歷史數據
  • FIFO

 

 

 

以上就是Redis的基本概念,下麵我們將介紹在開發過程中可能會踩到的“坑”。

Redis常見問題解析:擊穿

概念:在Redis獲取某一key時, 由於key不存在, 而必須向DB發起一次請求的行為, 稱為“Redis擊穿”。

引發擊穿的原因:

  • 第一次訪問
  • 惡意訪問不存在的key
  • Key過期

合理的規避方案:

  • 伺服器啟動時, 提前寫入
  • 規範key的命名, 通過中間件攔截
  • 對某些高頻訪問的Key,設置合理的TTL或永不過期

Redis常見問題解析:雪崩

概念:Redis緩存層由於某種原因宕機後,所有的請求會涌向存儲層,短時間內的高併發請求可能會導致存儲層掛機,稱之為“Redis雪崩”。

合理的規避方案:

  • 使用Redis集群
  • 限流

Redis在產品開發中的應用實踐

為此,我很高興的為大家介紹,葡萄城架構師Jim將在2019-11-27 14:00 為大家帶來一場公開課,其中 Jim除了為大家講解Redis的基礎,同時也會實際演示他所在的項目組使用Redis時碰到的問題以及解決方案,對於剛接觸Redis的同學來說,更具參考意義和學習價值,歡迎大家屆時參加,公開課地址:https://live.vhall.com/661463644

  • 後端採用nodeJS
  • 使用Azure的Redis服務
  • Redis的使用場景

    -  token緩存, 用於令牌驗證

    -  IP白名單

碰到的問題

  • “網路抖動”或者Redis服務異常導致Redis訪問超時
  • Redis客戶端驅動穩定性問題

    -  連接池 “Broken connection” 問題

    -  JS的Promise引出的Redis重置問題

下麵我們來簡單瞭解一下Redis的進階知識。

進階之Redis協議簡介

Redis客戶端通訊協議:RESP(Redis Serialization Protocol),其特點是:

  • 簡單
  • 解析速度快
  • 可讀性好

Redis集群內部通訊協議:RECP(Redis Cluster Protocol ) ,其特點是:

  • 每一個node兩個tcp 連接
  • 一個負責client-server通訊(P: 6379)
  • 一個負責node之間通訊(P: 10000 + 6379)

 

Redis協議支持的數據類型:

  • 簡單字元(首位元組: “+”)

        “+OK\r\n”

  • 錯誤(首位元組: “-”)

        “-error msg\r\n”

  • 數字(首位元組: “:”)

        “:123\r\n”

  • 批量字元(首位元組: “$”)

        “&hello\r\nWhoa re you\r\n”

  • 數組(首位元組: “*”)

        “*0\r\n”

        “*-1\r\n”

除了Redis,還有什麼NoSQL型資料庫

市面上類似於Redis,同樣是NoSQL型的資料庫有很多,如下圖所示,除了Redis,還有MemCache、Cassadra和Mongo。下麵,我們就分別對這幾個資料庫做一下簡要的介紹:

 

 

Memcache這是一個和Redis非常相似的資料庫,但是它的數據類型沒有Redis豐富。Memcache由LiveJournal的Brad Fitzpatrick開發,作為一套分散式的高速緩存系統,被許多網站使用以提升網站的訪問速度,對於一些大型的、需要頻繁訪問資料庫的網站訪問速度的提升效果十分顯著。

Apache Cassandra(社區內一般簡稱為C*)這是一套開源分散式NoSQL資料庫系統。它最初由Facebook開發,用於儲存收件箱等簡單格式數據,集Google BigTable的數據模型與Amazon Dynamo的完全分散式架構於一身。Facebook於2008將 Cassandra 開源,由於其良好的可擴展性和性能,被 Apple、Comcast、Instagram、Spotify、eBay、Rackspace、Netflix等知名網站所採用,成為了一種流行的分散式結構化數據存儲方案。

MongoDB:是一個基於分散式文件存儲、面向文檔的NoSQL資料庫,由C++編寫,旨在為WEB應用提供可擴展的高性能數據存儲解決方案。MongoDB是一個介於關係資料庫和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富,最像關係型資料庫的,它支持的數據結構非常鬆散,是一種類似json的BSON格式。

總結

以上就是Redis入門介紹教程,如果各位還想瞭解更多,歡迎通過評論和私信的方式告訴我。

 


您的分享是我們最大的動力!

更多相關文章
  • https://sqlserver.code.blog/2019/11/26/missing-msi-and-msp-files/ ...
  • 預讀:用估計信息,去硬碟讀取數據到緩存。預讀100次,也就是估計將要從硬碟中讀取了100頁數據到緩存。 物理讀:查詢計劃生成好以後,如果緩存缺少所需要的數據,讓緩存再次去讀硬碟。物理讀10頁,從硬碟中讀取10頁數據到緩存。 邏輯讀:從緩存中取出所有數據。邏輯讀100次,也就是從緩存里取到100頁數據 ...
  • bitmap就是在一個二進位的數據中,每一個位代表一定的含義,這樣最終只需要存一個整型數據,就可以解釋出多個含義.業務中有一個欄位專門用來存儲用戶對某些功能的開啟和關閉,如果是傳統的思維,肯定是建一個欄位來存0代表關閉,1代表開啟,那麼如果功能很多或者需要加功能開關,就需要不停的創建欄位.使用bit ...
  • 背 景: 在MySQL中如果是有限的層次,比如我們事先如果可以確定這個樹的最大深度, 那麼所有節點為根的樹的深度均不會超過樹的最大深度,則我們可以直接通過left join來實現。 但很多時候我們是無法控制或者是知道樹的深度的。這時就需要在MySQL中用存儲過程(函數)來實現或者在程式中使用遞歸來實 ...
  • select A.* from tb_mend_enrol A, (select A.Typeid, A.address from tb_mend_enrol A group by A.Typeid, A.address having count(A.Typeid) >= 2 and count(A ...
  • [20191126]探究等待事件的本源2.txt--//做一個測試,驗證如果寫入控制文件慢也會影響提交性能.1.環境:[email protected]> @ ver1PORT_STRING VERSION BANNER x86_64/Linux 2.4.xx 11.2.0.4.0 Oracle Database ...
  • -- 1.提取此類數據中的1的索引位置,從1開始 例: 0001100001100 --> 4,5,10,11 create or replace function hazq_instr_contains( v_str in varchar2)return varchar2is v_count nu ...
  • 一、問題描述: 需要將工作界面上的一些已經離職的用戶狀態改為失效,並備註為離職 二、需要準備/拿到手的工具/條件/數據: 1.已離職人員名單(excel格式) 2.任意mongodb工具(筆者使用的是NoSQLBooster for Mongodb) 3.連接好的mongodb資料庫(有些網路/策略 ...
一周排行
  • C#實現(Delegate)的委托就不多說了,直接上代碼,看代碼中的註釋: namespace Delegate { delegate void DGSayiHi(string name);//聲明委托 delegate void DGDo(string name); class Program { ...
  • C#實現的從小到大的冒泡排序: public void BubbleSort(int[] array) { int length = array.Length; for (int i = 0; i < length - 1; i++) { for (int j = length - 1; j > i ...
  • string aa = DateTime.Now.ToShortDateString();//"2019/9/23" string bb = DateTime.Now.ToShortTimeString();//"上午 10:21" string ff = DateTime.Now.ToLongDa ...
  • 1. 什麼是,以及怎麼用畫中畫 Windows 10 Creators Update以後UWP提供了一個新的視圖模式CompactOverlay,中文翻譯成 緊湊的覆蓋層 ?反正大部分時間我們都會稱它為 畫中畫模式 。 上圖中右上角即為進入畫中畫模式的微軟“電影和電視”應用。 可以調用 "Appli ...
  • C#實現的對兩個Table進行Merge,兩表必須存在至少一個公共欄位作為連接項,否則連接就失去了意義。如下是對兩個table進行Merge的詳細代碼: private void button1_Click(object sender, EventArgs e)//Button點擊觸發事件 { #r ...
  • 在很多時候,我們做一些非常規化的界面的時候,往往需要創建一些用戶控制項,在其中繪製好一些基礎的界面塊,作為後續重覆使用的一個單元,用戶控制項同時也可以封裝處理一些簡單的邏輯。在開發Winform各種類型項目,我都時不時需要定製一些特殊的用戶控制項,以方便在界面模塊中反覆使用。我們一般是在自定義的用戶控制項里... ...
  • 第一部分:面向對象 封裝 繼承(里氏轉換) 多態第二部分:值類型、引用類型、字元串操作第三部分:集合文件操作第四部分:正則表達式第五部分:XML操作第六部分:委托、事件第七部分:反射。 //存儲著我們當前正在運行的進程//Process[] pro = Process.GetProcesses(); ...
  • 程式處理存放圖片的幾種方式 我的理解有4個: 1:放在項目本身得文件夾中,直接部署到伺服器上 2:存放在磁碟中,然後資料庫中存放路徑,讀取得時候傳路徑。這個適合小項目 3:將圖片轉換成二進位文件,但是不建議這樣做,因為會給資料庫造成壓力。 4:存放在雲存儲器上,也是在資料庫上存地址,不過是雲地址,使 ...
  • 什麼是AutoMapper?AutoMapper是一個簡單的小型庫,用於解決一個看似複雜的問題 - 擺脫將一個對象映射到另一個對象的代碼。這種類型的代碼是相當沉悶和無聊的寫,所以為什麼不發明一個工具來為我們做? 我們來看看在.netcore3.1中怎樣使用AutoMapper9.0。 Profile ...
  • Teigha中實體旋轉 代碼: using (var trans = database.TransactionManager.StartTransaction()) { Entity ent = trans.GetObject(entityId, OpenMode.ForWrite) asEntit ...
x