1. 程式人生 > >redis的資料結構之 String 和

redis的資料結構之 String 和

請允許我拽一句文化詞兒 工欲善其事必先利其器。 這裡的器就是我們redis的根本 有什麼樣的資料結構決定了它適合做什麼樣的事兒。

------------------------------------------------------------分割線------------------------------------------------------------- 快取大致可以分為兩類: 記憶體快取元件:(別問我有哪些 ,沒研究過。有興趣的話 自己去研究) 分散式快取元件:Redis ,MongoDb(市場佔有率正在萎縮因其維護起來比較卵疼),HBase(大資料方向的)

--------------------上乾貨------------------------------------------- 初識redis 官網地址:

https://redis.io/ 沒事多逛逛 命令集:http://redisdoc.com/index.html Remote Dictionary Server(遠端資料服務) 這樣看來它更像一個字典,例如大部分人用過的《新華字典》 redis例項 就是在伺服器上安裝的那個軟體 db redis的db更類似於namespace的概念。單例的redis例項中有16個db,注意這裡強調單例 在叢集模式下 則只有一個db key 可以稱為控制代碼;用來讀取資料 value 有多種資料結構;用來存值。別急 下面會分享的。

持久化:redis支援資料持久化 也別急後面也會分享到

value型別: 1、String -------別方(慌)就是java中的String 它支援

: 1.1、字串 1.2、整數 1.3、浮點 它的內部結構 兩種:一種是int ;二種是SDS,Simple Dynamic String; 用途:整數數用int ,字串或位元組串用或者浮點數String 如果你懂得c語言的話 哈哈 那麼恭喜你可以去看一下這種資料型別的原始碼了 搜尋sds.h 這個檔案 這裡是String型別資料的結構原始碼

番外篇 :和SDS有關 二進位制安全: 在C語言的字串裡,我們儲存資料就必須符合某種編碼規則 ,並且除了字串的末尾之外在字串的末尾也不能包含空格,否則程式在讀取資料時會把空格認為是結尾標識。所以這樣一個規定 使得C語言只能儲存文字資料而不能儲存音訊,視訊等資料; 由此引入了二進位制安全 在此用’\n’來表示結束 替代了空格 這就是二進位制安全 (理解的比較粗淺)

如果閱讀原始碼的話會看到這樣的結構 struct sttribute((packed))sdshdr5{*******} 這裡的sdshdr5 是SDS的header 表示可以儲存多大長度的字串

預設是用sdshdr8 來儲存資料的

如何根據header來計算該結構可以存放多長的資料呢? soooooo!!!!! easy 就sdshdr8來講 它儲存的長度是 2^8-1個 位元組(byte也叫bit) 從redis3.2只有SDS有5種結構了 sdshdr5(這個是沒有用到的,原因是 在大概87行有這樣幾個串串 char type = sdsReqType(initlen);//獲取字元長長度 if(type==SDS_TYPE_5 && initlen ==0 ) type=SDS_TYPE_8; //怎麼樣講到這裡有沒有豁然開朗; SDS_TYPE_5被直接轉換到SDS_TYPE_8了; sdshdr8 sdshdr16 sdshdr32 sdshdr64

----------------------------再碼一段番外篇---------------------- 假如我們存了一個 “hello”,那麼這個裡面的屬性都做了什麼呢? sdshdr8 len len=5 alloc alloc=5 flag flag= 比如說是001吧 這個flag是sdshdr8的一個標誌, 每個header都對應了一個標誌;當然實際上可能是另外一個數值,這裡僅僅是舉例 buf[] [‘h’,‘e’,‘l’,‘l’,‘o’,\0] 實際上是這樣的 \0 是出於二進位制安全的結尾符 這個結尾符不會計入到len 或alloc長度當中去的

那麼這裡還會涉及到擴容 這就是另外一回事了 ,有興趣的話自己研究C語言去 那麼String的應用場景是什麼呢 ip限制 防止一個ip在單位時間內惡意的多次訪問 結合incr使用 另一個關注點是 namespace 為防止大規模使用redis中 key的衝突 儘量在key命名時體現namespace 如user.***** order.****同時還應注意可以的長度,避免過多的網路開銷 2、list 連結串列 一個key對應多個value 可以從兩邊讀取元素,它具有連結串列所有的優缺點; 優點:訪問連結串列兩端的資料時速度非常快時間複雜度是O(1) 缺點:當資料量非常大時 比如100k;通過下標訪問資料的時候 會非常慢 它的操作命令是: lpush 從左邊壓入(新增)元素 lpop 從左邊彈出元素 rpush 從右邊壓入(新增)元素 rpop 從右邊彈出元素 記住先進後出的原則 比如我們這樣操作 lpush mylist 1 2 3 4 rpush mylist 0 -1 lrang mylist 0 -1 可以看到他的資料是這樣式兒的 1) 4 2) 3 3) 2 4) 1 5) 0 6) -1 list的資料結構在3.2這個版本遇到了一個分水嶺 在3.2之前 value物件內部使用linkedlistziplist 當資料量比較小的時候 使用ziplist 以節省記憶體空間 當元素個數比較多或單個元素比較長的時候 會使用雙向連結串列linkedlist

在3.2之後 使用quicklist quicklist對linkedlist和ziplist的兩個優點做了彙總 linkedlist 優點: 對兩端的資料進行操作速度非常快既複雜度比較低 缺點:但是記憶體開銷比較大 ziplist 優點:記憶體開銷比較小 缺點:因為它是一段連續的記憶體儲存,所以當對其進行資料插入和刪除時,會頻繁申請記憶體降低了速度

所以結合這兩者的有點quicklist應運而生 其本質是linkedlist 但是它有一個特點:它是基於ziplist的linkedlist 。

有點繞?!我來解釋一下: 可以想象成一個鏈條,這個鏈條就是linkedlist,然而這個鏈條中的每一個環卻是ziplist。對!!簡單粗暴的糅合

有一點需要講清楚 quicklist裡面儲存的ziplist裡面有兩種儲存方式 一種是壓縮 一種是不壓縮的 那麼怎麼區分呢? 看它的資料結構 quicklist tail head count len

head指向quicklistnode

quicklistnode中有這些屬性 prev next zl 其中zl指向ziplist(壓縮資料)和quicklistLZF(非壓縮資料) 然而quicklistnode又是一個雙向連結串列可以前後互相指向 所以它是這樣一個儲存方式 總結一下 quicklist中的每個節點時quicklistnode,每一個quicklistnode裡都有兩種資料結構 這兩種結構是 ziplist和quicklistLZF

所以quicklist是一個經過特殊編碼的linckedlist

那麼它的使用場景是什麼呢 1、分散式佇列 利用 先進先出 比如生產者和消費者 生產者把訊息壓入redis的list ----lpush 消費者從redis的list中彈出訊息------brpop同步彈出資料 rpop 和 brpop 是同一個命令 只是brpop會阻塞 2、實現棧,當做MQ來實現 利用它後進先出的特性 lpush、lpop 3、佇列 lpush rpop