redis的資料結構之 String 和
請允許我拽一句文化詞兒 工欲善其事必先利其器。 這裡的器就是我們redis的根本 有什麼樣的資料結構決定了它適合做什麼樣的事兒。
------------------------------------------------------------分割線------------------------------------------------------------- 快取大致可以分為兩類: 記憶體快取元件:(別問我有哪些 ,沒研究過。有興趣的話 自己去研究) 分散式快取元件:Redis ,MongoDb(市場佔有率正在萎縮因其維護起來比較卵疼),HBase(大資料方向的)
--------------------上乾貨-------------------------------------------
初識redis
官網地址:
持久化:redis支援資料持久化 也別急後面也會分享到
value型別: 1、String -------別方(慌)就是java中的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物件內部使用linkedlist和ziplist 當資料量比較小的時候 使用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