1. 程式人生 > >在centos上搭建redis叢集並附測試(真叢集非偽叢集)

在centos上搭建redis叢集並附測試(真叢集非偽叢集)

環境:centos6.5 x86  32位    redis3.2.8  ruby-2.2.3

一. redis叢集原理

redis是單執行緒,但是一般的作為快取使用的話,redis足夠了,因為它的讀寫速度太快了。
官方的一個簡單測試:
測試完成了50個併發執行100000個請求。
設定和獲取的值是一個256位元組字串。
結果:讀的速度是110000次/s,寫的速度是81000次/s 
在這麼快的讀寫速度下,對於一般程式來說足夠用了,但是對於訪問量特別大的網站來說,還是稍有不足。
那麼,如何提升redis的效能呢?看標題就知道了,搭建叢集。

先來一張redis叢集的架構圖:


    在這個圖中,每一個藍色的圈都代表著一個redis的伺服器節點。它們任何兩個節點之間都是相互連通的。客戶端可以與任何一個節點相連線,
然後就可以訪問叢集中的任何一個節點。對其進行存取和其他操作。
   那麼redis是怎麼做到的呢?首先,在redis的每一個節點上,都有這麼兩個東西,一個是插槽(slot)可以理解為是一個可以儲存兩個數值的一個變數。
這個變數的取值範圍是:0-16383。還有一個就是cluster我個人把這個cluster理解為是一個叢集管理的外掛。當我們的存取的key到達的時候,
redis會根據crc16的演算法得出一個結果,然後把結果對 16384 求餘數,這樣每個 key 都會對應一個編號在 0-16383 之間的雜湊槽,
通過這個值,去找到對應的插槽所對應的節點,然後直接自動跳轉到這個對應的節點上進行存取操作。


還有就是因為如果叢集的話,是有好多個redis一起工作的,那麼,就需要這個叢集不是那麼容易掛掉,所以呢,理論上就應該給叢集中的每個節點至少一個備用的redis服務。
這個備用的redis稱為從節點(slave)。那麼這個叢集是如何判斷是否有某個節點掛掉了呢?

首先要說的是,每一個節點都存有這個叢集所有主節點以及從節點的資訊。

它們之間通過互相的ping-pong判斷是否節點可以連線上。如果有一半以上的節點去ping一個節點的時候沒有迴應,叢集就認為這個節點宕機了,
然後去連線它的備用節點。如果某個節點和所有從節點全部掛掉,我們叢集就進入faill狀態。還有就是如果有一半以上的主節點宕機,那麼我們叢集同樣進入發力了狀態。
這就是我們的redis的投票機制,具體原理如下圖所示:


(1)投票過程是叢集中所有master參與,如果半數以上master節點與master節點通訊超時(cluster-node-timeout),認為當前master節點掛掉.
(2):什麼時候整個叢集不可用(cluster_state:fail)? 
   a:如果叢集任意master掛掉,且當前master沒有slave.叢集進入fail狀態,也可以理解成叢集的slot對映[0-16383]不完整時進入fail狀態. 
    ps : redis-3.0.0.rc1加入cluster-require-full-coverage引數,預設關閉,開啟叢集相容部分失敗.
   b:如果叢集超過半數以上master掛掉,無論是否有slave,叢集進入fail狀態.

二 .  叢集安裝配置

2.1  安裝配置redis

     此步省略,請參考我到博文【http://blog.csdn.net/wx5040257/article/details/78347729】【http://blog.csdn.net/wx5040257/article/details/78388588】

我準備的伺服器ip及各伺服器角色如下圖所示:


各節點間互聯互通,master和slave由建立叢集時確定。

2.2 安裝cluster依賴環境
     只需在任意一臺主機上(如169.254.130.122)安裝即可。

     先按照Ruby,注意,不要用yum命令安裝,yum命令安裝的版本較低,後續步驟會報錯,如圖:


建議進行原始碼安裝。

2.2.1  安裝ruby

      解壓縮原始碼包,並移動到/usr/local/src目錄下

#  tar  -zxf  

# mv  ruby-2.2.3  /usr/local/src/ruby

      進入原始碼目錄進行安裝

#  cd   /usr/local/src/ruby

#  ./configure

# make  && make install

