1. 程式人生 > >redis cluster叢集 原理、機制及原始碼分析

redis cluster叢集 原理、機制及原始碼分析

* 需求背景

1、擴充套件性:單機記憶體資源有限,要動態地節點擴容、節點縮容;

2、主從、資料備份和容災;

3、redis是單執行緒io結構,多核結構的server發揮不到作用;

方案有:client sharding、twemproxy、redis cluster、proxy+redis cluster;----> codis proxy+zookeeper/nginx+redis 

1、支援資料分片;

2、主從備份,支援主從自動切換;

3、讀請求負載均衡;

4、支援節點failover,資料自動遷移;

功能

1、節點自動發現

* 通過客戶端meet訊息,把節點加入叢集中;  

* 每個節點每秒從已知節點中隨機選五個節點,傳送ping pong訊息,當接收者有選中節點,更新對這個節點的認知;如果沒有選中節點的資訊,接受者與被選中節點進行握手;

* 一個節點可以通過向叢集廣播自己的pong訊息讓叢集中的其他節點立即重新整理關於這個節點的認識;

* slave節點發現用cluster replicate node_id,通過訊息傳送給叢集中其他節點,最終讓其他叢集節點感知到;

2、命令請求分配到不同節點叢集處理

* key 做 crc(key)&16383 -->得到槽位;

* 為每個節點分配槽位資訊,並且傳播節點槽位指派資訊給其他節點,且每個節點有一個全域性記錄每個槽位對應的處理節點資訊(cluster_node);

* 當命令給的節點不是對應的槽為處理節點,向客戶端傳送moved錯誤,重定位節點;

3、節點備份 複製

4、故障遷移 slave節點轉移為master節點,從節點選舉為主節點

* 故障檢測機制:每個節點定期向其他節點發ping訊息,規定time內是否返回pong;如果超時,疑似下線pfail,疑似下線有fail_report,有疑似下線報告;

* 叢集中的各個節點會通過互相傳送訊息的方式來交換急群眾的各個節點的狀態資訊,例如某個節點處於下線狀態、疑似下線狀態、還是已經下線狀態;

*在叢集中,半數以上負責槽位的節點將主節點x報告為pfail,這個主節點x將標誌為fail;標誌為主節點x為下線的節點立即向叢集廣播一條關於x的fail訊息,所有接收到fail訊息的節點,就立即將x節點標誌位fail;

* 選舉新主節點:slave節點檢測到下線fail,立即廣播clustermsg_type_failover_ath_request訊息,之後收到其他主節點clustermsg_type_failover_auth_ok訊息;當收到clustermsg_type_failover_auth_ok訊息數大於等於N/2+1,就被選舉為主節點;

* 故障遷移:被選為主節點的從節點自己進行故障轉移操作,新主節點自己執行slaveof no one;槽位接管;當資料遷移及槽位接管後,向其他主節點廣播pong訊息,讓其他節點認識新的節點;

5、擴容 縮容

* redis-trib setslot <slot> importing source_ip,target_node 準備匯入slot鍵值對;

* redis-trib setslot <slot> migrating target_ip,source_ip準備遷移slot鍵值對;

* 源節點是否儲存了術語slot的鍵值,如果有,將鍵全部遷移到目標節點;最後將slot指派給目標節點,廣播slot重分配訊息告知slot分配給了目標節點;

* 在槽位重分配的過程中,slot的鍵值對可能存在兩個節點中,ask錯誤,指引客戶端轉向target目標節點;

場景識別

* 叢集中gossip協議,節點發現;^_^
* 資料分片,向叢集傳送不同key的訊息;^_^
* 擴容 縮容 槽位遷移;^_^
* 故障檢測 從節點選舉 和資料遷移^_^

原始碼分析

此圖截圖來源於書籍《redis 設計與實現》黃健巨集著

* 設定key-value和獲取key-value

此圖截圖來源於書籍《redis 設計與實現》黃健巨集著

* 資料遷移:key-value的遷移是客戶端控制的,用migrate命令把key-value遷移到指定的槽位;

*向目標節點發送cluster setslot <slot> importing <source_ip>,讓目標節點準備好從源節點匯入資料槽slot的鍵值對;

* 對源節點發送 cluster setslot <slot> magrating <target_ip>,讓源節點準備好將屬於slot的鍵值對遷移到目標節點;

* 向源節點發送 cluster getkeysinslot <slot> <count> 命令,達到count個鍵名;

* 對於每個得到的鍵名,向源節點發送一個migrate <target_ip> <target_port> <key_name> 0 <timeout>命令,將選中的鍵原子的從源節點遷移到目標節點;

* 最後,向叢集的任意一個節點發送cluster setslot <slot> node <target_id>,將槽位slot指派給目標節點。

此說明主要參考書籍《redis 設計與實現》黃健巨集著