1. 程式人生 > >Redis筆記1(資料結構)

Redis筆記1(資料結構)

redis的特點

(1)優點

  • 資料結構豐富----方便操作,比如佇列的先進先出,hash結構O(1)的快速查詢,sorted-set有序集合方便獲取排名
  • 資料在記憶體操作—快速
  • 單執行緒處理—避免鎖
  • 非阻塞式IO多路複用—充分利用網路IO
  • 設計簡單,效率高
  • 方便擴充套件,不像mysql一樣分庫分表,只要簡單擴大記憶體,或增加redis個數
    (2)缺點
  • Rdb備份不具備實時性
  • Aof持久化比較消耗記憶體和cpu,甚至當aof檔案過大的時候佔用磁碟

基礎資料結構

1 SDS

應用場景: list物件當列表比較長,而且儲存的內容也比較長的時候,採用此種資料結構編碼(類似於線性表)

struct sdshdr {
    int len; // buf 中已佔用空間的長度
    int free;// buf 中剩餘可用空間的長度
    char buf[]; // 資料空間,以’\0’結尾
};

相比字串做出的優化

  • 常數複雜度獲取字串長度-----sds->len
  • 杜絕緩衝區溢位-----通過free的長度來判斷是否有充足的空間
  • 減少修改字串時帶來的記憶體重分配次數----free夠的時候,不需要重分配,只有free不足的時候需要擴充套件。如果對字串收縮也不需要立刻回收空間,只需要修改len和free的屬性即可。----空間預分配和惰性空間釋放
  • 二進位制安全
  • SDS相對C字串雖然有些操作更快更便捷,但是這是以事先預分配超過需求的空間,以及記錄len和free來完成的。這個過程有點以犧牲空間換時間的方法。而且這個len和free大小設定也是一門技術活!

2.連結串列

方便插入刪除,方便重排,特別適合佇列這種頻繁的push和pop的操作

3.字典

用於儲存鍵值對,Redis 的資料庫就是使用字典來作為底層實現,雜湊表也是
漸進式Rehash
隨著操作的不斷執行,雜湊表儲存的鍵值對會逐漸地增多或者減少,為了讓hash表的負載因子(load factor)維持在一個合理的範圍之內,當雜湊表儲存的鍵值對數量太多或者太少時,程式需要對hash表的大小進行相應的擴充套件活放縮。

hash表的負載因子 = hash節點個數/hash表的長度

為了避免rehash(hash節點個數可能成百上千萬個)對伺服器效能造成影響,伺服器不是一次性將ht[0]裡面的所有鍵值對全部rehash到ht[1], 而是分多次、漸進式地將ht[0]裡面的鍵值對慢慢地rehash到ht[1].

漸進式rehash的基本步驟是:

(1)為ht[1]分配空間,讓字典同時持有ht[0]和ht[1]兩個雜湊表

(2)在字典中維持一個索引計數器變數rehashidx,並將它的值設定為0,標識rehash開始。

(3)在rehash進行期間,每次對字典執行新增、刪除、查詢、刪除或者更新操作時,程式除了執行指定的操作以外,還會順帶將ht[0]雜湊表在rehashidx索引上的所有鍵值對rehash到ht[1], 當rehash工作完成之後,程式將rehashidx屬性的值增一。

(4)隨著字典操作的不斷執行,最終在某個時間點上,ht[0]的所有鍵值對都會被rehash至ht[1],這時程式將rehashidx的屬性的值設為-1,表示rehash操作已完成。

漸進式rehash的好處在於它採取分而治之的方式,將rehash鍵值對所需的計算工作均攤到字典的每個新增刪除查詢和更新操作上,從而避免了集中式rehash而帶來的龐大計算量。

4. 跳躍表

跳躍表(skiplist)是一種有序資料結構,它通過在某個節點中維持多個指向其他節點的指標,從而達到快速訪問節點的目的。

redis中的應用:有序集合鍵,叢集節點中用作內部資料結構

類似紅黑樹,但是實現較紅黑樹簡單。排序或者有序查詢可以達到二分查詢的效率,該資料結構是以空間換時間。

5. 整數集合

整數集合是集合鍵的底層實現之一, 當一個集合只包含整數值元素,並且這個集合的元素數量不多時,Redis就會使用整數集合作為集合鍵的底層實現。

6. 壓縮列表—記憶體編碼的資料結構(節省記憶體)

壓縮列表是列表鍵和hash鍵的底層實現之一。當一個列表鍵只包含少量列表項,並且每個列表項要麼就是小整數值,要麼就是長度比較短的字串,那麼redis就會使用壓縮列表來做列表鍵的底層實現。

7. redis物件(頂層)

Redis並沒有直接使用這些資料結構來實現鍵值對資料庫,而是基於這些資料庫建立了一個物件系統,比如字串物件,列表物件,集合物件,hash表物件,有序集合對等

使用物件的好處在於:

(1)我們可以針對不同的使用場景,為物件設定多種不同的資料結構實現,從而優化物件在不同場景下的使用效率—對應redisObject中的encoding

(2)Redis的物件還實現了基於引用計數計數的記憶體回收機制—對應redisObject中的refCount

(3)Redis還通過引用計數實現了物件共享機制

(4)Redis物件帶有訪問時間記錄資訊,該資訊可以計算資料庫鍵的空轉時長,從而確定在記憶體不足的情況下是否優先刪除

因為C語言並不具備自動記憶體回收功能,所以redis物件系統構建了一個引用計數refcount技術來實現記憶體回收機制,通過這一機制,程式可以通過跟蹤物件的引用計數資訊,在適當的時候自動釋放物件進行記憶體回收。

物件的引用計數資訊會隨著物件的使用狀態而不斷變化:

在建立一個新物件時,引用計數的值會被初始化為1;
  當物件被一個新程式使用時,它的引用計數值會被增1
  當物件不再被一個程式使用時,它的引用計數會減1
  當物件的引用計數為0時,物件所佔用的記憶體會被釋放。