Redis集群模式通信成本影響因素
一、通信開銷影響因素
節點數量
每秒從本地實例列表選擇5個節點,在這5個節點中選擇最久沒有通信的實例,向該實例發送PING消息。
即:定時發送PING消息的節點數量=5。
避免一些實例節點一直選不到,會有一個定時任務掃描兜底措施。
集群內部每秒10次的固定頻率掃描本地緩存節點列表,也就是每100ms一次。
如果節點:PONG更新時間node.pong_received>(cluster-node-timeout/2)立即向該節點發送PING消息,假設該數量為N。
即:兜底發送的節點數量=10 * N。
通過調大cluster_node_timeout可以減少通信的節點數量,例如:從15秒調整到30秒。
但是,cluster_node_timeout過大會影響故障發現的時間和新節點發現的時間。
消息大小
一次通信包含消息頭和消息體。
消息頭:PING消息頭相對固定,主要占用的發送節點負責的槽位(myslots[CLUSTER_SLOTS/8])占用2KB。
消息體:會攜帶一定數量的其他節點信息,默認包含集群總節點數的1/10,最少包含集群的3個節點,最多包含集群總節點數-2。
消息體clusterMsgDataGossip各個字段字節大小,共計104個字節。
屬性 | 大小 |
char nodename[CLUSTER_NAMELEN] | 40字節 |
uint32_t ping_sent | 4字節 |
uint32_t pong_received | 4字節 |
char ip[NET_IP_STR_LEN] | 46字節 |
uint16_t port | 2字節 |
uint16_t cport | 2字節 |
uint16_t flags | 2字節 |
uint16_t pport | 保留字段 |
uint16_t notused1 | 4字節 |
合計 | 104字節 |
200個節點的redis集群,一次通信成本:2KB的消息頭+2KB的消息體(20*104)= 4KB,一來一回8KB。
攜帶消息體的大小與集群規模相關,規模越大消息體越大,通信成本越高。
達到一定程度后整體集群性能會下降,Redis Cluster官方建議最大規模1000個實例,實際中通常不會超過500個實例。
二、擴縮容與槽位遷移
節點擴縮容本質上是槽在節點之間的遷移。
節點擴容后,需要將原有節點上的槽遷移到新節點。
如下圖所示,當集群中加入節點4時,將節點1的Slo01,節點2的Slot04,節點3的Slot07遷移給節點4以實現數據均衡。
節點縮容前,需要將待下線節點上的槽先遷移走。
如下圖所示,當集群中節點4下線,需要先將其擁有的槽位Slot01、Slot04、Slot07遷移走。
槽位遷移命令有:ADDSLOTS、DELSLOTS、FLUSHSLOTS、SETSLOT。
三、請求路由與重定向
數據存儲在槽里,槽分布在實例上,處理客戶端請求也是找對應槽的過程。
請求重定向
請求路由過程如下:
- @1 客戶端發送請求命令到集群任意節點
- @2 計算key對應的槽,計算公式:slot=CRC16(key)&16383
- @3 槽在本節點,執行命令,每個實例維護自身負責的槽也維護其他實例負責的槽位
- @4 槽不在本節點,回復MOVE到其他節信息點
- @5 向目標節點發起請求
為了減少MOVE重定向的開銷,例如Jedis在客戶端實現時緩存了槽與節點的關系,減少通信的開銷。
然而也增加了客戶端的復雜性,客戶端會為集群中每個節點獨立的連接池,集群規模大時占用更多的本地緩存。
ASK重定向
如果訪問的槽正在做遷移,一部分數據在源節點,而另一部分已經遷移到目標節點,這個流程是如何的?
ASK重定向流程:
- @1 發送請求命令
- @2 計算key對應的槽
- @3 槽在本節點,數據也在,執行命令
- @4 訪問的數據正在遷移,回復ASK信息含請求數據的目標節點
- @5 向目標節點發起ASKING請求、執行命令獲取數據
ASK的重定向是臨時性的,客戶端(Jedis)收到回復不更新客戶端槽與節點映射,而MOVE的重定向會更新本地槽映射關系。