redis-cluster集羣擴容以及擴容client讀寫數據影響的探究node
一直以來,歷來只是對codis作過slot的動態遷移(同擴容)並且也只是線下環境,而沒有對線上的redis-cluster作過擴容和遷移。早就想有空測試一下卻一直沒有實際去作,然而就在今天收到了產品部的需求,要對線上某個業務線的redis-cluster作擴容。。。 這也正印證佛家那就話,你結下的因,遲早成你的果。(不懂,瞎說的)python
藉此契機,一探究竟。redis
測試環境:centos
主機類型:虛擬機 操做系統:centos6.5_x86_64ide
配置:1×1 4G 內存測試
1 構建集羣ui
(具體過程略)spa
在單臺主機上運行6個redis實例(端口:6380-6385)構造一個小集羣,以下:操作系統
[root@salt-master ~]# redis-cli -c -p 6380 cluster nodes ffb86e1168215b138c5b7a81ad92e44ca7095b54 192.168.11.3:6380 myself,master - 0 0 1 connected 0-5460 88e0cdfb2794816cb9a1ca39b7ad640656d5ef85 192.168.11.3:6382 master - 0 1487335437581 3 connected 10923-16383 a7a1020c36b8b0277c41ac7fc649ed9e81fa1448 192.168.11.3:6384 slave 8b20dd24f0aa2ba05754c4db016e0a29299df24e 0 1487335430478 5 connected 8de9d0da9dfd0db0553c68386cbccdcb58365123 192.168.11.3:6383 slave ffb86e1168215b138c5b7a81ad92e44ca7095b54 0 1487335436632 4 connected e8e6d0e32e0f2ee918795e3a232b9c768b671f39 192.168.11.3:6385 slave 88e0cdfb2794816cb9a1ca39b7ad640656d5ef85 0 1487335435563 6 connected 8b20dd24f0aa2ba05754c4db016e0a29299df24e 192.168.11.3:6381 master - 0 1487335433541 2 connected 5461-1092
從上面的輸出能夠看出,此集羣有3個主節點(master),每一個節點1個副本(slave),以及各個節點的IP、端口、ID、16384個slot槽位的分配。code
2 模擬數據
爲了稍後測試擴容時是否影響讀寫,咱們先在集羣裏寫點數據:
#!/usr/bin/env python # -*- coding: utf-8 -*- from rediscluster import StrictRedisCluster # Requires at least one node for cluster discovery. Multiple nodes is recommended. startup_nodes = [{"host": "192.168.11.3", "port": "6380"}, {"host": "192.168.11.3", "port": "6381"}, {"host": "192.168.11.3", "port": "6382"}, {"host": "192.168.11.3", "port": "6383"}, {"host": "192.168.11.3", "port": "6384"}, {"host": "192.168.11.3", "port": "6385"}] rc = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True) # pre_time = time.time() for i in xrange(100000): key = "key_%s" % i value = "value_%s" % i rc.set(key, value) # aft_time = time.time() # print aft_time - pre_time
(PS:個人這個小集羣set 10萬個key耗時21秒,有興趣的能夠和你本身的對比一下)
補充:
redis-cluster會額外啓用一個端口(默認是所監聽的port+10000)其餘與其它節點通訊的總線端口(一個有N個節點的集羣,則在每一個節點上,都有N-1個進來的鏈接和N-1個出去的鏈接與其餘節點進行通訊)。因此鏈接上集羣的任一節點,便可知曉全部節點。
3 新增資源
仍是在這臺虛擬機上,咱們在啓動2個redis實例,做爲新增的資源。
新增兩個實例端口分別爲6386 6387
[root@salt-master conf]# /usr/local/redis-server/bin/redis-server /usr/local/redis-server/conf/redis6386.conf [root@salt-master conf]# /usr/local/redis-server/bin/redis-server /usr/local/redis-server/conf/redis6387.conf
4 擴容集羣
將上面新增的2個實例擴容到集羣,此時只是集羣間相互知道有新的成員了,但新成員上未分配slot(slot集羣分配數據的最小單元),因此此時新增節點上不會有任何數據。
4.1 添加主節點
[root@salt-master conf]# /usr/local/redis-server/bin/redis-trib.rb add-node 192.168.11.3:6386 192.168.11.3:6380 >>> Adding node 192.168.11.3:6386 to cluster 192.168.11.3:6380 >>> Performing Cluster Check (using node 192.168.11.3:6380) M: ffb86e1168215b138c5b7a81ad92e44ca7095b54 192.168.11.3:6380 slots:0-5460 (5461 slots) master 1 additional replica(s) M: 88e0cdfb2794816cb9a1ca39b7ad640656d5ef85 192.168.11.3:6382 slots:10923-16383 (5461 slots) master 1 additional replica(s) S: a7a1020c36b8b0277c41ac7fc649ed9e81fa1448 192.168.11.3:6384 slots: (0 slots) slave replicates 8b20dd24f0aa2ba05754c4db016e0a29299df24e S: 8de9d0da9dfd0db0553c68386cbccdcb58365123 192.168.11.3:6383 slots: (0 slots) slave replicates ffb86e1168215b138c5b7a81ad92e44ca7095b54 S: e8e6d0e32e0f2ee918795e3a232b9c768b671f39 192.168.11.3:6385 slots: (0 slots) slave replicates 88e0cdfb2794816cb9a1ca39b7ad640656d5ef85 M: 8b20dd24f0aa2ba05754c4db016e0a29299df24e 192.168.11.3:6381 slots:5461-10922 (5462 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. >>> Send CLUSTER MEET to node 192.168.11.3:6386 to make it join the cluster. [OK] New node added correctly.
解釋:
redis-trib.rb add-node 192.168.11.3:6386 192.168.11.3:6380
命令 添加節點 新節點的IP:port 集羣任意節點的IP:port(用於集羣發現)
同理,爲剛添加的主節點增長副本(即添加從節點)
首先查看新增節點的ID:
[root@salt-master conf]# redis-cli -c -p 6380 CLUSTER nodes | grep 6386 301b60cdb455b9ae27b7b562524c0d039e640815 192.168.11.3:6386 master - 0 1487342302506 0 connected
4.2 添加從節點:
redis-trib.rb add-node --slave --master-id 301b60cdb455b9ae27b7b562524c0d039e640815 192.168.11.3:6387 192.168.11.3:6380
查看整個集羣情況:
[root@salt-master conf]# redis-cli -c -p 6380 CLUSTER nodes 301b60cdb455b9ae27b7b562524c0d039e640815 192.168.11.3:6386 master - 0 1487342439807 0 connected ffb86e1168215b138c5b7a81ad92e44ca7095b54 192.168.11.3:6380 myself,master - 0 0 1 connected 0-5460 b34e53b4b82fb11043f73819179524d49ce75ead 192.168.11.3:6387 slave 301b60cdb455b9ae27b7b562524c0d039e640815 0 1487342438797 0 connected 88e0cdfb2794816cb9a1ca39b7ad640656d5ef85 192.168.11.3:6382 master - 0 1487342441826 3 connected 10923-16383 a7a1020c36b8b0277c41ac7fc649ed9e81fa1448 192.168.11.3:6384 slave 8b20dd24f0aa2ba05754c4db016e0a29299df24e 0 1487342434759 5 connected 8de9d0da9dfd0db0553c68386cbccdcb58365123 192.168.11.3:6383 slave ffb86e1168215b138c5b7a81ad92e44ca7095b54 0 1487342440816 4 connected e8e6d0e32e0f2ee918795e3a232b9c768b671f39 192.168.11.3:6385 slave 88e0cdfb2794816cb9a1ca39b7ad640656d5ef85 0 1487342443843 6 connected 8b20dd24f0aa2ba05754c4db016e0a29299df24e 192.168.11.3:6381 master - 0 1487342444851 2 connected 5461-10922
能夠看到新增的2個節點已經加入集羣,可是沒有分配slot,全部目前不會接受任何redis client鏈接請求
5 遷移slot,測試讀寫
接下來咱們從新分配集羣的slot,使全部的節點數量均衡,於此同時模擬業務程序對集羣讀寫操做,觀察擴容遷移過程當中讀寫是否出錯並統計出錯的key數量。
5.1 模擬業務程序
邏輯:在遷移slot過程當中,對集羣操做,變動key對應的值,而後馬上獲取key的值,若獲得的值與咱們設置的值相同,則數據一致,未出錯;若不一樣(即set沒有寫入或get錯誤結果)則統計爲錯誤。
該程序暫不運行,待到開始遷移slot後,運行該程序。
#!/usr/bin/env python # -*- coding: utf-8 -*- from rediscluster import StrictRedisCluster # Requires at least one node for cluster discovery. Multiple nodes is recommended. startup_nodes = [{"host": "192.168.11.3", "port": "6380"}, {"host": "192.168.11.3", "port": "6381"}, {"host": "192.168.11.3", "port": "6382"}, {"host": "192.168.11.3", "port": "6383"}, {"host": "192.168.11.3", "port": "6384"}, {"host": "192.168.11.3", "port": "6385"}] rc = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True) count = 0 for i in xrange(100000): key = "key_%s" % i value = "_value_%s" % i rc.set(key, value) result = rc.get(key) if result == value: pass else: count +=1 print count
5.2 遷移slot
爲新增的節點分配slot,也就是把防止在其餘節點上的slot遷移到這個節點上,網友的一句話形容的很形象:就像玩撲克抽牌同樣:slot從A遷移到B,就好像從A抽一張牌,從其餘全部節點遷移N個slot,相似從新洗牌發牌同樣。
[root@salt-master bin]# redis-trib.rb reshard 192.168.11.3:6380 # 分配slot >>> Performing Cluster Check (using node 192.168.11.3:6380) M: ffb86e1168215b138c5b7a81ad92e44ca7095b54 192.168.11.3:6380 slots:2683-5460 (2778 slots) master 1 additional replica(s) S: 8617133eb1d2ef07f87dd6b108a4a0ec53ccdf99 192.168.11.3:6391 slots: (0 slots) slave replicates cdbcbd49b78684188fe321eec90e625ed394e0b7 (省略部分輸出......) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. How many slots do you want to move (from 1 to 16384)? 6384 # 輸入要遷移的slot的數量 What is the receiving node ID? cdbcbd49b78684188fe321eec90e625ed394e0b7 Please enter all the source node IDs. Type 'all' to use all the nodes as source nodes for the hash slots. Type 'done' once you entered all the source nodes IDs. Source node #1:all # 輸入slot來源節點,all表示全部其它節點 Moving slot 6260 from 301b60cdb455b9ae27b7b562524c0d039e640815 Moving slot 6261 from 301b60cdb455b9ae27b7b562524c0d039e640815 Moving slot 6262 from 301b60cdb455b9ae27b7b562524c0d039e640815 Moving slot 6263 from 301b60cdb455b9ae27b7b562524c0d039e640815 Do you want to proceed with the proposed reshard plan (yes/no)? yes # 最終確認 Moving slot 0 from 192.168.11.3:6388 to 192.168.11.3:6390: ..... .......
遷移的slot的數量能夠根據節點配置不一樣而不一樣,若各節點配置相同,則能夠平均分配slot(n=16384/主節點數量)
另外,在承載業務的集羣上面進行遷移時,數據量越大,遷移時間越長。
6 本次探究結論
redis-cluster擴容(slot遷移)不影響數據的讀寫。