IT|資料庫|Key-Value|Redis Cluster 集群伺服器設定


Redis 集群提供了以下兩個好處:
將數據自動切分(split)到多個節點的能力。
當集群中的一部分節點失效或者無法進行通訊時, 仍然可以繼續處理命令請求的能力。



Redis 架構

架構細節:
(1)所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬.
(2)節點的fail是通過集群中超過半數的節點檢測失效時才生效.
(3)客戶端與redis節點直連,不需要中間proxy.客戶端不需要連接集群所有節點,連接集群中任何一個可用節點即可
(4)redis-cluster把所有的物理節點映射到[0-16383]slot,cluster 負責維護node<->slot<->value



Redis 架構圖


Redis Cluster 搭建與使用

要讓集群正常工作至少需要3個主節點,在這裡我們要創建6redis節點,其中三個為主節點,三個為從節點,對應的redis節點的ip和端口對應關係如下(為了簡單演示都在同一台機器上面)。
127.0.0.1:7000
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


[安裝 redis]

創建存放多個實例的目錄
mkdir /home/pi/data/cluster -p
cd /home/pi/data/cluster
mkdir 7000 7001 7002 7003 7004 7005

修改配置文件
樹莓派
cp /etc/redis.conf /home/pi/data/cluster/7000/

Linux
cp /home/pi/redis-4.0.2/redis.conf /home/pi/data/cluster/7000/

修改以下選項(修改完成後,把修改完成的redis.conf複製到7001-7005目錄下,並且端口修改成和文件夾對應):

port 7000
daemonize yes —> 即默認以後台程序方式運行
cluster-enabled yes  —> 文件中的 cluster-enabled 選項用於開實例的集群模式
cluster-config-file nodes.conf —> cluster-conf-file 選項則設定了保存節點配置文件的路徑, 默認值為nodes.conf
cluster-node-timeout 5000
appendonly yes —> 開啟 AOF 模式

複製 redis.conf 到以下目錄並改寫 port(7001、7002、7003、7004、7005 )


cp /home/pi/data/cluster/7000/redis.conf /home/pi/data/cluster/7001/
cp /home/pi/data/cluster/7000/redis.conf /home/pi/data/cluster/7002/
cp /home/pi/data/cluster/7000/redis.conf /home/pi/data/cluster/7003/
cp /home/pi/data/cluster/7000/redis.conf /home/pi/data/cluster/7004/
cp /home/pi/data/cluster/7000/redis.conf /home/pi/data/cluster/7005/

按上述步驟重複修改 port 屬性

分別啟動 6 個 redis 實例

樹莓派
#0
cd /home/pi/data/cluster/7000
redis-server redis.conf
#1
cd /home/pi/data/cluster/7001
redis-server redis.conf
#2
cd /home/pi/data/cluster/7002
redis-server redis.conf
#3
cd /home/pi/data/cluster/7003
redis-server redis.conf
#4
cd /home/pi/data/cluster/7004
redis-server redis.conf
#5
cd /home/pi/data/cluster/7005
redis-server redis.conf

查看進程是否存在
ps -ef | grep redis

檢查是否端口為進程
netstat -npl

[執行命令創建 cluster]

安裝ruby相關的環境,否則創建集群可能會失敗
sudo apt-get install rubygems

安裝運行需要依賴的ruby的包 gem-redis
必須與 redis 安裝版本一致 
cd ~
gem install -l redis-4.0.1.gem

異常處理


gem-redis 必需搭配 Ruby 2.2 以上版本

複製集群管理程序到/usr/local/bin
cd /home/pi/Downloads/redis-4.0.1
sudo cp /home/pi/Downloads/redis-4.0.1/src/redis-trib.rb /usr/local/bin/redis-trib

創建集群
執行前先確定 aofrdbnodes.conf 個別資料夾已先刪除
192.168.43.176
redis-trib create --replicas 1 192.168.43.176:7000 192.168.43.176:7001 192.168.43.176:7002 192.168.43.176:7003 192.168.43.176:7004 192.168.43.176:7005

127.0.0.1
redis-trib create --replicas 1 127.0.0.1:7000 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

異常處理

pi@MyPi1:/usr/local/bin $ redis-trib create --replicas 1 127.0.0.1:7000 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
>>> Creating cluster

[ERR] Node 127.0.0.1:7000 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.

解決辦法

將每個節點下aofrdbnodes.conf本地備份文件刪除 (7000、7001、7002、7003、7004、7005)
之後再執行此腳本,成功執行

