redis-cluster 分佈式集羣

redis分佈式集羣概述

Redis 集羣是一個提供在多個Redis間節點間共享數據的程序集。
Redis集羣並不支持處理多個keys的命令,因爲這需要在不同的節點間移動數據,從而達不到像Redis那樣的性能,在高負載的情況下可能會導致不可預料的錯誤.
Redis 集羣通過分區來提供一定程度的可用性,在實際環境中當某個節點宕機或者不可達的情況下繼續處理命令.
Redis 集羣的優勢:

  • 自動分割數據到不同的節點上。
  • 整個集羣的部分節點失敗或者不可達的情況下能夠繼續處理命令。

如何搭建環境

  1. 集羣服務器配置
    集羣中有三臺服務器,分別是192.168.56.101、192.168.56.103、192.168.56.105,預期搭建環境:三主三從,使用這三臺服務器上的7000/7001端口提供redis服務
  2. 安裝軟件

    安裝ruby以及rubygems

sudo apt-get install ruby_full rubygems

安裝rubygems的redis包

sudo gem install redis

安裝redis 4.0.11

 cd  /usr/local/src
 sudo wget http://download.redis.io/releases/redis-4.0.11.tar.gz
 sudo tar zxf redis-4.0.11.tar.gz
 cd redis-4.0.11
 sudo make
 sudo make test
 sudo make install 
  1. 配置集羣

配置文件 (創建工作目錄,生成配置文件)

sudo mkdir -p /usr/local/redis-cluster
cd /usr/local/redis-cluster
sudo mkdir 7000 7001
sudo cp /usr/local/src/redis-4.0.11/redis.conf /usr/local/redis-cluster/7000
sudo cp /usr/local/src/redis-4.0.11/redis.conf /usr/local/redis-cluster/7001

修改配置文件 步驟如下:

  • (1)綁定端口,port 7000

  • (2)註釋掉IP綁定,##bind 127.0.0.1

  • (3)指定數據存放路徑,dir /usr/local/redis-cluster/7000

  • (4)啓動集羣模式,cluster-enabled yes

  • (5)指定集羣節點配置文件,cluster-config-file nodes-7000.conf

  • (6)後臺啓動,daemonize yes

  • (7)指定集羣節點超時時間,cluster-node-timeout 5000

  • (8)修改pidfile配置,pidfile /var/run/redis_7000.pid

  • (9)將 protected-mode yes 修改爲 protected-mode no

啓動redis服務 (分別在各個服務器上執行以下命令)

sudo /usr/local/bin/redis-server /usr/local/redis-cluster/7000/redis.conf
sudo /usr/local/bin/redis-server /usr/local/redis-cluster/7001/redis.conf

啓動集羣 (在一個服務器節點上執行即可)

sudo /usr/local/src/redis-4.0.11/src/redis-trib.rb create --replicas 1 192.168.56.105:7000 192.168.56.105:7001 192.168.56.101:7000 192.168.56.101:7001 192.168.56.103:7000 192.168.56.103:7001
  1. 驗證是否正常工作
    集羣啓動成功

查詢集羣中的主節點 (可以看到現在集羣中共三主三從)

redis-cli -h 192.168.56.105 -p 7000 cluster nodes |grep master
192.168.56.105:7000> cluster nodes
050a20ab3750ae41053047ef1fb57c65b1738ff2 192.168.56.101:7001@17001 slave ac2cf6f9a81dc30d0feef1c2475429a674ea5a03 0 1543817706527 4 connected
ce77ac2f93303cfa8b8df45f7ddbb2ed5703addc 192.168.56.103:7001@17001 slave c69fa64175e952b7f8a18cc3974ad94e10bfd50e 0 1543817705620 6 connected
b13cf9657a49a4df32ac2504c5adfce64b13606a 192.168.56.103:7000@17000 master - 0 1543817706000 5 connected 10923-16383
7710f528109bab3b518065e822753bb6d83749fa 192.168.56.105:7001@17001 slave b13cf9657a49a4df32ac2504c5adfce64b13606a 0 1543817705000 5 connected
c69fa64175e952b7f8a18cc3974ad94e10bfd50e 192.168.56.101:7000@17000 master - 0 1543817706626 3 connected 5461-10922
ac2cf6f9a81dc30d0feef1c2475429a674ea5a03 192.168.56.105:7000@17000 myself,master - 0 1543817706000 1 connected 0-5460

