【Redis】Redis叢集主從調整演算法
一、問題出發
1)Redis 叢集為什麼要調整主從?
在大叢集中,一個叢集上百個redis 例項,一個 IP 可能有上十個例項,如果這十幾個例項都是主例項,那麼這麼大的流量會導致叢集的抖動
當承載10
多個主例項的節點當機,叢集的通訊,資料的複製,可想而知,有多恐怖
2)Redis 大叢集調整主從的窘境
100 多例項,人工調整,得耗費多少時間?
例項關係錯綜複雜,有些IP
之前例項有直接主從關係,直接
cluster failover
就能調整,但是如果節點之間沒直接主從關係呢?甚至沒有間接主從關係?
二、深入環境的提煉與抽象
1)有直接主從關係;比如A 節點與 C 節點
圖(一)
2) 有間接主從關係;例如:A->B->C
圖(2)
3) 節點之間無關係
比如:A 節點與 C 節點; D 節點與 C 節點;這裡我們繼續說明一個概念,一個叢集中,如果IP團體之間沒有關係,我們叫孤島,如果整個叢集都有關係,那麼叢集也是一個孤島;圖中AD是一個孤島,BC是一個孤島,即這個叢集有兩個孤島
圖(3)
三、提煉需求
(1)將孤島中從例項最多的節點跟從例項最少的節點進行交換(可能要進過多次切換,比如圖(2)要切換兩次),直到平衡( 為什麼說是要孤島,而不是叢集呢,因為一個孤島與另一個孤島之間沒有直接和間接主從關係,無法 cluster failover 達到平衡 )
(2)分割孤島( 每個孤島可以按照第一步來達到平衡 )
四、核心難點解決
1)將每個IP 的按需要移動從例項的個數排列,然後首尾切換,得到平衡
例如:這裡slave_most:3 表示有三個例項要變為主庫; slave_most:0 表示沒有例項變為主庫, slave_most:-2 表示有 2 個例項要從庫,這裡需要兩個資料結構,單個 IP 的 redis 抽象( RedisNode ),以及整個叢集 IP 的 Redis 的抽象( RedisNodes )
圖(4)
2) 求切換路徑
在《深入環境的提煉與抽象》這裡,我們講了一個孤島中,存在直接或者間接的主從關係,那麼理想的切換是有直接關係的,然後再找有間接關係,這樣我們可以 抽象成金字塔 , 自頂向下,從左向右掃描, 且掃描數層數不能超過節點總數 -1 ; 例如圖 2 ,我們從 A 節點開始掃描,目標是 C 節點 (A 是金字塔的頂層 ) ,發現 A 節點上的從例項對應的主例項有節點 D( 即 D 是金字塔的第二層) , D 上的從例項對用的主例項有 C,A(C , A 即金字塔的第底層 ); 那麼圖 2 也可表示成 :
圖(5)
這裡還可以最佳化,就是底層的A 是可以去掉,因為形成了迴環,用剪枝的方法給他去掉
3) 求孤島
孤島,一堆例項有直接和間接主從關係的節點的集合; 找出每個節點的直接關係圖,然後有交集的就合併,沒交集或者合併後與其他的集合沒交集,就是孤島 , 以圖 (2) 為例:
圖(6)
孤島這裡描述不太清楚,直接上程式碼吧
def getAreaNodes(self) : #單個ip的關係集合 tmp_sets=[] #有主從關係的IP的集合,包括級聯關係 area_sets=[] for r_node in self.m_nodes.redis_nodes : ip_list=set() ip_list.add(r_node.node_name) for entry in r_node.entrys : if entry.is_master() : continue ip_list.add(entry.master_ip) tmp_sets.append(ip_list) #我只需要遍歷單個ip關係集合-1次,就能找出區域數 num_t = len(tmp_sets)-1 #遍歷最佳化,如果一個孤島的節點數就是叢集數,那可以立即返回 finish_flag=False for out_index in range(0,num_t) : #找到有關聯關係的集合,則此值為True find_flag=False #一旦tmp_sets[0] 與後面的tmp_sets[1],tmp_sets[2],...任何一個下標為in_index有交集,則合併集合,開始下一輪迴圈 for in_index in range(1,len(tmp_sets)) : #有交集,則合併 if len([elem for elem in tmp_sets[0] if elem in tmp_sets[in_index]]) > 0 : tmp_sets[0]=tmp_sets[0] | tmp_sets[in_index] if len(tmp_sets[0]) == len(self.m_nodes.redis_nodes) : area_sets.append(tmp_sets[0]) finish_flag=True break del tmp_sets[in_index] find_flag=True break if finish_flag==True : break #與其他集合無交集,那肯定是孤島,這這就是我們所求的孤島 if find_flag==False or out_index==num_t-1 : area_sets.append(tmp_sets[0]) del tmp_sets[0] for area_index in range(0,len(area_sets)): self.node_areas.area_append(RedisNodes()) for r_node in self.m_nodes.redis_nodes : for area_index in range(0,len(area_sets)): if r_node.node_name in area_sets[area_index] : self.node_areas.areas[area_index].node_append(r_node) return self.node_areas
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30221425/viewspace-2678371/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Redis主從同步叢集搭建Redis主從同步
- 基於Dokcer搭建Redis叢集(主從叢集)Redis
- Redis叢集搭建 三主三從Redis
- Redis高可用-主從,哨兵,叢集Redis
- redis原理及叢集主從配置Redis
- Redis叢集搭建(三主三從)Redis
- Redis叢集的主從切換研究Redis
- Redis搭建主從複製、哨兵叢集Redis
- (八)Redis 主從複製、切片叢集Redis
- Redis學習筆記七:主從叢集Redis筆記
- Redis的主從複製,哨兵和Cluster叢集Redis
- Redis三種高可用模式:主從、哨兵、叢集Redis模式
- linux系統——Redis叢集搭建(主從+哨兵模式)LinuxRedis模式
- 三千字介紹Redis主從+哨兵+叢集Redis
- Redis資料型別, Redis主從哨兵和叢集(將資料匯入叢集) ubuntu使用Redis資料型別Ubuntu
- Redis系列:搭建Redis叢集(叢集模式)Redis模式
- 基於docker環境下搭建redis主從叢集DockerRedis
- redis主從叢集搭建及容災部署(哨兵sentinel)Redis
- redis安裝,主從複製,哨兵機制,叢集Redis
- redis叢集Redis
- redis 叢集Redis
- 【Redis學習專題】- Redis主從+哨兵叢集部署Redis
- 記一次阿里雲 Redis 主從版升級到 Redis 叢集版的坑阿里Redis
- 【Redis】用python操作redis叢集RedisPython
- 認識Redis叢集——Redis ClusterRedis
- redis叢集之主從複製叢集的原理和部署Redis
- Redis cluster 叢集Redis
- redis系列:叢集Redis
- Redis Cluster(叢集)Redis
- redis叢集原理Redis
- 搭建 Redis 叢集Redis
- redis叢集搭建Redis
- Redis哨兵叢集:哨兵掛了,主從庫還能切換嗎?Redis
- Docker部署系列之Docker Compose安裝Redis三主三從叢集DockerRedis
- Redis基礎知識(學習筆記18--主從叢集)Redis筆記
- 搭建Redis“主-從-從”模式叢集並使用 RedisTemplate 實現讀寫分離Redis模式
- 【Redis叢集實戰】Redis Cluster 部署Redis
- Redis(5.0) 叢集搭建Redis