剛開始看redis..總結一下看到的東西,有些話是參考網上的,有些話是類似自己白話說的,若有不對請指正。
Redis
redis常用五種數據結構:string hash list set sortedset
String:(字符串)
一個key對應一個value,是二進制安全的
typedef char *sds;
struct sdshdr {
int len;// 記錄 buf 數組中已使用字節的數量 等於 SDS 所保存字符串的長度
int free;// 記錄 buf 數組中未使用字節的數量
char buf[];// 字節數組,用於保存字符串
};
一個sds實際申請的內存: sizeof(sdshdr)+len+free+1 剛開始free爲0,當需要增長時根據策略進行動態增長
List:(列表/雙向鏈表)
typedef struct listNode {
struct listNode *prev; //指向前一個節點
struct listNode *next; //指向後一個節點
void *value;//值
} listNode;//節點
typedef struct list {
listNode *head;//雙向鏈表的頭節點
listNode *tail;//雙向鏈表的尾節點
void *(*dup)(void *ptr);//複製
void (*free)(void *ptr);//釋放
int (*match)(void *ptr, void *key);//匹配
unsigned long len;//鏈表長度
} list;//雙向鏈表/列表
typedef struct listIter {
listNode *next;//指向列表的某個節點
int direction;//迭代方向
} listIter;//訪問鏈表的迭代器
Hash:(哈希)
是一個string類型的field和value的映射表,適用於儲存對象
Set:(集合)
底層實現是哈希,一般情況使用0號哈希表,如果在rehash時,則會同時使用0號和1號哈希表
哈希表採用鏈地址法解決鍵衝突,自動rehash收縮或者擴展哈希表
typedef struct dictEntry {
void *key; //鍵
union {
void *val;
uint64_t u64;
int64_t s64;
} v; //值
struct dictEntry *next;//指向下一個節點
} dictEntry;//哈希節點
typedef struct dictht {
dictEntry **table; //桶 哈希節點類型
unsigned long size;//指針數組大小
unsigned long sizemask;//指針數組掩碼,用於計算索引值
unsigned long used;//hash表現有節點數量
} dictht;//哈希表
typedef struct dict {
dictType *type; //類型處理函數
void *privdata; //類型處理函數私有值
dictht ht[2];//兩個hash表
int rehashidx; //rehash標示,爲-1表示不在rehash,不爲0表示正在rehash的桶
int iterators; //當前正在運行的安全迭代器數量
} dict;//集合有2個哈希表
Rehash:創建比ht[0]->table更大的ht[1]->table,size爲大於use*2的2的指數,開始值爲4,然後把ht[0]的鍵值對遷移到ht[1]中,將ht[0]中數據清空,將新的ht[1]替代ht[0]。
進行rehash的條件:
自然 rehash : ratio >= 1 ,且變量 dict_can_resize 爲真。
強制 rehash : ratio 大於變量 dict_force_resize_ratio (目前版本中, dict_force_resize_ratio 的值爲 5 )。
Sorted set:(有序集合)
Redis 有序集合和集合一樣也是string類型元素的集合,且不允許重複的成員。
不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來爲集合中的成員進行從小到大的排序。
有序集合的成員是唯一的,但分數(score)卻可以重複。
typedef struct zskiplistNode {
robj *obj; // 成員對象
double score;// 分值
struct zskiplistNode *backward; // 後退指針
struct zskiplistLevel {
struct zskiplistNode *forward; // 前進指針
unsigned int span;// 跨度
} level[]; // 層
} zskiplistNode;//有序集合的節點
typedef struct zskiplist {
struct zskiplistNode *header, *tail; // 表頭節點和表尾節點
unsigned long length;// 表中節點的數量
int level;// 表中層數最大的節點的層數
} zskiplist;//有序集合
數據庫:
Redis客戶端默認目標數據庫爲0號數據庫
數據庫由dict(保存鍵值對)和expires(保存鍵的過期時間)兩字典組成
RDB持久化
服務器中的非空數據庫以及他們的鍵值對統稱爲數據庫狀態。
RDB持久化可將數據庫狀態保存在磁盤,可手動執行也可定期執行。通過該文件可還原數據庫狀態。
RDB文件是經過壓縮的二進制文件,對於不同類型的鍵值對,RDB會以不同方式來保存。
SAVE或者BGSAVE可生成rdb文件。
SAVE會阻塞服務器進程,到創建完成前都不能處理任何命令請求。BGSAVE會派生出一個子進程來創建RDB,父進程就可以執行其他命令了。
服務器啓動時如果檢測到RDB文件就會載入,如果開啓了AOF持久化功能,則優先用AOF文件。
AOF持久化
AOF持久化是通過保存redis服務器所執行的寫命令來記錄數據庫狀態。
實現:命令追加、文件寫入、文件同步
命令追加:服務器執行寫命令過後,會將寫命令追加到服務器狀態緩衝區的末尾。
文件寫入與同步:在每次結束一個事件循環前,會考慮將緩衝區的內容寫入AOF文件。
發佈和訂閱:
SUBSCRIBE:客戶端可以訂閱一個或多個頻道,成爲這些頻道的訂閱者。每當有客戶端向這些頻道發消息的時候,頻道的所有訂閱者都可以收到這條消息。
PSUBSCRIBE:客戶端可以訂閱一個或多個模式,成爲這些模式的訂閱者。每當有客戶端向這些頻道發消息的時候,訂閱頻道以及與這個頻道相匹配的模式的訂閱者都會收到消息。
事務:redis用multi和exec打包事務
以multi開始exec結束,服務器執行事務期間不會中斷去執行其他命令。
redis不支持回滾機制,若一個事務在入隊命令過程中,出現了命令不存在或者格式錯誤則服務器拒絕執行此事務。