驗證redis集羣讀寫數據

192.168.56.105:7000> set person1 liubei
-> Redirected to slot [8665] located at 192.168.56.101:7000
OK
192.168.56.101:7000> set person2 guanyu
-> Redirected to slot [4538] located at 192.168.56.105:7000
OK
192.168.56.105:7000> set person3 zhangfei
OK
192.168.56.105:7000> set person4 zhugeliang
-> Redirected to slot [12668] located at 192.168.56.103:7000
OK

單節點讀取節點數據 (如果數據不再本節點上會報錯)
在這裏插入圖片描述
集羣中讀取節點數據 (數據會自動重定向到相應節點)
redis-cli -c Enable cluster mode (follow -ASK and -MOVED redirections).
在這裏插入圖片描述
注意:讀取從節點,用redis-cli連接,先發送“readonly”命令纔可以。

測試geo相關命令

geoadd eating 116.487187 40.002045 "soho-t3" 
geoadd eating 116.488092 40.001923 "xiaoxiangge" 116.488249 40.002431 "youjingge" 116.488473 40.001778 "yaogeyongcan" 116.487063 40.002462 "xuebing" 116.487665 40.002672 "maishisala" 116.487162 40.002662 "gongcha" 116.486349 40.001664 "lanzhouniuroulamian"

查找離soho-T3最近的一家餐廳

georadius eating 116.48718684911727905 40.00204543082474373 200 m WITHDIST ASC

在redis集羣中,發佈訂閱不受影響
在任一節點上發佈消息,其他訂閱的節點都會收到消息。

如何增刪節點

如何添加一個新節點,包括一主一從並分配slot給新節點
這裏比如添加兩個新節點 (主:192.168.56.103:7002 從:192.168.56.101:7002)

######  在101和103上分別添加一個新實例 端口:7002:
sudo mkdir /usr/local/redis-cluster/7002 && sudo cp /usr/local/redis-cluster/7000/redis.conf /usr/local/redis-cluster/7002/redis.conf && sudo sed -i "s/7000/7002/g" /usr/local/redis-cluster/7002/redis.conf

###### 分別在101和103上啓動redis實例
sudo /usr/local/bin/redis-server /usr/local/redis-cluster/7002/redis.conf

###### 將這兩個啓動的實例加入到集羣中
sudo /usr/local/src/redis-4.0.11/src/redis-trib.rb add-node 192.168.56.101:7002 192.168.56.105:7000
sudo /usr/local/src/redis-4.0.11/src/redis-trib.rb add-node 192.168.56.103:7002 192.168.56.105:7000

###### 給192.168.56.103:7002重新分配槽 4096個槽給節點 192.168.56.103:7002 ID:4ba66479f7036cb8827cd69c8b8d71e8025617e7
sudo /usr/local/src/redis-4.0.11/src/redis-trib.rb reshard 192.168.56.105:7000
######重新分片的過程中會提示接收槽的節點及從哪些節點獲取槽
...
What is the receiving node ID? b988f19d9f7832f68b797f29cd66165950135a18
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
...

###### 登錄到192.168.56.101:7002 ,並將該節點設置爲103:7002的從節點
redis-cli -h 192.168.56.101 -p 7002
cluster replicate 4ba66479f7036cb8827cd69c8b8d71e8025617e7

######也可以先添加主節點,再爲該節點添加一個從節點
sudo /usr/local/src/redis-4.0.11/src/redis-trib.rb add-node --slave --master-id '1493e944e61a228a2cfe5fa58866c0f9fe13befb' 192.168.56.103:7002 192.168.56.105:7000

最終結果如下:(可以看到101:7002已經變成了103:7002的從節點)在這裏插入圖片描述

