Redis Cluster原理初步
目錄
目錄 1
1.?前言 1
2.?槽(slots) 1
3.?路由配置(node.conf) 1
4.?總slots數(cluster.h:16384) 2
5.?key的路由 2
6.?將key轉成整數值(crc16.c:crc16) 2
7.?計算key所在slot(cluster.c:keyHashSlot) 2
8.?Redis?Cluster?Client實現 3
?
1.?前言
截至2016/5/16最新版本的redis-3.2.0仍然非強一致性,基于性能考慮master和它的slaves間數據是異步復制的。另外,一個確定的key總是只會落到確定的master,除非使用redis-trib.rb等工具修改slots和master間的綁定關系,目前的redis?cluste不支持自動從一個master遷移一個slot到另一個master(slaves對slots來說,可以認為和對應的master相同)。
2.?槽(slots)
Redis?cluster將所有存儲在其上的key通過一個hash算法劃分成若干slots,當前為16384個slots,值在cluster.h文件中由宏CLUSTER_SLOSTS指定。
3.?路由配置(node.conf)
存儲的內容和redis命令“cluster?nodes”的輸出相同,即存儲了master和slave信息,以及各master存儲的slots,亦即slots的路由信息存儲在node.conf。
同一Redis?cluster中的所有節點的node.conf文件內容最終是一致的。
4.?總slots數(cluster.h:16384)
| #define?CLUSTER_SLOTS?16384?//?等于(0x3FFF?+?1) |
?
宏CLUSTER_SLOTS定義了redis?cluster的slots數,理論上這個值應當可以修改重編譯。其值越大,相對更容易均衡,可支撐更多節點數的集群(實際受限于無中心節點,當然架構的redis?cluster節點數不宜過大,否則可能引起網絡風暴)。
5.?key的路由
->?將key轉成整數值
->?計算key所在的slot
->?找到slot所在的master或slaves(redis?cluster可配置允許slaves提供讀)
->?轉成直接對master或slaves的請求。
?
由于任何一個redis?cluster節點都存儲了相同內容的node.conf,所以client可以請求任一節點獲得slots的路由數據。
而且由于node.conf中包含了master和slaves信息,因此讀寫操作可以完美的路由到相應的節點。
6.?將key轉成整數值(crc16.c:crc16)
Redis使用crc算法將一個字符串轉成整數,宏CLUSTER_SLOTS的值是不能超過CRC返回的最大值。
| uint16_t?crc16(const?char?*buf,?int?len)?{ ????int?counter; ????uint16_t?crc?=?0; ????for?(counter?=?0;?counter?<?len;?counter++) ????????????crc?=?(crc<<8)?^?crc16tab[((crc>>8)?^?*buf++)&0x00FF]; ????return?crc; } |
7.?計算key所在slot(cluster.c:keyHashSlot)
對于一個redis?KEY它歸屬于哪一個slot,這個可以通過函數keyHashSlot()調用計算出來:
| unsigned?int?keyHashSlot(char?*key,?int?keylen)?{ ????int?s,?e;?/*?start-end?indexes?of?{?and?}?*/ ? ????for?(s?=?0;?s?<?keylen;?s++) ????????if?(key[s]?==?'{')?break; ? ????/*?No?'{'???Hash?the?whole?key.?This?is?the?base?case.?*/ ????if?(s?==?keylen)?return?crc16(key,keylen)?&?0x3FFF; ? ????/*?'{'?found??Check?if?we?have?the?corresponding?'}'.?*/ ????for?(e?=?s+1;?e?<?keylen;?e++) ????????if?(key[e]?==?'}')?break; ? ????/*?No?'}'?or?nothing?betweeen?{}???Hash?the?whole?key.?*/ ????if?(e?==?keylen?||?e?==?s+1)?return?crc16(key,keylen)?&?0x3FFF; ? ????/*?If?we?are?here?there?is?both?a?{?and?a?}?on?its?right.?Hash ?????*?what?is?in?the?middle?between?{?and?}.?*/ ????return?crc16(key+s+1,e-s-1)?&?0x3FFF;?//?3FFF即為16383 } |
8.?Redis?Cluster?Client實現
通過上面的信息,不然發現,Redis?Cluster?Client只是在原來單機版client基礎上多了一層薄的路由邏輯。因此可以基于現有的hiredis等實現支持redis?cluster的client庫。大致過程如下:
| class?CRedisClusterClient { public: ????//?nodes?Redis集群中的單個或多個節點,格式為:ip1:port1,ip2:port2,如:127.0.0.1:6379,127.0.0.1:6380,192.168.31.11:6379 ????CRedisClusterClient(const?std::string&?nodes); ????void?set(const?std::string&?key,?const?std::string&?value)?const; ????void?get(const?std::string&?key,?std::string*?value); ? private: ????redisContext*?_redis_context;?//?hiredis }; |
?
set()函數實現:
1)?CRedisClusterClient從nodes取任一nodeA,如:127.0.0.1:6380
2)?建立與nodeA的連接
3)?從nodeA取得slots路由數據(實現時可緩存這部分數據,以提升性能)
4)?構造slots路由數據表(由于slots總數有限,可以以slot為下標數組方式組織路由表)
5)?計算key所在的slot
6)?找到slot所在的nodeB(對于寫操作,要求nodeB為master,有可能碰巧就是nodeA)
7)?使用hiredis訪問nodeB(從這步開始和原使用hiredis相同)
8)?取得hiredis返回的結果
?
如果使用hiredis發生網絡異常,對于寫操作從第3步開始重執行,對于讀操作從第6步重選一個node重執行。
?
轉載于:https://www.cnblogs.com/aquester/p/9891529.html
總結
以上是生活随笔為你收集整理的Redis Cluster原理初步的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【COCOS2DX隐藏IOS7状态栏】通
- 下一篇: linux cmake编译源码,linu