Linux下redis集羣方案之redis cluster的搭建部署(redis版本:redis-5.0.3)

 

對於Redis集羣方案有好多種,基本經常使用的就是twemproxy,codis,redis  cluster這三種解決方案。node

 

本博文介紹redis  clusterlinux

 

上篇博文實現redis的高可用,針對的主要是master宕機的狀況,咱們發現全部節點的數據都是同樣的,那麼一旦數據量過大,redis也會存在效率降低的問題,redis3.0版本正式推出後,有效地解決了redis分佈式方面的需求,當遇到單機內存,併發,流量等瓶頸時,能夠採用Cluster架構方法達到負載均衡的目的。redis

 

一.redis  cluster集羣的介紹

 

1.redis使用中遇到的瓶頸算法

 

咱們平常在對於redis的使用中,常常會遇到一些問題vim

  一、容量問題,單實例redis內存沒法無限擴充,達到32G後就進入了64位世界,性能降低。ruby

  二、併發性能問題,redis號稱單實例10萬併發,但也是有盡頭的。服務器

 

2.redis-cluster的優點  架構

 

一、官方推薦,毋庸置疑。併發

二、去中心化,集羣最大可增長1000個節點,性能隨節點增長而線性擴展。app

三、管理方便,後續可自行增長或摘除節點,移動分槽等等。

四、簡單,易上手。

 

3.redis-cluster名詞介紹

 

一、master  主節點、

二、slave   從節點

三、slot    槽,一共有16384數據分槽,分佈在集羣的全部主節點中。

 

4.redis-cluster的設計

Redis集羣搭建的方式有多種,例如使用zookeeper等,但從redis 3.0以後版本支持redis-cluster集羣,Redis-Cluster採用無中心結構,每一個節點保存數據和整個集羣狀態,每一個節點都和其餘全部 節點鏈接。其redis-cluster架構圖以下:

redis-cluster

圖中描述的是六個redis實例構成的集羣

6379端口爲客戶端通信端口

16379端口爲集羣總線端口

集羣內部劃分爲16384個數據分槽,分佈在三個主redis中。

從redis中沒有分槽,不會參與集羣投票,也不會幫忙加快讀取數據,僅僅做爲主機的備份。

三個主節點中平均分佈着16384數據分槽的三分之一,每一個節點中不會存有有重複數據,僅僅有本身的從機幫忙冗餘。

 

其結構特色:

     一、全部的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬。
     二、節點的fail是經過集羣中超過半數的節點檢測失效時才生效。
     三、客戶端與redis節點直連,不須要中間proxy層。客戶端不須要鏈接集羣全部節點,鏈接集羣中任何一個可用節點便可。
     四、redis-cluster把全部的物理節點映射到[0-16383]slot上,cluster 負責維護node<->slot<->value。

     五、Redis集羣預分好16384個桶,當須要在 Redis 集羣中放置一個 key-value 時,根據 CRC16(key) mod 16384的值,決定將一個key放到哪一個桶中。

 

 5.redis cluster節點分配

 

        假設咱們如今有三個主節點,分別是:A, B, C 三個節點,它們能夠是一臺機器上的三個端口,也能夠是三臺不一樣的服務器。那麼,採用哈希槽 (hash slot)的方式來分配16384個slot 的話,它們三個節點分別承擔的slot 區間是:


      節點A覆蓋0-5460;
      節點B覆蓋5461-10922;
      節點C覆蓋10923-16383。

    

     獲取數據:

        若是存入一個值,按照redis cluster哈希槽的算法: CRC16('key')%16384 = 6782。 那麼就會把這個key 的存儲分配到 B 上了。一樣,當我鏈接(A,B,C)任何一個節點想獲取'key'這個key時,也會這樣的算法,而後內部跳轉到B節點上獲取數據。

    

     新增一個主節點:

        新增一個節點D,redis cluster的這種作法是從各個節點的前面各拿取一部分slot到D上,我會在接下來的實踐中實驗。大體就會變成這樣:
  

    節點A覆蓋1365-5460
    節點B覆蓋6827-10922
    節點C覆蓋12288-16383
    節點D覆蓋0-1364,5461-6826,10923-12287


     一樣刪除一個節點也是相似,移動完成後就能夠刪除這個節點了。

 