如何刪除一個節點 (刪除前需要先將其中的槽分片到其他節點)
這裏演示先刪除從節點101:7002,再刪除節點103:7002

###### 集羣中刪除一個節點 使用 del-node 命令即可: 
./redis-trib del-node 127.0.0.1:7000 `<node-id>`
第一個參數是任意一個節點的地址,第二個節點是你想要移除的節點地址。

###### 先刪除從節點 101:7002
sudo /usr/local/src/redis-4.0.11/src/redis-trib.rb  del-node 192.168.56.105:7000 '1f716ae0975de33b124e2a8115b679720ac1522a'

###### 刪除前按照設置自動遷移數據
sudo /usr/local/src/redis-4.0.11/src/redis-trib.rb reshard --from b988f19d9f7832f68b797f29cd66165950135a18 --to ac2cf6f9a81dc30d0feef1c2475429a674ea5a03 --slots 1024 --yes 192.168.56.105:7000
sudo /usr/local/src/redis-4.0.11/src/redis-trib.rb reshard --from b988f19d9f7832f68b797f29cd66165950135a18 --to c69fa64175e952b7f8a18cc3974ad94e10bfd50e --slots 1024 --yes 192.168.56.105:7000
sudo /usr/local/src/redis-4.0.11/src/redis-trib.rb reshard --from b988f19d9f7832f68b797f29cd66165950135a18 --to b13cf9657a49a4df32ac2504c5adfce64b13606a --slots 2048 --yes 192.168.56.105:7000
###分片後刪除主節點
sudo /usr/local/src/redis-4.0.11/src/redis-trib.rb  del-node 192.168.56.105:7000 'b988f19d9f7832f68b797f29cd66165950135a18'

重新分片的過程中有可能會出錯,如果出錯了,就重新修復。
###### 修復命令: sudo /usr/local/src/redis-4.0.11/src/redis-trib.rb fix 192.168.56.105:7001
###### 客戶端登錄相應節點,可以使用命令取消slots遷移(5461爲slot的ID):cluster setslot 5461 stable
###### 取消刪除後要針對該節點上的數據重新分片

刪除成功後,現在的集羣又變成了三主三從的狀態
在這裏插入圖片描述

如果主節點服務停止,集羣如何處理

這裏重新添加101:7002主節點以及103:7002從節點,然後人爲地殺掉101:7002進程看系統會不會啓動故障轉移

### 刪除前集羣節點狀態
192.168.56.105:7001> cluster nodes
b13cf9657a49a4df32ac2504c5adfce64b13606a 192.168.56.103:7000@17000 master - 0 1543820785196 10 connected 1024-1364 5461-6826 10923-11263 12288-16383
c69fa64175e952b7f8a18cc3974ad94e10bfd50e 192.168.56.101:7000@17000 master - 0 1543820786508 3 connected 6827-10922
ce77ac2f93303cfa8b8df45f7ddbb2ed5703addc 192.168.56.103:7001@17001 slave c69fa64175e952b7f8a18cc3974ad94e10bfd50e 0 1543820785000 6 connected
3573dbaba4528d305afcf78fdf67ab1ca6b455cf 192.168.56.103:7002@17002 slave 1493e944e61a228a2cfe5fa58866c0f9fe13befb 0 1543820784686 0 connected
ac2cf6f9a81dc30d0feef1c2475429a674ea5a03 192.168.56.105:7000@17000 master - 0 1543820786506 11 connected 0-1023 1365-5460 11264-12287
1493e944e61a228a2cfe5fa58866c0f9fe13befb 192.168.56.101:7002@17002 master - 0 1543820786201 0 connected
050a20ab3750ae41053047ef1fb57c65b1738ff2 192.168.56.101:7001@17001 slave ac2cf6f9a81dc30d0feef1c2475429a674ea5a03 0 1543820785000 11 connected
7710f528109bab3b518065e822753bb6d83749fa 192.168.56.105:7001@17001 myself,slave b13cf9657a49a4df32ac2504c5adfce64b13606a 0 1543820782000 2 connected