命令的意義如下:
* 給定 redis-trib.rb 程序的命令是 create 這表示我們希望創建一個新的集群。
* 選項 --replicas 1 表示我們希望為集群中的每個主節點創建一個從節點。
* 之後跟著的其他參數則是實例的地址列表, 我們希望程序使用這些地址所指示的實例來創建新集群。
簡單來說, 以上命令的意思就是讓 redis-trib 程序創建一個包含三個主節點和三個從節點的集群。
接著, redis-trib 會打印出一份預想中的配置給你看, 如果你覺得沒問題的話, 就可以輸入 yes redis-trib 就會將這份配置應用到集群當中:


輸入 yes 並按確認之後, 集群就會將配置應用到各個節點, 並連接起(join)各個節點各個節點開始互相通訊

一切正常後輸出以下信息
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

測試 Redis 集群比較簡單的辦法就是使用 redis-rb-cluster 或者 redis-cli 接下來我們將使用 redis-cli 為例來進行演示:
redis-cli -c -p 7001
set name kevin
get name


可以查詢相關指令透過以下命令:可以看見有add-node,不用想了,肯定是添加節點。那麼del-node就是刪除節點。還有check肯定就是檢查狀態了。
[root@redis-server ~]# redis-trib help
Usage: redis-trib <command> <options> <arguments ...>

  set-timeout     host:port milliseconds
  add-node        new_host:new_port existing_host:existing_port
                  --master-id <arg>
                  --slave
  fix             host:port
  help            (show this help)
  del-node        host:port node_id
  import          host:port
                  --from <arg>
  check           host:port
  call            host:port command arg arg .. arg
  create          host1:port1 ... hostN:portN
                  --replicas <arg>
  reshard         host:port
                  --yes
                  --to <arg>
                  --from <arg>
                  --slots <arg>

For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.
[root@redis-server ~]#

可以看到7000-7002master7003-7005slave
redis-cli -h 192.168.43.176 -p 7000 cluster nodes


[故障轉移測試]



可以看見7001是正常的,並且獲取到了keyvalue,現在kill7000實例,再進行查詢。
[root@redis-server ~]# ps -ef | grep 7000
root      4168     1  0 11:49 ?        00:00:03 redis-server *:7000 [cluster]
root      4385  4361  0 12:39 pts/3    00:00:00 grep 7000
[root@redis-server ~]# kill 4168
[root@redis-server ~]# ps -ef | grep 7000
root      4387  4361  0 12:39 pts/3    00:00:00 grep 7000
[root@redis-server ~]# redis-cli -c -p 7001
127.0.0.1:7001> get name
"yayun"
127.0.0.1:7001>

可以正常獲取到value,現在看看狀態。
[root@redis-server ~]# redis-cli -c -p 7001 cluster nodes
2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001 myself,master - 0 0 2 connected 5461-10922
0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002 master - 0 1428295271619 3 connected 10923-16383
37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003 master - 0 1428295270603 7 connected 0-5460
e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004 slave 2d03b862083ee1b1785dba5db2987739cf3a80eb 0 1428295272642 5 connected
2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000 master,fail - 1428295159553 1428295157205 1 disconnected
9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005 slave 0456869a2c2359c3e06e065a09de86df2e3135ac 0 1428295269587 6 connected
[root@redis-server ~]#
原來的7000端口實例已經顯示fail,原來的7003slave,現在自動提升為master
關於更多的在線添加節點,刪除節點,以及對集群進行重新分片請參考官方文檔。


Java 集群測試

使用Java客戶端對Redis進行操作
package com.agile.example.redis;

import java.io.IOException;
import java.util.HashSet;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;

/**
 * Redis cluseter test
 *
 * @author Kevin
 * @date 2017-11-16
 */

public class RedisClusterTest {

public static void main(String[] args) throws IOException {

HashSet<HostAndPort> nodes = new HashSet<HostAndPort>();
nodes.add(new HostAndPort("192.168.43.176", 7000));
nodes.add(new HostAndPort("192.168.43.176", 7001));
nodes.add(new HostAndPort("192.168.43.176", 7002));
nodes.add(new HostAndPort("192.168.43.176", 7003));
nodes.add(new HostAndPort("192.168.43.176", 7004));
nodes.add(new HostAndPort("192.168.43.176", 7005));

JedisCluster cluster = new JedisCluster(nodes);
cluster.set("jedisClusterKey", "hello world");
String str = cluster.get("jedisClusterKey");
System.out.println("---" + str);

cluster.close(); // 關閉連接

  }
}

留言

這個網誌中的熱門文章

IoT|硬體|樹莓派|外接麥克風及喇叭設置

成長|語文|學習-英文 持續更新!

IoT|硬體|通訊|Arduino 使用 SoftwareSerial Library 與電腦通訊