Redis的設計與實現-讀書筆記(一)

SDS

SDS的定義

在Redis中使用SDS(簡單動態字符串)來代替c風格字符串

struct SDS{
	int len,free;
	char buf[];
}

SDS與C風格字符串的區別

  • O(1)獲取SDS長度
  • 通過分析free來杜絕緩衝區溢出
  • 通過空間預分配(大於1M分配1M,小於1M分配2倍)和惰性釋放(提供了內存釋放API)減少內存分配次數
  • 二進制安全(因爲使用len而不是’\0’來判斷結束)
  • SDS使用’\0’來結尾,所以可以複用部分C函數

鏈表

列表,慢查詢,發佈訂閱,監視器等功能中都用到了鏈表

Redis中鏈表的結構

typedef struct list{
	listNode *head,*tail;//頭,尾
	unsigned long len;//長度
	void *(*dup)(void *ptr);//複製函數
	void (*free)(void *ptr);//釋放函數
	int (*match)(void *ptr,void *key);//匹配判斷函數
}list;

listNode 的底層是雙向無環鏈表

字典

Redis中數據庫,哈希表等功能的底層都用到了字典

字典的實現

typedef struct dictht{
	dictEntry **table;//值數組
	unsigned long size; // 哈希表大小
	unsigned long sizemask;//掩碼
	unsigned long used;//已使用數量
}
typedef struct dictEntry{
	void *key;//鍵
	union{//值
		void *val;
		uint64_t u64;
		int64_t s64;
	}v;
	struct dictEntry *next;//下個哈希表節點
}dictEntry;
typedef struct dict{
	dictType* type;
	void *privatedata;
	dictht ht[2];//維護兩個,爲了完成負載因子均衡
	int trehashidx;//不在rehash時,值爲-1
}

在Redis中會根據不同的鍵類型,選擇不同的處理函數(type->hashFunction() , 如計算,處理,銷燬函數),Redis使用MH2算法.

解決鍵衝突

使用鏈地址法,在鏈的頭部插入新節點,保證插入的O1複雜度

處理負載因子

負載因子 = 保存節點數量 / size
在進行bgsave,bgrewrite時 觸發rehash的負載因子值爲5 , 不進行時爲 1 (因爲要避免寫時複製時多餘的內存寫入)

利用ht[1]來完成擴展(第一個大於used*2的2的冪)或者收縮(第一個大於used的2的冪) 空間大小
在大小改變後,將ht[0]中的元素rehash到ht[1]中,完成後交換兩者地址,完成rehash

漸進式rehash:每次訪問ht[0]時rehash一個rehashidx上的數據,當rehashidx等於達到上限時說明rehash完畢,將rehashidx置爲-1(通過漸進rehash避免服務長時間停止響應)

rehash 讀操作 會先在ht[0],後在ht[1]上讀 , 寫操作全部寫在ht[1]

跳錶

跳躍表支持平均logN,最壞o(N)的不穩定查找複雜度,可以通過順序性批量操作節點,是有序列表的底層實現之一,還是集羣內部的數據結構.

typedef struct zskiplistNode{
	struct zskiplistNode *backward; // 後退指針
	double score;//分數
	robj *obj;//實際對象
	struct zskiplistLevel{ //層
		struct zskiplistLevel *forward; //每層上的前進指針
		unsigned int span; // 跨度
	}level[];//層的大小是1~32的隨機數
}zskiplistNode;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章