### 殺掉主節點 192.168.56.101:7002端口的redis-server進程
shiyf@shiyf-VirtualBox:/usr/local/redis-cluster$ ps -ef|grep redis
root      2220     1  0 11:07 ?        00:00:48 /usr/local/bin/redis-server *:7000 [cluster]
root      2226     1  0 11:07 ?        00:00:40 /usr/local/bin/redis-server *:7001 [cluster]
root      2675     1  0 15:03 ?        00:00:00 /usr/local/bin/redis-server *:7002 [cluster]
shiyf     2680  1985  0 15:04 pts/0    00:00:00 grep --color=auto redis
shiyf@shiyf-VirtualBox:/usr/local/redis-cluster$ sudo kill -9 2675

可以看到刪除後從節點仍然沒有變化,主節點狀態變成 fail
在這裏插入圖片描述> 這時候需要手動將從節點提升爲主節點,保證集羣數據可用
主節點掛掉,如何將從節點升級爲主節點?
如果主節點服務掛掉,我們可以先登錄到從節點服務器上,然後使用 cluster failover force命令,將從節點升級爲主節點。
”CLUSTER FAILOVER”命令支持兩個選項:FORCE和TAKEOVER。使用這兩個選項,可以改變上述的流程。如果有FORCE選項,則從節點不會與主節點進行交互,主節點也不會阻塞其客戶端,而是從節點立即開始故障轉移流程:發起選舉、統計選票、贏得選舉、升級爲主節點並更新配置。
如果有TAKEOVER選項,則更加簡單粗暴:從節點不再發起選舉,而是直接將自己升級爲主節點,接手原主節點的槽位,增加自己的configEpoch後更新配置。
因此,使用FORCE和TAKEOVER選項,主節點可以已經下線;
而不使用任何選項,只發送”CLUSTER FAILOVER”命令的話,主節點必須在線。

###### 如果待刪除節點已經不能連接,則調用CLUSTER FORGET剔除(需要在任一節點上執行一次FORGET):
CLUSTER FORGET '141cdfe5ff0808f20780c8fa574c844027250dad'	

###登錄到從節點 103:7002,並主動發起主節點選舉
redis-cli -h 192.168.56.103 -p 7002
192.168.56.103:7002> cluster failover takeover
OK

手動執行故障轉移後,結果如下(101:7002成爲主節點):
在這裏插入圖片描述

如何通過PHP訪問redis集羣

目前我們用到的 php 的 redis 擴展 主要有2個,第一個是最常用的 phpredis, 它是用c寫的php的高效擴展:https://github.com/phpredis,還有1個是predis, 它是用php代碼寫的,也用的蠻多的:https://github.com/nrk/predis

//這裏以phpredis中的RedisCluster爲例
<?php

//測試主節點讀寫
$objCluster = new RedisCluster(null, ['192.168.56.105:7000', '192.168.56.101:7000', '192.168.56.103:7000']);

$objCluster->lPush('wuguo', 'sunquan');
$objCluster->lPush('wuguo', 'zhouyu');
$objCluster->lPush('wuguo', 'lvmeng');
$objCluster->lPush('wuguo', 'luxun');
$wuguoPersons = $objCluster->lRange('wuguo', 0, -1);

$objCluster->sAdd('weiguo', 'caocao');
$objCluster->sAdd('weiguo', 'guojia');
$objCluster->sAdd('weiguo', 'simayi');
$objCluster->sAdd('weiguo', 'zhangliao');
$weiguoPersons = $objCluster->sMembers('weiguo');

$objCluster->set('person1', 'liubei');
$objCluster->set('person2', 'guanyu');
$objCluster->set('person3', 'zhangfei');
$objCluster->set('person4', 'zhugeliang');
$objCluster->set('person5', 'zhaoyun');
$objCluster->set('person6', 'machao');

$name1 = $objCluster->get('person1');
$name2 = $objCluster->get('person2');
$name3 = $objCluster->get('person3');
$name4 = $objCluster->get('person4');
$name5 = $objCluster->get('person5');
$name6 = $objCluster->get('person6');

