分散式快取Redis之cluster叢集
寫在前面
jedis客戶端操作redis主要三種模式:單臺模式、分片模式(ShardedJedis)、叢集模式(BinaryJedisCluster),分片模式是一種輕量級叢集。
單臺模式、分片模式(ShardedJedis)前面已經講述過。這篇文章主要來看叢集模式。
現在專案上用redis的話,很少說不用叢集的情況,畢竟如果生產上只有一臺redis會有極大的風險,比如機器掛掉,或者記憶體爆掉,都會導致資料丟失。從Redis3.0,Jedis2.9版本開始有了cluster的概念。
一、Redis叢集介紹
Redis 叢集的特點
1)是一個提供在多個Redis間節點間共享資料的程式集;
2)並不支援處理多個keys的命令
3)通過分割槽來提供一定程度的可用性,在實際環境中當某個節點宕機或者不可達的情況下繼續處理命令。
4)Redis 叢集是 Redis 的一個分散式實現;
5)所有的redis節點彼此互聯(PING-PONG機制),內部使用二進位制協議優化傳輸速度和頻寬;
6)節點的fail是通過叢集中超過半數的節點檢測失效時才生效;
7)客戶端與redis節點直連,不需要中間proxy代理層。客戶端不需要連線叢集所有節點,連線叢集中任何一個可用節點即可。
8)Redis 叢集是3.0之後才引入的,在3.0之前,使用哨兵(sentinel)機制
Redis 叢集的優勢
- 自動分割資料到不同的節點上。
- 整個叢集的部分節點失敗或者不可達的情況下能夠繼續處理命令。
Redis 叢集的資料分片
Redis 叢集沒有使用一致性hash,而是引入了雜湊槽的概念。Redis 叢集有16384個雜湊槽(slot),當需要在 Redis 叢集中放置一個 key-value 時,每個key通過CRC16校驗後對16384取模來決定放置哪個槽,叢集的每個節點負責一部分hash槽。
比如當前叢集有3個節點,那麼:
- 節點 A 包含 0 到 5500號雜湊槽
- 節點 B 包含5501 到 11000 號雜湊槽
- 節點 C 包含11001 到 16383號雜湊槽
這種結構很容易新增或者刪除節點。比如如果我想新添加個節點D, 我需要從節點 A, B, C中分部分槽到D上。如果我想移除節點A,需要將A中得槽移到B和C節點上,然後將沒有任何槽的A節點從叢集中移除即可。
由於從一個節點將雜湊槽移動到另一個節點並不會停止服務,所以無論新增刪除或者改變某個節點的雜湊槽的數量都不會造成叢集不可用的狀態。
Redis只會為主節點分配雜湊槽。
叢集分割槽,最主要的目的是在移除、新增一個節點時對已經存在的快取資料的定位影響儘可能的降到最小。
和memcached一樣,Redis也採用一定的演算法進行鍵-槽(key->slot)之間的對映。memcached採用一致性雜湊(consistency hashing)演算法進行鍵-節點(key-node)之間的對映,而redis叢集使用叢集公式來計算鍵 key 屬於哪個槽:
HASH_SLOT(key)= CRC16(key) % 16384
Redis 叢集的主從複製模型
為了使在部分節點失敗或者大部分節點無法通訊的情況下叢集仍然可用,所以叢集使用了主從複製模型,每個節點都會有N-1個複製品。
在我們的例子中具有A,B,C三個節點的叢集,在沒有複製模型的情況下,如果節點B失敗了,那麼整個叢集就會以為缺少5501-11000這個範圍的槽而不可用。
然而如果在叢集建立的時候(或者過一段時間),我們為每個節點新增一個從節點A1,B1,C1,那麼整個叢集便有三個master節點和三個slave節點組成,這樣在節點B失敗後,叢集便會選舉B1為新的主節點繼續服務,整個叢集便不會因為槽找不到而不可用了。不過當B和B1 都失敗後,叢集是不可用的。
什麼時候整個叢集不可用(cluster_state:fail)?
- 如果叢集任意master掛掉,且當前master沒有slave,叢集進入fail狀態。也可以理解成叢集的slot對映[0-16383]不完成時進入fail狀態;
- 如果叢集超過半數以上master掛掉,無論是否有slave叢集進入fail狀態。
ps:當叢集不可用時,所有對叢集的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)錯誤。
二、搭建並使用Redis叢集
只在這總結一下經常遇到的問題:主要是隨著年代的更新,版本的更新,很多源/庫,現在都沒了。
1、redis-trib.rb命令提示not command,即不能執行叢集安裝命令:
redis-trib.rb是redis官方推出的管理redis叢集的工具,整合在redis的原始碼src目錄下。因為redis-trib.rb是用ruby語言編寫,系統沒有安裝ruby環境。
**解決辦法:**Ubuntu下安裝ruby命令:
sudo apt-get install ruby
2、再進一步,提示出錯:cannot load such file –redis
這是因為需要安裝驅動,在安裝驅動之前,需要替換資源庫,否則資源請求地址會報錯,不知道從什麼時候開始,使用淘寶的gemsruby資源庫(https://ruby.taobao.org/),會提示Error fetching https://ruby.taobao.org/
發現原來是taobao Gems 源已停止維護,現由 ruby-china 提供映象服務,即我們要換源:http://gems.ruby-china.org/
補充此處的幾條命令:
1、刪除預設的官方源:
gem sources -r https://rubygems.org/
2、(以前的) 新增淘寶源:
gem sources -a https://ruby.taobao.org/
3、(現在應該新增的)注意:這裡是http而不是https
gem sources -a http://gems.ruby-china.org/
4、檢視當前源:
gem sources -l
3、redis-trib.rb具有以下功能:
● create :建立叢集
● check :檢查叢集
● info :檢視叢集資訊
● fix :修復叢集
● reshard :線上遷移slot
● rebalance :平衡叢集節點slot數量
● add-node :將新節點加入叢集
● del-node :從叢集中刪除節點
● set-timeout :設定叢集節點間心跳連線的超時時間
● call :在叢集全部節點上執行命令
● import :將外部redis資料匯入叢集
● redis-trib.rb主要有兩個類: ClusterNode 和 RedisTrib 。 ClusterNode儲存了節點本身以及處於叢集中的所有節點的狀態, RedisTrib 則是redis-trib.rb各個功能的實現。
比如:
向叢集中新增節點,7037是新增節點,7036是叢集中已有的節點
./redis-trib.rb add-node 192.168.2.128:7037 192.168.2.128:7036
重新分配槽
./redis-trib.rb reshard 192.168.2.128:7031
指定當前節點的主節點
cluster replicate cf48228259def4e51e7e74448e05b7a6c8f5713f
刪除節點
./redis-trib.rb del-node 192.168.2.128:7037 'a56461a171334560f16652408c2a45e629d268f6'
4、在安裝redis-cluster過程中可以節省時間的操作集合:
1)如何快速啟動六個(或更多)伺服器?
方法一:依次進入每個節點目錄(時間都浪費在切換目錄上了),執行 ./redis-server redis.conf.
方法二:寫個shell指令碼,vim startall.sh就會開啟vim編輯器,建立一個空的文字:
即將方法一在命令列操作的指令集合到文本里。以一個節點為例:
cd redis01
./redis-server redis.conf
cd ..
cd redis02
blurblur....
執行./startall.sh 提示permission denied說明許可權不足,執行命令chmod 777 startall.sh修改許可權即可。
方法三:用指令碼迴圈啟動,這樣更方便省時
for((i=1;i<=6;i++)); do /usr/local/redis/bin/redis-server /usr/local/redis-cluster/703$i/redis.conf; done
三、redis cluster命令
叢集(cluster)
cluster info 列印叢集的資訊
cluster nodes 列出叢集當前已知的所有節點(node),以及這些節點的相關資訊節點
cluster meet 將ip和port所指定的節點新增到叢集當中,讓它成為叢集的一份子
cluster forget 從叢集中移除node_id指定的節點
cluster replicate 將當前節點設定為node_id指定的節點的從節點
cluster saveconfig 將節點的配置檔案儲存到硬盤裡面
cluster slaves 列出該slave節點的master節點
cluster set-config-epoch 強制設定configEpoch槽(slot)
cluster addslots [slot …] 將一個或多個槽(slot)指派(assign)給當前節點
cluster delslots [slot …] 移除一個或多個槽對當前節點的指派
cluster flushslots 移除指派給當前節點的所有槽,讓當前節點變成一個沒有指派任何槽的節點
cluster setslot node 將槽slot指派給node_id指定的節點,如果槽已經指派給另一個節點,那麼先讓另一個節點刪除該槽,然後再進行指派
cluster setslot migrating 將本節點的槽slot遷移到node_id指定的節點中
cluster setslot importing 從node_id 指定的節點中匯入槽slot到本節點
cluster setslot stable 取消對槽slot的匯入(import)或者遷移(migrate) 鍵
cluster keyslot 計算鍵key應該被放置在哪個槽上
cluster countkeysinslot 返回槽slot目前包含的鍵值對數量
cluster getkeysinslot 返回count個slot槽中的鍵
其它
cluster myid 返回節點的ID
cluster slots 返回節點負責的slot
cluster reset 重置叢集,慎用
四、Redis叢集方案
最早的Redis Sharding分片方案,然後Sentinel哨兵方案,前面介紹的是官方推出的Redis-cluster方案。
基於代理的分片方案:
如果您覺得這篇文章對您有所啟發、有所幫助,可以給我打賞一元錢,去買個茶葉蛋吃,謝謝~~~~
微信:
支付寶:
—–樂於分享,共同進步
—–Any comments greatly appreciated
—–誠心歡迎各位交流討論!QQ:1138517609