6.Redis Cluster主從模式

          redis cluster 爲了保證數據的高可用性,加入了主從模式,一個主節點對應一個或多個從節點,主節點提供數據存取,從節點則是從主節點拉取數據備份,當這個主節點掛掉後,就會有這個從節點選取一個來充當主節點,從而保證集羣不會掛掉。

      上面那個例子裏,集羣有ABC三個主節點,,若是這3個節點都沒有加入從節點,若是B掛掉了,咱們就沒法訪問整個集羣了。A和C的slot也沒法訪問。

     因此咱們在集羣創建的時候,必定要爲每一個主節點都添加了從節點, 好比像這樣,,集羣包含主節點A、B、C,,以及從節點A一、B一、C1,那麼即便B掛掉系統也能夠繼續正確工做。

     B1節點替代了B節點,因此Redis集羣將會選擇B1節點做爲新的主節點,集羣將會繼續正確地提供服務。 當B從新開啓後,它就會變成B1的從節點。

    不過須要注意,若是節點B和B1同時掛了,Redis集羣就沒法繼續正確地提供服務了。

 

二.實驗環境

 

1.selinux和firewalld狀態爲disabled

2.各主機信息以下:

主機 ip
server1 172.25.83.1

3.節點準備(官方推薦三主三從的配置方式。

redis3.0及以上版本實現,集羣中至少應該有奇數個節點,因此至少有三個節點,每一個節點至少有一個備份節點,因此下面使用6節點(主節點、備份節點由redis-cluster集羣肯定)。

172.25.83.1:7001,172.25.83.1:7002,172.25.83.1:7003,172.25.83.1:7004,172.25.83.1:7005,172.25.83.1:7006搭建初始集羣。

172.25.83.1:7007,172.25.83.1:7008擴容時用到。

 

三.redis  cluster集羣的部署

 

配置server1:(由於server1以前是作過主從切換的,因此redis已經安裝好。

 

1.停掉redis服務(redis服務自己監聽的端口是6379端口)

 

[root@server1 ~]# /etc/init.d/redis_6379 stop

 

 

2.建立目錄,用於存放redis  Cluster對應的節點配置文件

 

[root@server1 ~]# mkdir /usr/local/rediscluster
[root@server1 ~]# cd /usr/local/rediscluster/
[root@server1 rediscluster]# mkdir 700{1..6}
[root@server1 rediscluster]# ls
7001  7002  7003  7004  7005  7006

 

3.編寫redis Cluster對應的節點的配置文件,並啓動redis  Cluster對應的全部節點

 

(1)編輯配置文件,下面給出的是一個節點7001的配置文件(其他節點(7002-7006)的配置文件跟這個配置文件相似,只須要將其中的7001改成對應的節點便可

[root@server1 rediscluster]# cd 7001/
[root@server1 7001]# vim redis.conf
port 7001                #端口
cluster-enabled yes      #若是是yes,表示啓用集羣,不然以單例模式啓動
cluster-config-file nodes.conf     #請注意,儘管有此選項的名稱,但這不是用戶可編輯的配置文件,而是Redis羣集節點每次發生更改時自動保留羣集配置(基本上爲狀態)的文件,以便可以 在啓動時從新讀取它。 該文件列出了羣集中其餘節點,它們的狀態,持久變量等等。 因爲某些消息的接收,一般會將此文件重寫並刷新到磁盤上。
cluster-node-timeout 5000     #Redis羣集節點超過不可用的最長時間,而會將其視爲失敗。 若是主節點超過指定的時間不可達,它將由其從屬設備進行故障切換。 此參數控制Redis羣集中的其餘重要事項。 值得注意的是,每一個沒法在指定時間內到達大多數主節點的節點將中止接受查詢。
appendonly yes     #是否開啓appendonlylog,開啓的話每次寫操做會記一條log,這會提升數據抗風險能力,但影響效率。
pidfile "/usr/local/rediscluster/7001/redis.pid"      #pid文件存放的位置
logfile "/usr/local/rediscluster/7001/redis.log"      #日誌文件存放的位置 
daemonize yes        #打入後臺
dir "/usr/local/rediscluster/7001"    #該節點所在目錄

 

 

(2)啓動節點,下面給出的是7001節點的啓動方法(其他節點(7002-7006)的啓動方法,相似。只須要把7001改成對應的節點便可

[root@server1 7001]# redis-server redis.conf   #啓動7001節點 
[root@server1 7001]# netstat -antulpe     #查看端口,是否有7001端口,以確保7001端口已經啓動

 

 

4.建立集羣(集羣中的主從節點是隨機的

redis3版本利用redis-trib.rb命令來建立集羣,以下所示:

節點所有啓動後,每一個節點目前只能識別出本身的節點信息,彼此之間並不知道對方的存在;

採用redis-trib.rb來實現集羣的快速搭建,redis-trib.rb是採用Rudy實現的集羣管理工具,內部經過Cluster相關命令幫咱們實現簡化集羣建立,檢查,槽遷移和均衡等常見的運維操做。

 

(1)安裝redis-trib所需的 ruby環境

 

[root@server1 ~]# yum install ruby -y

 

(2)將redis-trib.rb對應的腳本文件放到/usr/local/bin目錄下,以便直接敲擊redis-trib.rb命令

 

[root@server1 ~]# cd redis-5.0.3/src/
[root@server1 src]# cp redis-trib.rb /usr/local/bin/

 

 

(3)使用redis-trib.rb建立集羣

 

 

 

 

既然redis-trib.rb命令用不了,那麼/usr/local/bin目錄下的redis-trib.rb腳本就能夠刪除了。

 

 

可是redis5版本,再也不使用redis-trib.rb來命令來建立集羣了,從上面的提示,咱們能夠看出,須要使用redis-cluster來建立集羣,過程以下:


 

[root@server1 ~]# redis-cli --cluster help    #在使用redis-cli --cluster命令以前,能夠先查看下redis-cli --cluster命令的幫助
  create         host1:port1 ... hostN:portN
                 --cluster-replicas <arg>
[root@server1 ~]# redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006   #輸入yes
# 使用create命令 --replicas 1 參數表示爲每一個主節點建立一個從節點,其餘參數是實例的地址集合。

 

建立過程當中會給出主從節點角色分配的計劃,以下圖所示

爲何172.25.83.1:7001,172.25.83.1:7002,172.25.83.1:7003是主節點,請看上圖,當咱們贊成這份計劃以後,輸入yes,redis-cli  --cluster開始執行節點握手和槽分配操做,輸出以下:

 

最終能夠看到:(固然下面的信息,也能夠登陸每一個節點(例如:redis-cli  -p  7001),查看每一個節點的info replication,來獲取)

(1)主節點:7001;對應的從節點爲:7005

(2)主節點:7002;對應的從節點爲:7006

(3)主節點:7003;對應的從節點爲:7004

 

此時能夠利用下面的命令來查看該集羣的信息以查看該集羣的主節點:

[root@server1 bin]# redis-cli --cluster info 127.0.0.1:7001    #節點7001,能夠換爲任何一個節點,看到的結果都是同樣的

 

 

redis集羣的測試:測試存取值

 

客戶端鏈接集羣redis-cli須要帶上 -c ,redis-cli -c -p 端口號

 

根據redis-cluster的key值分配,name應該分配到節點7002[5461-10922]上,上面顯示redis cluster自動從7001跳轉到了7002節點。

咱們能夠測試一下7004從節點獲取name值

 

 

結論:

7006位7003的從節點,從上面也是自動跳轉至7002獲取值,這也是redis cluster的特色,它是去中心化,每一個節點都是對等的,鏈接哪一個節點均可以獲取和設置數據。

 

四.redis  cluster集羣的故障遷移

 

(1)查看7002節點上的全部key,並手動將7002節點掛掉

 

 

此時看到進程中已經沒有7002節點對應的進程了

 

(2)再次查看集羣的信息,能夠看到7006節點(以前7002節點的從節點)已經成爲主節點。查看7006節點的全部key,能夠看出7006節點承擔着7002節點的角色。對外提供的服務不受影響

 

 

可是此時,若是將7006節點也手動down掉,那麼該集羣也就費了。

 

五.redis  cluster集羣的擴容

 

配置過程

 

新增節點:172.25.83.1:7007,172.25.83.1:7008。配置文件與以前的基本一致

1.建立目錄

 

[root@server1 rediscluster]# mkdir 700{7,8}
[root@server1 rediscluster]# ls
7001  7002  7003  7004  7005  7006  7007  7008

 

2.編輯配置文件

 

[root@server1 7007]# vim redis.conf

 

[root@server1 7008]# vim redis.conf

 

3.啓動7007和7008節點

 

[root@server1 7007]# redis-server redis.conf
[root@server1 7008]# redis-server redis.conf
[root@server1 7008]# ps ax

 

 

4.加入集羣

 

(1)新增主節點

[root@server1 7008]# redis-cli --cluster help
add-node       new_host:new_port existing_host:existing_port
               --cluster-slave
               --cluster-master-id <arg>
#existing_port——這個是必傳參數,用來從一個節點獲取整個集羣信息,至關於獲取集羣信息的入口。
check          host:port
               --cluster-search-multiple-owners
#host:port——這個是必傳參數,用來從一個節點獲取整個集羣信息,至關於獲取集羣信息的入口。
[root@server1 7008]# redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001  
#往集羣中添加端口7007,
#存在的端口能夠寫7001-7006中的任意一個
[root@server1 7008]# redis-cli --cluster check 127.0.0.1:7001   
#檢測節點,以查看7007節點的id號,以便將7008加入集羣,做爲7007的從節點。
#端口能夠寫7001-7007中的任意一個

 

 

(2)新增從節點

[root@server1 7008]# redis-cli --cluster add-node 127.0.0.1:7008 127.0.0.1:7007 --cluster-slave --cluster-master-id "239b6e3dfa0d35fb64ed7b3c839ec99129107a90"  
#將7008節點添加成7007的從節點
#這裏的239b6e3dfa0d35fb64ed7b3c839ec99129107a90爲節點7007的id號
#這裏的第二個節點,必須寫7007,不能寫別的節點。由於這步是要將節點7008添加稱爲7007的節點
[root@server1 7008]# redis-cli --cluster check 127.0.0.1:7001   
#檢測節點,以查看7007節點和7008節點是否添加成功,並查看槽的分配狀況

 

 

至此,集羣的添加也就完成了。

 

5.遷移槽和數據

 

[root@server1 7008]# redis-cli --cluster help
 reshard        host:port
                --cluster-from <arg>
                --cluster-to <arg>
                --cluster-slots <arg>
                --cluster-yes
                --cluster-timeout <arg>
                --cluster-pipeline <arg>
                --cluster-replace
#host:port——這個是必傳參數,用來從一個節點獲取整個集羣信息,至關於獲取集羣信息的入口。
[root@server1 7008]# redis-cli --cluster reshard 127.0.0.1:7007 --cluster-from all --cluster-to "239b6e3dfa0d35fb64ed7b3c839ec99129107a90" --cluster-slots 300 --cluster-yes       
#從全部節點遷移300個槽給127.0.0.1:7007,這裏的"239b6e3dfa0d35fb64ed7b3c839ec99129107a90"爲節點7007的id號;
#這裏的節點7007能夠寫7001-7008中的任意一個節點任意的一個節點,由於幫助中沒有代表是已經存在的節點,仍是新節點,因此均可以。

#這裏也能夠寫4096個槽,若是這裏寫4096(13684/4=4096),那麼槽就獲得了平均分配,也就不須要下一步的平均分配槽的操做了。

 

 

6.執行命令使得槽平均分配

 

[root@server1 7008]# redis-cli --cluster help
rebalance      host:port
               --cluster-weight <node1=w1...nodeN=wN>
               --cluster-use-empty-masters
               --cluster-timeout <arg>
               --cluster-simulate
               --cluster-pipeline <arg>
               --cluster-threshold <arg>
               --cluster-replace
host:port:這個是必傳參數,用來從一個節點獲取整個集羣信息,至關於獲取集羣信息的入口。
--weight <arg>:節點的權重,格式爲node_id=weight,若是須要爲多個節點分配權重的話,須要添加多個--weight <arg>參數,即--weight b31e3a2e=5 --weight 60b8e3a1=5,node_id可爲節點名稱的前綴,只要保證前綴位數能惟一區分該節點便可。沒有傳遞–weight的節點的權重默認爲1。
--auto-weights:這個參數在rebalance流程中並未用到。
--threshold <arg>:只有節點須要遷移的slot閾值超過threshold,纔會執行rebalance操做。具體計算方法能夠參考下面的rebalance命令流程的第四步。
--use-empty-masters:rebalance是否考慮沒有節點的master,默認沒有分配slot節點的master是不參與rebalance的,設置--use-empty-masters可讓沒有分配slot的節點參與rebalance。
--timeout <arg>:設置migrate命令的超時時間。
--simulate:設置該參數,能夠模擬rebalance操做,提示用戶會遷移哪些slots,而不會真正執行遷移操做。
--pipeline <arg>:與reshar的pipeline參數同樣,定義cluster getkeysinslot命令一次取出的key數量,不傳的話使用默認值爲10。
[root@server1 7008]# redis-cli --cluster rebalance 127.0.0.1:7008 --cluster-threshold 1 --cluster-use-empty-masters   #平衡集羣節點slot數量
[root@server1 7008]# redis-cli --cluster check 127.0.0.1:7008  #檢測節點,查看slot的分配狀況,以查看是否平衡成功

 

 

看到每一個主節點的solt數量都是4096(solt的區間爲:0-1364;5461-6826;10923-12287),表示solt數量平衡成功。

 

測試過程:

 

測試一下7007主節點和7008從節點獲取name值

 


 

結論:

節點7007和7008能夠獲得name的值,表示redis cluster集羣的擴容配置成功。值的注意的是:當7008節點獲取name值時,自動跳轉到了7007節點,而不是以前的7002節點。這是由於:以前redis  cluster在擴容時。將存儲name值的slot(5798)轉移到7007主節點上了

 

六.redis  cluster集羣的收縮

 

咱們下線7007和7008節點

 

(1)經過集羣節點信息,咱們之道7007主節點負責的solt爲:0-1364;5461-6826;10923-12287。如今咱們把0-1364遷移到7001;5461-6826遷移到7002;10923-12287遷移到7003。

 

[root@server1 7008]# redis-cli --cluster reshard 127.0.0.1:7007
How many slots do you want to move (from 1 to 16384)? 1365   #1365個slot,第一次默認是0-1364
What is the receiving node ID? 14a0f59768d46879c929afc62018421db53a5efd   #7001節點的id
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: 239b6e3dfa0d35fb64ed7b3c839ec99129107a90    #70007節點的id
Source node #2: done
Do you want to proceed with the proposed reshard plan (yes/no)? yes

 

[root@server1 7008]# redis-cli --cluster reshard 127.0.0.1:7007
How many slots do you want to move (from 1 to 16384)? 1366   #移1366個slot,第二次默認是5461-6826
What is the receiving node ID? d93240e95225c62eb00072b378d6956c1a1ac8c8   #7002節點的id
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: 239b6e3dfa0d35fb64ed7b3c839ec99129107a90    #7007節點的id
Source node #2: done 
Do you want to proceed with the proposed reshard plan (yes/no)? yes

 

[root@server1 7008]# redis-cli --cluster reshard 127.0.0.1:7007
How many slots do you want to move (from 1 to 16384)? 1365   #1365個slot,第三次默認是10923-12287
What is the receiving node ID? 6444903d022f2707db089ba53b76ea9170df06b5   #7003的id
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: 239b6e3dfa0d35fb64ed7b3c839ec99129107a90  #7007的id
Source node #2: done    
Do you want to proceed with the proposed reshard plan (yes/no)? yes

 

槽節點遷移完以後,查看集羣的信息,發現7007已經沒有分配槽了

 

 

(2)忘記節點:

因爲集羣內的節點不停地經過Gossip消息彼此交換節點信息,所以須要經過一種健壯的機制讓集羣內全部節點忘記下線的節點。也就是說讓其餘節點再也不與要下線的節點進行Gossip消息交換。

 

利用redis-cli  --cluster  del-node命令實現節點下線,先下線從節點再下線主節點,避免沒必要要的全量複製。命令以下:

 

[root@server1 7008]# redis-cli --cluster help
del-node       host:port node_id
[root@server1 7008]# redis-cli --cluster del-node 127.0.0.1:7008 7fe1e1e925a1a7219d014255278a1a3a9b2cab18    
#下線從節點7008
#該id是7008的id,而且節點必須寫7008。不能隨便寫個節點
[root@server1 7008]# redis-cli --cluster del-node 127.0.0.1:7007 239b6e3dfa0d35fb64ed7b3c839ec99129107a90
#下線主節點7007
#該id是7007的id,而且節點必須寫7008。不能隨便寫個節點

 

 

此時查看集羣的信息,發現7007和7008節點已經不存在,其進程也已被殺死

 

 

 

結論:

集羣信息中已經沒有節點7007和7008,表名redis cluster集羣的收縮配置成功。