持久化
- RDB容易丟失數(shù)據隅俘,AOF通過合適的fsync策略丟失更少的數(shù)據
- AOF體積大考赛,但是可以自動重寫
- RDB適合數(shù)據備份
RDB
- 把內存里的key-value快照寫到磁盤文件里
- fork一個子進程來生成RDB文件
- RDB文件是二進制文件
- 在一定的時間段內執(zhí)行一定數(shù)量的寫操作颜骤,會觸發(fā)BGRDB
AOF
- 將執(zhí)行過的寫操作記錄到AOF文件里
- AOF是一個文本文件
- 先寫緩存捣卤,然后同步到AOF文件里。同步策略有3種鸠项,比如其中一種是每隔1秒同步一次AOF文件
- AOF文件太大了之后會觸發(fā)AOF重寫子姜。重寫是根據當時的key-value來重新生成寫操作,所以跟已經存在的AOF文件不相關
- AOF重寫過程中的寫操作記錄在緩存牧抽,最后會追加到AOF文件里
數(shù)據庫
- 默認16個數(shù)據庫扬舒,編號從0開始。集群里只能使用0號數(shù)據庫
- 數(shù)據庫內部是一個dict結構
- keyspace@{dbid}:{key} 頻道通知key的操作
- keyevents@{dbid}:{ops} 頻道通知操作的key
過期
- expires字典(dict)記錄key的過期時間
- 惰性刪除策略孕惜,操作的時候判斷key是否過期晨炕,過期則刪除
- 定期刪除策略,啟一個job碧磅,隨機刪除N個過期的key
LRU
- HashMap + 雙向鏈表,每次訪問之后移到鏈頭
- 近似淘汰算法:隨機取出若干個key丰榴,按照訪問時間排序,淘汰最不經常使用的
淘汰策略
- noeviction 不淘汰
- volatile-lru 設置了過期時間的key參與LRU
- allkeys-lru 所有的key參與LRU
- volatile-random 隨機淘汰設置了過期時間的key
- allkeys-random 隨機淘汰所有的key
- volatile-ttl 設置了過期時間的key中存活時間最短的
主從復制
- 角色:主節(jié)點换况,從節(jié)點
- 從節(jié)點第一次連上主節(jié)點盗蟆,發(fā)送命令PSYNC喳资,主節(jié)點會執(zhí)行全局復制:生成RDB文件,并發(fā)送給從節(jié)點(同時會把生成RDB文件過程中的寫操作也發(fā)送給從節(jié)點)
- 同步完成之后鲜滩,主節(jié)點會把寫命令傳播給從節(jié)點(命令傳播)
- 從節(jié)點斷線重連之后节值,發(fā)送命令PSYNC給主節(jié)點,主節(jié)點會執(zhí)行部分復制:根據從節(jié)點的offset搞疗,從replication backlog里讀取未同步的命令,發(fā)送給從節(jié)點
- replication backlog是一個固定大小的先進先出隊列豌汇,每個位置存儲了一個字節(jié)
- 從節(jié)點定時發(fā)送心跳檢查給主節(jié)點业簿,主節(jié)點檢查到從節(jié)點的offset小于自己的offset,也會把未同步的命令補償給從節(jié)點柜思,整個過程與部分復制類似
Sentinel
建立
- 角色:哨兵巷燥,主節(jié)點,從節(jié)點
- 哨兵和主節(jié)點建立命令和訂閱鏈接
- 哨兵每10秒向主節(jié)點發(fā)送INFO命令陨享,從返回消息里了解主節(jié)點钝腺,并發(fā)現(xiàn)從節(jié)點
- 哨兵每10秒向從節(jié)點發(fā)送INFO命令艳狐,更新從節(jié)點和主節(jié)點的信息
- 哨兵每2秒向主從節(jié)點發(fā)送消息,包括哨兵和主節(jié)點的信息蔬啡,使其他哨兵發(fā)現(xiàn)自己镀虐,然后哨兵之間建立命令鏈接
故障轉移
- 哨兵每秒向所有節(jié)點發(fā)送PING命令,返回PONG
- 在一個時間范圍內空猜,連續(xù)返回無效回復恨旱,則標識為主觀下線
- 哨兵檢測到主節(jié)點主觀下線后,發(fā)送命令SENTINEL is-master-down-by-addr漓摩,回復是否主觀下線
- 哨兵收集到一定數(shù)量的主觀下線管毙,則把節(jié)點標識為客觀下線
- 選舉領頭哨兵
- 從節(jié)點中挑選一個節(jié)點,轉換為主節(jié)點
- 其他從節(jié)點改為復制新的主節(jié)點
- 已下線的主節(jié)點設置為從節(jié)點
集群
建立集群
- 客戶端發(fā)送CLUSTER MEET 命令把節(jié)點B加入節(jié)點A的集群
- 節(jié)點A發(fā)送MEET命令給B夭咬,B發(fā)送PONG命令給A,A再發(fā)送PING給B南用,握手完成
槽指派
- 集群的整個數(shù)據庫被分成16384個槽slot, 每個節(jié)點指派一部分槽
- 客戶端發(fā)送 CLUSTER AddSlots 命令把槽指派給節(jié)點
- 節(jié)點發(fā)送消息給其他節(jié)點裹虫,告知自己負責哪些槽
執(zhí)行命令
- 節(jié)點計算key使用哪個槽(CRC16)融击,如果是自己則執(zhí)行命令,如果不是則返回MOVED錯誤匣屡,指引客戶端轉向正確的節(jié)點
重新分片
- 向目標節(jié)點發(fā)送 CLUSTER SETSLOT slot IMPORTING source 命令拇涤,讓目標節(jié)點準備好從源節(jié)點導入槽
- 向源節(jié)點發(fā)送 CLUSTER SETSLOT slot MIGRATING target 命令,讓源節(jié)點準備好遷移槽
- 向源節(jié)點發(fā)送 CLUSTER GetKeysInSlot slot count 命令券躁,返回key name列表
- 對每個key如绸,向源節(jié)點發(fā)送 Migrate target key 命令怔接,遷移
- 向任意節(jié)點發(fā)送 CLUSTER SetSlot slot NODE target 命令扼脐,告知槽已經重新指派
在重新分片過程中奋刽,如果源節(jié)點不存在key,則返回ASK錯誤
客戶端發(fā)送 ASKING 命令給目標節(jié)點佣谐,再發(fā)送原來的命令;如果不發(fā)送ASKING命令罚攀,則目標節(jié)點會返回Moved錯誤
故障轉移
- 通過發(fā)送PING消息來檢測對方是否在線,如果在規(guī)定的時間里沒有返回PONG斋泄,則標識為 疑似下線PFail
- 如果半數(shù)以上的節(jié)點都標記為 疑似下線炫掐,則標記為 已下線Fail
- 選擇一個從節(jié)點成為新的主節(jié)點
數(shù)據結構
- string:int, embstr, raw,
- list:雙向鏈表, ziplist, linked list
- hash: 映射表。數(shù)據較少時通過ziplist實現(xiàn)旗唁,數(shù)據較多時通過dict實現(xiàn)
- set: 集合摔认,數(shù)據少時intset, 通過hash實現(xiàn)
- zset: 有序集合,ziplist, skiplist
Sorted Set
- 數(shù)據較少時电谣,通過ziplist實現(xiàn)抹蚀。壓縮鏈表,元素壓縮編碼
- 數(shù)據較多時晒来,通過zset實現(xiàn)郑现,包含一個dict和一個skiplist。dict用來查詢數(shù)據到score的映射關系攒读,skiplist用來根據score查詢數(shù)據(支持范圍查詢)辛友。
- dict: 字典,鏈表解決碰撞
- skiplist: 跳表邓梅,實現(xiàn)簡單邑滨,范圍查詢,內存占用少
發(fā)布訂閱
- 角色:Channel掖看,Publisher,Subscriber
命令:
- PUBLISH
- SUBSCRIBE
- UNSUBSCRIBE
- PSUBSCRIBE
- UNPSUBSCRIBE
訂閱Channel
- redisServer.pubsub_channels 字典
- 把client添加到channel墨礁,一個channel對應多個client
- 把channel添加到client
訂閱模式
- redisServer.pubsub_patterns 鏈表
- 把{client,pattern}添加到鏈表里
發(fā)布消息
- 在字典里找出channel,遍歷上面的client列表焕毫,發(fā)送信息給client
- 遍歷模式列表驶乾,如果模式能夠匹配channel,發(fā)送信息給client
謝謝閱讀疙咸!