1. 程式人生 > >三分鐘快速搭建分散式高可用的Redis叢集

三分鐘快速搭建分散式高可用的Redis叢集

![](https://img2020.cnblogs.com/blog/145687/202005/145687-20200512085745093-1337803618.jpg) 這裡的Redis叢集指的是Redis Cluster,它是Redis在3.0版本正式推出的專用叢集方案,有效地解決了Redis分散式方面的需求。當單機記憶體、併發、流量等遇到瓶頸的時候,可以採用這種Redis Cluster方案進行解決。 ### 分割槽規則 Redis Cluster採用虛擬槽(slot)進行資料分割槽,即使用分散度良好的雜湊函式把所有鍵對映到一個固定範圍的整數集合裡,這裡的整數就是槽(slot)。Redis Cluster槽的範圍是0~16383,計算公式:slot=CRC16(key) & 16383。 > **白嫖小貼士**:CRC16是一種高質量的雜湊演算法,可以使每個槽所對映的鍵通常比較均勻。 當叢集中有3個節點時,每個節點平均大概負責5461個槽以及槽所對映的鍵值資料。這樣一來,可以解耦資料與節點之間的關係,簡化節點擴容和縮容的難度。節點自身維護槽的對映關係,不需要客戶端或代理服務維護分割槽資訊。 不過,Redis Cluster相對於單機還是存在一些限制的,比如: 1. 批量操作鍵支援有限,僅支援具有相同槽的鍵進行批量操作。 2. 事務操作鍵支援有限,僅支援在同一個節點上多個鍵的事務操作。 3. 不支援多個數據空間。單機Redis可以支援16個數據庫,而Cluster模式下只能使用一個數據庫空間。 扯了這麼多Redis Cluster的分割槽規則,下面我們開始步入正題。 歡迎關注微信公眾號:萬貓學社
,每週一分享Java技術乾貨。 ### 手動搭建 把Redis Cluster搭建起來總共幾步?答:三步!第一步把冰箱門開啟。第二步把大象關進去。第三步把冰箱門帶上。不好意思,段子暴露年齡了。叢集搭建需要以下三個步驟: 1. 準備節點。 2. 節點握手。 3. 分配槽。 Redis Cluster由多個節點組成,節點數量至少有6個才能組成一個完整高可用的叢集,其中有3個主節點和3個從節點,我們就以此為例搭建一個Redis Cluster。 #### 準備節點 首先,為6個節點(同一臺機器上的6380、6381、6382、6383、6384、6385埠)分別建立配置檔案,以6380埠的節點為例: ``` # 節點埠 port 6380 #日誌檔案 logfile "log/redis-6380.log" # 開啟叢集模式 cluster-enabled yes # 叢集配置檔案 cluster-config-file "data/nodes-6380.conf" ``` 保持檔名為redis-6380.conf,其他節點的配置檔案替換成各自的埠。準備好配置檔案後啟動所有節點,命令如下: ``` src/redis-server conf/redis-6380.conf & src/redis-server conf/redis-6381.conf & src/redis-server conf/redis-6382.conf & src/redis-server conf/redis-6383.conf & src/redis-server conf/redis-6384.conf & src/redis-server conf/redis-6385.conf & ``` 檢測日誌是否正確,以下是6380埠的節點的日誌: ``` # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo # Redis version=4.0.14, bits=64, commit=00000000, modified=0, pid=3031, just started # Configuration loaded * No cluster configuration found, I'm df1ac987f47dea35f1d0a83c3b405f0ef86892ab * Running mode=cluster, port=6380. ``` 6380埠的節點啟動成功,第一次啟動時如果沒有叢集配置檔案,Redis會自動建立一個。6380埠的節點建立的叢集配置檔案如下: ``` df1ac987f47dea35f1d0a83c3b405f0ef86892ab :0@0 myself,master - 0 0 0 connected vars currentEpoch 0 lastVoteEpoch 0 ``` 叢集檔案中記錄的叢集的狀態,這裡最重要的是節點ID,它是一個40位的16進位制字串,用於唯一標識叢集中的這個節點。同樣,也可以通過cluster nodes命令檢視叢集節點狀態。比如在6380埠的節點上執行命令: ``` 127.0.0.1:6380>
cluster nodes df1ac987f47dea35f1d0a83c3b405f0ef86892ab :6380@16380 myself,master - 0 0 0 connected ``` 目前,我們已經成功啟動了6個節點,但是它們只能識別自己的節點資訊,互相之間並不認識。下面我們通過節點握手讓這6個節點互相之間建立聯絡從而組成一個叢集。 歡迎關注微信公眾號:萬貓學社,每週一分享Java技術乾貨。 #### 節點握手 節點握手是一些執行在叢集模式下的節點通過Gossip協議互相通訊,達到感知彼此的過程。 > **白嫖小貼士**:Gossip協議是基於流行病傳播方式的節點或者程序之間資訊交換的協議,在分散式系統中被廣泛使用。 節點握手通過客戶端執行`cluster meet`命令實現,它是一個非同步命令,執行之後立刻返回,在Redis內部非同步發起與目標節點的握手通訊,該命令的語法如下: ``` cluster meet 目標節點IP 目標節點埠 ``` 把6個節點加到一個叢集中: ``` 127.0.0.1:6380>
cluster meet 127.0.0.1 6381 OK 127.0.0.1:6380> cluster meet 127.0.0.1 6382 OK 127.0.0.1:6380> cluster meet 127.0.0.1 6383 OK 127.0.0.1:6380> cluster meet 127.0.0.1 6384 OK 127.0.0.1:6380> cluster meet 127.0.0.1 6385 OK ``` 只需要在叢集中任意節點上執行`cluster meet`命令加入新的節點,握手狀態會通過訊息在叢集中傳播,其他節點也會自動發現新節點並與之發起握手流程。 我們再執行一下`cluster nodes`命令,檢查一下6個節點是否已經組成叢集: ``` 127.0.0.1:6380> cluster nodes 1e1f45677d7b9b0130d03193f0bcec34578ac47d 127.0.0.1:6385@16385 master - 0 1586617919021 5 connected df1ac987f47dea35f1d0a83c3b405f0ef86892ab 127.0.0.1:6380@16380 myself,master - 0 1586617916000 2 connected 5846b66ebe4fb4a5dcfd035652cc471f7e412752 127.0.0.1:6381@16381 master - 0 1586617917005 1 connected a435cf98c3444b0b110a224401e397a107c453ef 127.0.0.1:6384@16384 master - 0 1586617914988 4 connected 71e0e9e9a6f0c7c85dbe0d396846a9072625c5e8 127.0.0.1:6383@16383 master - 0 1586617918013 3 connected e25590603c7a254cce43aa8437861c5c425d753d 127.0.0.1:6382@16382 master - 0 1586617916000 0 connected ``` 可以看到,6個節點都在叢集中了。不過,此時因為還沒有為叢集中的節點分配槽,叢集還處於下線狀態,所有的資料讀寫都是被禁止的。比如: ``` 127.0.0.1:6380> set onemore study (error) CLUSTERDOWN Hash slot not served ``` 接下來,我們為叢集中的節點分配槽。 #### 分配槽 我們把6380、6382、6384埠的節點作為主節點,負責處理槽和相關資料;6381、6383、6385埠的節點分別作為從節點,負責故障轉移。先把16384個槽平均分配給6380、6382、6384埠的節點,為節點分配槽是通過`cluster addslots`命令實現: ``` # ./redis-cli -h 127.0.0.1 -p 6380 cluster addslots {0..5461} OK # ./redis-cli -h 127.0.0.1 -p 6382 cluster addslots {5462..10922} OK # ./redis-cli -h 127.0.0.1 -p 6384 cluster addslots {10923..16383} OK ``` 我們再執行一下`cluster nodes`命令,檢查一下槽是否已經分配: ``` 127.0.0.1:6380> cluster nodes 1e1f45677d7b9b0130d03193f0bcec34578ac47d 127.0.0.1:6385@16385 master - 0 1586619468000 5 connected df1ac987f47dea35f1d0a83c3b405f0ef86892ab 127.0.0.1:6380@16380 myself,master - 0 1586619464000 2 connected 0-5461 5846b66ebe4fb4a5dcfd035652cc471f7e412752 127.0.0.1:6381@16381 master - 0 1586619467000 1 connected a435cf98c3444b0b110a224401e397a107c453ef 127.0.0.1:6384@16384 master - 0 1586619467000 4 connected 10923-16383 71e0e9e9a6f0c7c85dbe0d396846a9072625c5e8 127.0.0.1:6383@16383 master - 0 1586619467348 3 connected e25590603c7a254cce43aa8437861c5c425d753d 127.0.0.1:6382@16382 master - 0 1586619468355 0 connected 5462-10922 ``` 再使用`cluster replicate`命令把一個節點變成從節點.,這個命令必須在從節點上執行,它的語法是: ``` cluster replicate 主節點ID ``` 把6381、6383、6385埠的節點變成對應6380、6382、6384埠的節點的從節點: ``` # ./redis-cli -h 127.0.0.1 -p 6381 127.0.0.1:6381> cluster replicate df1ac987f47dea35f1d0a83c3b405f0ef86892ab OK 127.0.0.1:6381> exit # ./redis-cli -h 127.0.0.1 -p 6383 127.0.0.1:6383> cluster replicate e25590603c7a254cce43aa8437861c5c425d753d OK 127.0.0.1:6383> exit # ./redis-cli -h 127.0.0.1 -p 6385 127.0.0.1:6385> cluster replicate a435cf98c3444b0b110a224401e397a107c453ef OK 127.0.0.1:6385> exit ``` 我們再執行一下`cluster nodes`命令,檢查一下叢集狀態和主從關係: ``` 127.0.0.1:6380> cluster nodes df1ac987f47dea35f1d0a83c3b405f0ef86892ab 127.0.0.1:6380@16380 myself,master - 0 1586620148000 2 connected 0-5461 5846b66ebe4fb4a5dcfd035652cc471f7e412752 127.0.0.1:6381@16381 slave df1ac987f47dea35f1d0a83c3b405f0ef86892ab 0 1586620150000 2 connected e25590603c7a254cce43aa8437861c5c425d753d 127.0.0.1:6382@16382 master - 0 1586620151000 0 connected 5462-10922 71e0e9e9a6f0c7c85dbe0d396846a9072625c5e8 127.0.0.1:6383@16383 slave e25590603c7a254cce43aa8437861c5c425d753d 0 1586620152220 3 connected a435cf98c3444b0b110a224401e397a107c453ef 127.0.0.1:6384@16384 master - 0 1586620150000 4 connected 10923-16383 1e1f45677d7b9b0130d03193f0bcec34578ac47d 127.0.0.1:6385@16385 slave a435cf98c3444b0b110a224401e397a107c453ef 0 1586620149000 5 connected ``` 自此,RedisCluster已經手動搭建完成。手動搭建可以理解叢集建立的流程和細節,不過大家也會發現手動搭建有很多步驟,當叢集的節點比較多的時候,肯定會讓人頭大。所以Redis官方提供了redis-trib.rb工具,可以讓我們快速地搭建叢集。 ### 自動搭建 redis-trib.rb是使用Ruby開發的Redis Cluster的管理工具,不需要額外下載,預設位於原始碼包的src目錄下,但因為該工具是用Ruby開發的,所以需要準備相關的依賴環境。 歡迎關注微信公眾號:萬貓學社,每週一分享Java技術乾貨。 #### 環境準備 安裝Ruby: ``` yum -y install zlib-devel wget https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.1.tar.gz tar xvf ruby-2.5.1.tar.gz cd ruby-2.5.1/ ./configure -prefix=/usr/local/ruby make make install cd /usr/local/ruby/ cp bin/ruby /usr/local/bin cp bin/gem /usr/local/bin ``` 安裝rubygem redis依賴: ``` wget http://rubygems.org/downloads/redis-3.3.0.gem gem install -l redis-3.3.0.gem ``` 安裝redis-trib.rb: ``` cp src/redis-trib.rb /usr/local/bin ``` 執行redis-trib.rb命令確認一下環境是否準備正確: ``` # redis-trib.rb help Usage: redis-trib create host1:port1 ... hostN:portN --replicas check host:port info host:port fix host:port --timeout reshard host:port --from ...此處省略一萬個字... ``` #### 搭建叢集 像前面的內容講的,準備好節點配置並啟動: ``` src/redis-server conf/redis-7380.conf & src/redis-server conf/redis-7381.conf & src/redis-server conf/redis-7382.conf & src/redis-server conf/redis-7383.conf & src/redis-server conf/redis-7384.conf & src/redis-server conf/redis-7385.conf & ``` 使用`redis-trib.rb create`命令完成節點握手和槽分配的工作,命令如下: ``` redis-trib.rb create --replicas 1 127.0.0.1:7380 127.0.0.1:7382 127.0.0.1:7384 127.0.0.1:7381 127.0.0.1:7383 127.0.0.1:7385 ``` 其中`--replicas `引數用來指定叢集中每個主節點有幾個從節點,這裡設定的是1。命令執行後,會首先給出主從節點的分配計劃: ``` >>> Creating cluster >>> Performing hash slots allocation on 6 nodes... Using 3 masters: 127.0.0.1:7380 127.0.0.1:7382 127.0.0.1:7384 Adding replica 127.0.0.1:7383 to 127.0.0.1:7380 Adding replica 127.0.0.1:7385 to 127.0.0.1:7382 Adding replica 127.0.0.1:7381 to 127.0.0.1:7384 >>> Trying to optimize slaves allocation for anti-affinity [WARNING] Some slaves are in the same host as their master M: c25675d021c377c91f860986025e3779d89ede79 127.0.0.1:7380 slots:0-5460 (5461 slots) master M: 58980a81b49de31383802d7d21d6782881678922 127.0.0.1:7382 slots:5461-10922 (5462 slots) master M: 3f00a37d2c7a5ea40671c8f2934f66d059157a4a 127.0.0.1:7384 slots:10923-16383 (5461 slots) master S: 6f7dd93973a8332305831e6b7b5e2c54c15b3b51 127.0.0.1:7381 replicates 3f00a37d2c7a5ea40671c8f2934f66d059157a4a S: 03e01f82a935ed7f977af092e6a9cb71057df68a 127.0.0.1:7383 replicates c25675d021c377c91f860986025e3779d89ede79 S: 2cf3883e974a709b7070d6c4d7c528d9fa813358 127.0.0.1:7385 replicates 58980a81b49de31383802d7d21d6782881678922 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.... >>> Performing Cluster Check (using node 127.0.0.1:7380) M: c25675d021c377c91f860986025e3779d89ede79 127.0.0.1:7380 slots:0-5460 (5461 slots) master 1 additional replica(s) M: 58980a81b49de31383802d7d21d6782881678922 127.0.0.1:7382 slots:5461-10922 (5462 slots) master 1 additional replica(s) S: 2cf3883e974a709b7070d6c4d7c528d9fa813358 127.0.0.1:7385 slots: (0 slots) slave replicates 58980a81b49de31383802d7d21d6782881678922 S: 03e01f82a935ed7f977af092e6a9cb71057df68a 127.0.0.1:7383 slots: (0 slots) slave replicates c25675d021c377c91f860986025e3779d89ede79 S: 6f7dd93973a8332305831e6b7b5e2c54c15b3b51 127.0.0.1:7381 slots: (0 slots) slave replicates 3f00a37d2c7a5ea40671c8f2934f66d059157a4a M: 3f00a37d2c7a5ea40671c8f2934f66d059157a4a 127.0.0.1:7384 slots:10923-16383 (5461 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. ``` 叢集建立完成後,還可以使用`redis-trib.rb check`命令檢查叢集是否建立成功,具體命令如下: ``` # redis-trib.rb check 127.0.0.1:7380 >>> Performing Cluster Check (using node 127.0.0.1:7380) M: c25675d021c377c91f860986025e3779d89ede79 127.0.0.1:7380 slots:0-5460 (5461 slots) master 1 additional replica(s) M: 58980a81b49de31383802d7d21d6782881678922 127.0.0.1:7382 slots:5461-10922 (5462 slots) master 1 additional replica(s) S: 2cf3883e974a709b7070d6c4d7c528d9fa813358 127.0.0.1:7385 slots: (0 slots) slave replicates 58980a81b49de31383802d7d21d6782881678922 S: 03e01f82a935ed7f977af092e6a9cb71057df68a 127.0.0.1:7383 slots: (0 slots) slave replicates c25675d021c377c91f860986025e3779d89ede79 S: 6f7dd93973a8332305831e6b7b5e2c54c15b3b51 127.0.0.1:7381 slots: (0 slots) slave replicates 3f00a37d2c7a5ea40671c8f2934f66d059157a4a M: 3f00a37d2c7a5ea40671c8f2934f66d059157a4a 127.0.0.1:7384 slots:10923-16383 (5461 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. ``` 可以看到,所有的槽都已分配到節點上,大功告成!

微信公眾號:萬貓學社

微信掃描二維碼

獲得更多Java技術乾貨