寫在前面
本學習教程所有示例代碼見GitHub:https://github.com/selfconzrr/Redis_Learning
官方文檔:
集羣教程:http://www.redis.cn/topics/cluster-tutorial.html
集羣規範:http://www.redis.cn/topics/cluster-spec.html
jedis客戶端操作redis主要三種模式:單臺模式、分片模式(ShardedJedis)、集羣模式(BinaryJedisCluster),分片模式是一種輕量級集羣。
單臺模式、分片模式(ShardedJedis)前面已經講述過。這篇文章主要來看集羣模式。
現在項目上用redis的話,很少說不用集羣的情況,畢竟如果生產上只有一臺redis會有極大的風險,比如機器掛掉,或者內存爆掉,都會導致數據丟失。從Redis3.0,Jedis2.9版本開始有了cluster的概念。
一、Redis集羣介紹
Redis 集羣的特點
1)是一個提供在多個Redis間節點間共享數據的程序集;
2)並不支持處理多個keys的命令,因爲這需要在不同的節點間移動數據,從而達不到像Redis那樣的性能,在高負載的情況下可能會導致不可預料的錯誤。
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
- 1
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集羣
這兩篇介紹的非常詳細。
https://www.cnblogs.com/hjwublog/p/5681700.html
http://blog.csdn.net/boonya/article/details/49362819
只在這總結一下經常遇到的問題:主要是隨着年代的更新,版本的更新,很多源/庫,現在都沒了。
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
- 1
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方案。
基於代理的分片方案:
- Twemproxy(已經不維護了):GitHub鏈接:https://github.com/twitter/twemproxy
- codis:現在比較推薦,可以參考博文學習:http://www.jianshu.com/p/14835303b07e