兩種redis集群解決方案:codis和cluster
1、Codis
codis是一個代理中間件,當客戶端向codis發送指令時,codis負責將指令轉發到后面的redis來執行,並將結果返回給客戶端。
一個codis實例可以連接多個redis實例,也可以啟動多個codis實例來支撐,每個codis節點都是對等的,這樣可以增加整體的QPS需求,還能起到容災功能。
槽位關系
codis根據key直接hash到1024個槽位,每個槽位對應后面的一個redis。計算出key的槽位就能將key轉發到正確的redis實例。
槽位關系一旦變化,就會涉及所有redis實例,codis用zookeeper來存儲槽位關系(集群配置中心),還提供了一個dashboard模塊來觀察和修改槽位關系。
槽位關系發生變化時,codis會用一個新的命令來查找指定槽位中的所有key,然后遷移每個key到正確的槽位。當請求打在正在遷移的槽位上時,codis會強制對該key進行遷移。
codis有自動均衡功能,在系統空閑時觀察每個redis實例對應的槽位數量,不均衡時就會自動遷移。
codis命令
對於批量獲取多個key的命令,codis會向每一個redis發送命令,然后匯總。
codis損失了redis的一些特性,因為原來存在一個redis里的key現在分散了,所以事務不支持了,rename這種涉及兩個key的命令也不支持了。
codis優缺點
codis增加了一層代理,網絡開銷變大。
codis優點:分布式交給了第三方處理,dashboard功能強大,但是調優參數多。
2、Cluster
cluster是redis官方提供的集群化方案,它與codis不同,它是去中心化的,集群的每個節點負責一部分數據,相互連接形成一個對等的集群,它們之間通過一種特殊的二進制協議相互交互集群信息。
cluster的槽位划分更細,槽位的信息存儲於每個節點上,不需要另外的分布式存儲來存節點的信息。客戶端也存有關於槽位的信息,它可以直接定位到目標節點。
槽位和遷移
cluster允許用戶強制將某個key掛在特定槽位上。
當客戶端向一個節點發送指令,但是節點已經沒有這個key了,此時就會返回-moved,告知客戶端應該去這個節點查找,同時客戶端修改本地槽位映射表。
遷移時按槽遷移,一次性獲取槽位所有key,然后一個key一個key遷移,每個key的遷移過程都是以原節點作為目標節點的客戶端,key是先序列化發送,然后接收端再反序列化存入內存,然后返回ok,最后原節點刪除該key。
遷移的過程是同步的,原節點的線程一直阻塞,直到遷移成功。
在遷移時請求,客戶端會先訪問舊節點,如果不在,舊節點返回重定向指令,然后客戶端發送asking命令給目標節點,然后再向目標節點請求。因為目標節點在遷移完成之前不屬於該槽位,所以直接訪問會被拒絕,發出moved命令,所以先發送asking告知下一條命令必須處理才行。
這樣遷移時的訪問效率由一次ttl變為了三次。
如果在遷移時訪問舊節點得到一個moved,然后如果此時新節點也要進行遷移,那么訪問新節點還是會得到一個moved,這就是多次重試,可以控制這個次數,如果超過一定次數直接認為失敗拋出異常。
( 無論是哪種集群方案,大key總是會大大降低遷移速度影響性能。)
gossip協議和節點失聯
redis集群使用gossip協議來廣播自己的狀態以及接受其他實例的信息。一個節點發現另一個節點失聯會把這條信息廣播出去,其他節點也收到該信息,如果發現該節點失聯的信息發生了很多,就標記該節點下線,然后進行主從切換,這就是一個節點失聯不代表失效,必須經過一個集群協商的過程。
有時發生網絡抖動,會導致節點失聯,頻繁的主從切換,此時可以設置timeout時間,還可以設置關於該時間的放大系數。以確保網絡抖動時主從切換不那么明顯。
如果服務器節點變更,客戶端訪問掛掉的節點,會拋出一個錯誤,此時會隨機訪問某個節點以確定原來槽位對應的位置。修改集群信息后,客戶端訪問會被告知集群不可用,此時就會重新初始化節點信息。