安裝完畢後如圖所示:


提示系統缺失zlib,可能後續還要安裝zlib包,請繼續往下看。可用ruby  -v命令檢視安裝成功的ruby版本。

2.2.2  安裝ruby  redis介面

# gem  install  redis

報錯,如圖所示:


解決方案,安裝zlib-dev,yum命令安裝即可

# yum  -y  install zlib-devel     

然後進入ruby原始碼資料夾
安裝ruby自身提供的zlib包
#cd ext/zlib
#ruby ./extconf.rb
#make
#make install

接下來再執行

# gem  install  redis

又報錯,如下所示:

[[email protected] zlib]# gem install redis
ERROR:  While executing gem ... (Gem::Exception)
    Unable to require openssl, install OpenSSL and rebuild ruby (preferred) or use non-HTTPS sources
原因:
缺少openssl,需要安裝openssl包,我現在這裡來安裝一個openssl-1.0.1s.tar.gz(下載連結:http://www.openssl.org/source/)
解決方法步驟:
1.解壓在/usr/local/src目錄下,進入/usr/local/src/openssl目錄準備安裝:
[[email protected] src]# cd /usr/local/src/openssl
[[email protected] openssl]# ./config -fPIC --prefix=/usr/local/openssl enable-shared  
[[email protected] openssl]# ./config -t  
[[email protected] openssl]# make && make install
openssl的配置檔案必須要配置-fPIC引數,如果沒有該引數下面的安裝中會出現問題!
安裝完成,可以檢測一下是否安裝成功:
[[email protected] openssl]# openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013
2.進入ruby原始碼[/usr/local/src/ruby]目錄下的ext/openssl 目錄:
[[email protected] openssl]# cd ../ruby-2.3.0  
[[email protected] ruby]# cd ext/openssl  
[[email protected] openssl]# ruby extconf.rb  
checking for t_open() in -lnsl... no  
checking for socket() in -lsocket... no  
checking for assert.h... yes  
checking for openssl/ssl.h... no  
提示沒有找到ssl.h, 因為出現了錯誤:openssl/ssl.h ....  no    ,輸入如下程式碼,重新執行:
# ruby extconf.rb --with-openssl-include=/usr/local/openssl/include/ --with-openssl-lib=/usr/local/openssl/lib
checking for EVP_CIPHER_CTX.engine in openssl/evp.h... yes
checking for X509_ATTRIBUTE.single in openssl/x509.h... yes
checking for OPENSSL_FIPS in openssl/opensslconf.h... no
checking for EVP_CTRL_GCM_GET_TAG in openssl/evp.h... yes
creating extconf.h
creating Makefile
[[email protected] openssl]#
ok,成功
3.接下來並且將ruby 原始碼目錄下的include目錄軟連結到 / 目錄下:

# ln  -s  /usr/local/src/ruby/include  / 

注意:建立軟鏈的時候一定要寫全路徑,不能寫相對路徑

4.  接下來,繼續在ext/openssl 目錄下執行:

[root[email protected] openssl]# pwd
/usr/local/src/ruby/ext/openssl
[[email protected] openssl]# make && make install
再次使用gem install 安裝 ruby redis 介面:

# gem install  redis

仍然報錯:

[[email protected] openssl]# gem install redis
ERROR:  Could not find a valid gem 'redis' (>= 0), here is why:
          Unable to download data from https://rubygems.org/ - SSL_connect returned=1 errno=0 state=error: certificate verify failed (https://api.rubygems.org/specs.4.8.gz)
意思上無法自動下載rubygems安裝,那好吧,我們自己下載安裝,例如我下載的是:redis-3.2.1.gem
[[email protected] soft]# gem install redis-3.2.1.gem 
Successfully installed redis-3.2.1
Parsing documentation for redis-3.2.1
Installing ri documentation for redis-3.2.1
Done installing documentation for redis after 1 seconds
WARNING:  Unable to pull data from 'https://rubygems.org/': SSL_connect returned=1 errno=0 state=error: certificate verify failed (https://api.rubygems.org/specs.4.8.gz)
1 gem installed
ok,安裝成功了!

2.3  接下來進行叢集的建立

1.  在各節點進行叢集配置,如圖:

#  vi   /usr/redis/redis.conf


cluster-enabled  yes  ==>表示開啟叢集功能

cluster-config-file  nodes-6379.conf   ====>表示自動生成的叢集配置檔案

cluster-node-timeout   15000====>  表示叢集節點連線超時時間

2.  建立叢集

建立叢集環境的命令格式為redis-trib.rb create --replicas <slaveCount> masterNode1,masterNode2,masterNodeN,slaveNode1,slaveNode2,slaveNodeN
Node的格式為"IP:port",slaveCount表示每個masterNode對應的slaveNode個數,在叢集環境中可以沒有slave(在命令中省略掉slaveNode部分即可)。
但如果有slave,則命令中,前n中個節點都為master,後n個節點都為slave,第n個master節點對應的slave應該是第n個。

注意:建立叢集前,每個節點到資料都要清空,用flushall命令

127.0.0.1:6379 > flushall

執行命令建立叢集:

redis-trib.rb create --replicas 1 169.254.130.122:6379 169.254.130.10:6379 169.254.130.20:6379 
169.254.130.12:6379 169.254.130.11:6379 169.254.130.25:6379  
注意:這條命令沒有跨行

出現如下提示資訊:

>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
169.254.130.122:6379
169.254.130.10:6379
169.254.130.20:6379
Adding replica 169.254.130.12:6379 to 169.254.130.122:6379
Adding replica 169.254.130.11:6379 to 169.254.130.10:6379
Adding replica 169.254.130.25:6379 to 169.254.130.20:6379
M: 89d0ca92c42dfd6fa8cd2286099a331687cc3620 169.254.130.122:6379
   slots:0-5460,9189 (5462 slots) master
M: b5d5a4a43778b7fdb64520538ace4a3a258b552a 169.254.130.10:6379
   slots:5461-10922 (5462 slots) master
M: daf3d1fa25405ae834db58d071f9b9a5165125ba 169.254.130.20:6379
   slots:312,700,741,2076,2880,4377,4576,7141,8931,8975,9189,10780,10923-16383 (5473 slots) master
S: c79959320e43ea0884d6f5914ead5198cd3d3f22 169.254.130.12:6379
   replicates 89d0ca92c42dfd6fa8cd2286099a331687cc3620
S: 8a38aee74310f5aeffbcabdc676f64853acf77d5 169.254.130.11:6379
   replicates b5d5a4a43778b7fdb64520538ace4a3a258b552a
S: a3b0e2a4ce8c4df395506942163f21db39ae9fb3 169.254.130.25:6379
   replicates daf3d1fa25405ae834db58d071f9b9a5165125ba
Can I set the above configuration? (type 'yes' to accept): 
從上面可看出,六個節點都處於"OK"狀態,並且前三個6379埠的都為master,而都三個6379埠的都為slave。

此時出現提示,鍵入yes後,各節點將會進行互聯操作
輸入yes,接下來報錯了:

Can I set the above configuration? (type 'yes' to accept): yes
/usr/local/lib/ruby/gems/2.2.0/gems/redis-3.2.1/lib/redis/client.rb:113:in `call': ERR Slot 4788 is already busy (Redis::CommandError)
        from /usr/local/lib/ruby/gems/2.2.0/gems/redis-3.2.1/lib/redis.rb:2556:in `block in method_missing'
        from /usr/local/lib/ruby/gems/2.2.0/gems/redis-3.2.1/lib/redis.rb:37:in `block in synchronize'
        from /usr/local/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
        from /usr/local/lib/ruby/gems/2.2.0/gems/redis-3.2.1/lib/redis.rb:37:in `synchronize'
        from /usr/local/lib/ruby/gems/2.2.0/gems/redis-3.2.1/lib/redis.rb:2555:in `method_missing'
        from /usr/redis/src/redis-trib.rb:212:in `flush_node_config'
        from /usr/redis/src/redis-trib.rb:776:in `block in flush_nodes_config'
        from /usr/redis/src/redis-trib.rb:775:in `each'
        from /usr/redis/src/redis-trib.rb:775:in `flush_nodes_config'
        from /usr/redis/src/redis-trib.rb:1296:in `create_cluster_cmd'
        from /usr/redis/src/redis-trib.rb:1701:in `<main>'
錯誤提示是
      slot插槽被佔用了(這是 搭建叢集前時,以前redis的舊資料和配置資訊沒有清理乾淨。)
解決方案是
          用redis-cli 登入到每個節點執行  flushall  和 cluster reset  就可以了。
然後重新執行建立叢集的命令:

#  redis-trib.rb create --replicas 1 169.254.130.122:6379 169.254.130.10:6379  ....(省略)

接下來又卡住了,如下:

Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join........................................................................
.......................................................................................................
....................................................................................
原因:
redis叢集不僅需要開通redis客戶端連線的埠,而且需要開通叢集匯流排埠
叢集匯流排埠為redis客戶端連線的埠 + 10000
如redis埠為6379
則叢集匯流排埠為16379
故,所有伺服器的點需要開通redis的客戶端連線埠和叢集匯流排埠
注意:iptables 放開,如果有安全組,也要放開這兩個埠

受不了啦,把所有節點的防火牆全部關閉算了。重新執行建立叢集的命令,這回成功了:

Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
2210:M 04 Nov 04:02:59.467 # IP address for this node updated to 169.254.130.122
Waiting for the cluster to join.
>>> Performing Cluster Check (using node 169.254.130.122:6379)
M: 89d0ca92c42dfd6fa8cd2286099a331687cc3620 169.254.130.122:6379
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: 8a38aee74310f5aeffbcabdc676f64853acf77d5 169.254.130.11:6379
   slots: (0 slots) slave
   replicates b5d5a4a43778b7fdb64520538ace4a3a258b552a
M: daf3d1fa25405ae834db58d071f9b9a5165125ba 169.254.130.20:6379
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
M: b5d5a4a43778b7fdb64520538ace4a3a258b552a 169.254.130.10:6379
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: a3b0e2a4ce8c4df395506942163f21db39ae9fb3 169.254.130.25:6379
   slots: (0 slots) slave
   replicates daf3d1fa25405ae834db58d071f9b9a5165125ba
S: c79959320e43ea0884d6f5914ead5198cd3d3f22 169.254.130.12:6379
   slots: (0 slots) slave
   replicates 89d0ca92c42dfd6fa8cd2286099a331687cc3620
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[[email protected] redis]# 2210:M 04 Nov 04:03:02.322 * Slave 169.254.130.12:6379 asks for synchronization
2210:M 04 Nov 04:03:02.322 * Full resync requested by slave 169.254.130.12:6379
2210:M 04 Nov 04:03:02.322 * Starting BGSAVE for SYNC with target: disk
2210:M 04 Nov 04:03:02.326 * Background saving started by pid 2502
2502:C 04 Nov 04:03:02.347 * DB saved on disk
2502:C 04 Nov 04:03:02.348 * RDB: 0 MB of memory used by copy-on-write
2210:M 04 Nov 04:03:02.352 * Background saving terminated with success
2210:M 04 Nov 04:03:02.352 * Synchronization with slave 169.254.130.12:6379 succeeded
2210:M 04 Nov 04:03:04.371 # Cluster state changed: ok
從上面可看出16384個雜湊槽已均勻分配給了三個master節點,分別為:
     169.254.130.20:6379(10923-16384)
     169.254.130.10:6379(5461-10922)
     169.254.130.122:6379(0-5460)

大功告成!!!

2.5  進行測試

登入122主機,用redis-cli   -c命令

-c命令在連線叢集結點時使用,此選項可防止moved和ask異常。

[[email protected] redis]# redis-cli -c
127.0.0.1:6379> set key1 "hello redis cluster"
-> Redirected to slot [9189] located at 169.254.130.10:6379
OK
169.254.130.10:6379> set key2 java
-> Redirected to slot [4998] located at 169.254.130.122:6379
OK
169.254.130.122:6379> 
169.254.130.122:6379> keys *
1) "key2"
169.254.130.122:6379> get key2
"java"
169.254.130.122:6379> get key1
-> Redirected to slot [9189] located at 169.254.130.10:6379
"hello redis cluster"
169.254.130.10:6379> get key20
-> Redirected to slot [905] located at 169.254.130.122:6379
"html"
169.254.130.122:6379> 
從中可以發現存時是分散式儲存,取時也是從叢集中取,測試成功