redis複製
一、主從複製
1、命令
PSYNC:該命令具有完整重同步和部分重同步。
完成重同步:通過主伺服器創建並發送RDB文件,以及向從伺服器發送保存在緩衝區那裡面的寫命令來進行同步。
部分重同步:當從伺服器在斷線重連主伺服器之後,則主伺服器將主從伺服器斷開期間執行的寫命令發送給從伺服器。從伺服器接收並執行這些寫命令。
部分重同步實現:
1)主伺服器的複製偏移量和從伺服器的複製偏移量
1、主伺服器每次向從伺服器傳播N個位元組的數據時,就將自己的複製偏移量的值加上N
2、從伺服器每次接收到主伺服器傳播來的N個位元組的數據時,就將自己的複製偏移量的值加上N
通過對比主從伺服器的偏移量可以確定主從伺服器狀態是否一致。
2)主伺服器的複製積壓緩衝區
主伺服器維護的一個固定長度,先進先出隊列,默認大小1MB。
當主伺服器進行命令傳播時,它不僅將寫命令發送給所有從伺服器,還會講寫命令入隊到複製積壓緩衝區。
當從伺服器重連時,從伺服器通過PSYNV命令將自己的複製偏移量offset發送給主伺服器,主伺服器有以下抉擇:
1、如果offset偏移量之後的數據,仍然存在於複製緩衝區,那麼主伺服器將對從伺服器執行部分重同步操作
2、相反,如果不存在,則執行完整的重同步操作。
3)伺服器的運行ID(run ID)
1、每個redis伺服器,無論主伺服器還是從伺服器,都會有自己的運行ID
2、運行ID在伺服器啟動時自動生成,由40個隨機的十六進位字元組成。
主伺服器根據從伺服器發送過來的運行ID,決定執行部分重同步還是完整重同步。
2、複製實現
1)從伺服器設置主伺服器的地址和埠:SLAVEOF
2)建立套接字連接:從伺服器根據IP和埠,創建連接。
3)發送ping命令:檢查讀寫狀態;檢查主伺服器能否正常處理命令請求
4)身份驗證
5)發送埠資訊:REPLCONF listening-port <port-number> 向主伺服器發送從伺服器的監聽埠。
6)同步:從伺服器向主伺服器發送PSYNC命令,執行同步操作。
7)命令傳播
二、哨兵(Sentinel)
1、概念
有一個或多個Sentinel實例組成的Sentinel系統,可以監視任意多個主伺服器,以及這些主伺服器屬下的所有從伺服器,並在主伺服器
進入下線狀態時,自動通過投票方法,將主伺服器屬下的某個從伺服器升級為新的主伺服器。
2、啟動並初始化Sentinel
$ redis-sentinel /path/to/you/sentinel.conf 或者通過命令 $ redis-server /path/to/your/sentinel.conf –sentinel
1)初始化伺服器
Sentinel本質是一個運行在特殊模式下的Redis伺服器,但是初始化是與普通的伺服器不同,不載入RDB文件或者AOF文件。
2)將普通redis伺服器使用的程式碼替換成Sentinel專用程式碼
3)初始化Sentinel狀態
初始化Sentinel狀態中的masters字典,裡面記錄了所有唄Sentinel監視的主伺服器相關資訊。
4)根據給定的配置文件,初始化Sentinel的監視主伺服器列表
初始化上面提到的字典。
5)創建連向主伺服器的網路連接
Sentinel會創建兩個連向主伺服器的非同步網路連接
1、命令連接:向主伺服器發送命令,並接收命令回復
2、訂閱連接,訂閱主伺服器的_sentinel_:hello頻道
當Sentinel發現有新的從伺服器出現時,會創建連接到從伺服器的命令連接和訂閱連接。
3、選舉領頭Sentinel
當一個主伺服器被判斷客觀下線時,監視這個下線主伺服器的各個Sentinel會進行協商,選舉出一個領頭Sentinel,並由領頭Sentinel對下線主伺服器
執行故障轉移操作:
1、設置規則:
1)所有sentinel(源)都向另一個sentinel(目的)發送命令,要求目的將自己設置為局部sentinel(源)
2)先到先得,最先向目標Sentinel發送設置要求的源Sentinel將成為Sentinel的局部Sentinel,
3)如果某個sentine被半數以上的sentinel設置為局部領頭,則這個sentinel成為領頭sentinel。
4)如果規定時間沒有選舉出,則再次選舉。
4、故障轉移
領頭sentinel在已下線主伺服器屬下的所有從伺服器中,挑選出一個狀態良好、數據完整的從伺服器,將其轉換為主伺服器。
所有從伺服器都保存在一個列表裡面,將通過以下規則進行過濾:
1)刪除下線或者斷線的從伺服器
2)刪除類表中5秒內沒有回復過領頭sentinel的INFO命令的從伺服器
3)刪除與已下線主伺服器連接斷開超多規定時間的從伺服器。
4)選舉優先順序搞的從伺服器
5)如果有多個相同優先順序的從伺服器,則按照從伺服器的複製偏移量,挑選出偏移量最大的從伺服器
6)如果還有多個,則挑選運行ID最小的從伺服器。
三、集群
1、節點
1)一個redis集群通常由多個節點(每個節點就是一個redis伺服器)組成,在剛開始的時候,每個節點都是相互獨立的,
都處於只包含自己的集群里,需要將各個獨立的節點連接起來,才能構成一個包含多個節點的集群
2)連接命令:CLUSTER MEET <ip> <port> 發送命令後節點進行握手,握手成功時,節點就會將ip和port所指定的節點添加到自己的集群中。
3)啟動節點:根據配置:cluster-enabled是否為yes來決定是否開啟伺服器的集群模式。
4)握手過程(A->B):
1、節點A為B創建一個clusterNode結構,並將該結構添加到自己的clusterStater.nodes字典里
2、A根據CLUSTER MEET命令給定的IP和port,向B發送一條MEET消息
3、B接收到A的MEET消息,為A創建一個clusterNode結構,並添加到自己的字典里
4、B向A發送一條PONG消息
5、A接收到B的PONG消息,發送一條PING消息。
至此握手完成,之後A會將節點B的資訊通過Gossip協議傳播給集群的其他節點,讓其他節點和B進行握手,
經過一段時間之後,節點B會被集群中的所有節點認識。
2、槽指派
redis集群通過分片的方式來保存資料庫中的鍵值對:集群的整個資料庫被分為16384個槽(slot),資料庫中的每個鍵都屬於這16384個slot的其中一個,集群中的每個
節點可以處理0個或最多16384個slot。
1)指派命令:CLUSTER ADDSLOTS <slot> [slot] 命令可以指派一個或多個slot給節點負責。
2)slots屬性:每個節點都包含一個slots屬性,其是一個二進位數組,包含16384個位元組,以0為起始索引,16383為終止索引。節點根據索引上的二進位位的值
來判斷是否負責處理槽i,如果二進位位上的值為1,則負責處理該槽,為0則不負責處理該槽。
節點之間通過傳播節點的槽指派資訊,獲知其他節點的槽指派資訊,並將其保存在為其創建的slusterNode節點裡。
3、集群中執行命令:
1)執行過程:客戶端向某個節點發起命令請求,如果該節點保存,則回復;否則返回一個MOVED錯誤,並直營客戶端轉向正確節點,並再次發送之前想要執行的命令。
MOVED錯誤格式:MOVED <slot> <ip>:<port>
2)計算鍵屬於哪個槽:
def slot_number(key) return CRC16(key) & 16383
先計算CRC-16校驗和,之後&16383,確定鍵key的槽號。
3)節點資料庫的實現
集群節點資料庫保存鍵值對以及鍵值對過期時間的方式,和單機伺服器相同。區別在於,節點只能使用0號資料庫,單機資料庫沒有限制。
4、重新分片
redis集群重新發片操作由redis的集群管理軟體redis-trib負責執行,redis-trib通過向源節點和目標節點發送命令來進行重新分片
1)命令:
1、redis-trib對目標節點發送 CLUSTER SETLOT <slot> IMPORTING <source_id>:讓目標節點準備好從源節點導入(import)屬於槽slot的鍵值對。
2、redis-trib對源節點發送 CLUSTER SETLOT <slot> MIGRATING <target_id>:讓源節點準備好將屬於槽slot的鍵值對遷移至目標節點。
3、redis-trib對源節點發送 CLUSTER GETKEYSINSLOT <slot> <count>:獲得最多count哥屬於槽slot的鍵值對的鍵名
4、對於步驟三獲得的每個鍵名,redis-trib對源節點發送MIGRATE <target_ip> <target_port> <key_name> 0 <timeout>:將被選中的鍵原子地從源節點遷移至目標節點。
5、重複步驟三和步驟四,將所有屬於槽的鍵值對進行遷移。
6、向任意一個節點發送CLUSTER SETSLOT <slot> NODE <target_id>:將槽slot指派給目標節點這個資訊,告知這個節點,這一指派資訊會通過消息傳播至整個集群,集群的其他節點就會獲知這一消息。
5、複製和故障轉移
redis集群中的節點分為主節點和從節點,主節點負責處理槽,從節點用於複製某個主節點,並在主節點下線時,代替主節點繼續處理命令。
1)設置從節點命令:CLUSTER REPLICATE <node_id>:可以讓接收命令的節點成為node_id的所指定的從節點,並開始對主節點進行複製
2)故障檢測:集群中的每個節點都會定期向集群中的其他節點發送ping消息,如果目標沒有在規定時間返回pong消息,則被標記為疑似下線。如果半數以上節點將該節點標記為疑似下線,則目標主節點表標記為已下線。
例如:有四個主節點7000,7001,7002,7003。如果7001收到主節點7002、主節點7003發送的主節點7000疑似下線消息,並且自己也認為該節點下線。
那麼主節點7001將在集群中廣播一條主節點7000的FAILL消息,所有收到的消息的節點將主節點7000標記為已下線。
3、故障轉移
1)複製下線主節點的所有從節點裡面,會有一個從節點被選中
2)被選中的節點執行SLAVEOF no one命令,成為新的主節點
3)新的主節點會側小所有對已下線主節點的槽指派,並將槽全部派給自己
4)新的主節點廣播一條pong消息,告知自己接管工作。
5)新主節點開始工作
4、選舉新的主節點
1)集群里每個負責處理槽的主節點都有一次投票機會
2)從節點發現自己正在複製的主節點進入下線狀態,會向集群中廣播,要求接收到消息的並且具有投票權的主節點向這個從節點投票
3)具有投票權的主節點向第一個發送給他的消息的從節點投票
4)當一個從節點收到N/2+1張支援票時,則該從節點會當選為新的主節點。
5)如果一個配置紀元(一輪投票)里沒有收集到足夠多的選票,則再次進行。
選舉新節點的方法和選舉領頭sentinel的方法相似,兩者都給予RAFT演算法的領頭選舉方法實現。