echo '<hr/>以下是主節點寫入的內容:';
var_dump($name1, $name2, $name3, $name4, $name5, $name6, $wuguoPersons, $weiguoPersons);

echo '<hr/>';

//測試redis事務
try {
    $objCluster->multi();    
    //$objCluster->get('person1'); //加入這一句可能會報錯,因爲讀寫沒有在一個主節點上操作。
    $objCluster->set('{shuguo}:person7', 'huangzhong');
    $objCluster->set('{shuguo}:person8', 'weiyan');
    $objCluster->get('{shuguo}:person7');
    $objCluster->get('{shuguo}:person8');
    var_dump($objCluster->exec());
    echo '<br/>';
} catch (Exception $e) {
    echo $e->getMessage().'<br/>';
}




//測試從節點讀
$objCluster = new RedisCluster(null, ['192.168.56.105:7001', '192.168.56.101:7001', '192.168.56.103:7001']);

$name1 = $objCluster->get('person1');
$name2 = $objCluster->get('person2');
$name3 = $objCluster->get('person3');
$name4 = $objCluster->get('person4');
$name5 = $objCluster->get('person5');
$name6 = $objCluster->get('person6');

echo '<hr/>以下是從節點讀取的內容:';
var_dump($name1, $name2, $name3, $name4, $name5, $name6, $wuguoPersons, $weiguoPersons);
echo '<hr/>';

//測試獲取主節點
foreach ($objCluster->_masters() as $arrMaster) {
    echo 'master node:' . implode(':', $arrMaster).'<br/>';
}

程序運行結果如下:
以下是主節點寫入的內容:string(6) “liubei” string(6) “guanyu” string(8) “zhangfei” string(10) “zhugeliang” string(7) “zhaoyun” string(6) “machao” array(4) { [0]=> string(5) “luxun” [1]=> string(6) “lvmeng” [2]=> string(6) “zhouyu” [3]=> string(7) “sunquan” } array(4) { [0]=> string(9) “zhangliao” [1]=> string(6) “guojia” [2]=> string(6) “simayi” [3]=> string(6) “caocao” } array(4) { [0]=> bool(true) [1]=> bool(true) [2]=> string(10) “huangzhong” [3]=> string(6) “weiyan” }
以下是從節點讀取的內容:string(6) “liubei” string(6) “guanyu” string(8) “zhangfei” string(10) “zhugeliang” string(7) “zhaoyun” string(6) “machao” array(4) { [0]=> string(5) “luxun” [1]=> string(6) “lvmeng” [2]=> string(6) “zhouyu” [3]=> string(7) “sunquan” } array(4) { [0]=> string(9) “zhangliao” [1]=> string(6) “guojia” [2]=> string(6) “simayi” [3]=> string(6) “caocao” }
master node:192.168.56.105:7000
master node:192.168.56.101:7000
master node:192.168.56.103:7002
master node:192.168.56.103:7000

與codies有何區別

Codies Redis cluster 備註
Redis版本 2.8.13分支開發 >= 3.0
部署 較複雜。 簡單
運維 Dashboard,運維方便。 運維人員手動通過命令操作。
監控 可在Dashboard裏監控當前redis-server節點情況,較爲便捷。 不提供監控功能。
組織架構 Proxy-Based 類中心化架構,集羣管理層與存儲層解耦。 P2P模型,gossip協議。去中心化,
伸縮性 動態伸縮。 需要手工增刪節點
Server羣組主從複製 不負責 負責。
主節點失效處理 不自動選主,交由運維人員處理。 自動選主。
數據遷移 以slot爲單位,遷移期間保證可用性。 開源的工具可以在github中獲取 redis-migrate-tool支持3.*版本的數據遷移
升級 基於redis 2.8.13分支開發,後續升級不能保證;Redis-server必須是此版本的codis,無法使用新版本redis的增強特性。 Redis官方推出,後續升級可保證。 升級需要重新加載數據,數據量較大的情況下, 分批次升級bin對運維要求比較高。
可靠性 經過線上服務驗證,可靠性較高。 現在已經出現3.0/4.0及5.0版本,均支持redis-cluster
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章