Redis Cluster客户端实现

1、使用最频繁的 Java客户端Jedis最近添加了对Redis Cluster的支持,请参阅项目README中的Jedis Cluster部分。

2、redis-rb-cluster是我(@antirez)编写的Ruby实现,可作为其他语言的参考。它是原始redis-rb的简单包装,实现了最小语义以有效地与集群通信。

3、redis-cli从-c交换机启动时,该实用程序将实现基本的群集支持。



redis-cli

下面我们使用redis-cli来进行集群的交互

使用客户端连接任意一个节点,使用-c表示以集群的方式登录,-p指定端口。使用exit退出客户端

redis-cli -c -p 7000

给redis设值,可以看到是分配到第6257个槽上,实例是7001实例

127.0.0.1:7000> set msg hello
-> Redirected to slot [6257] located at 127.0.0.1:7001
OK
127.0.0.1:7001>

查询集群状态

进入客户端后可以使用cluster info查询集群的状态

[root@localhost bin]# redis-cli -c -p 7000
127.0.0.1:7000> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:243
cluster_stats_messages_pong_sent:235
cluster_stats_messages_sent:478
cluster_stats_messages_ping_received:230
cluster_stats_messages_pong_received:243
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:478

说明:
cluster_state: ok状态表示集群可以正常接受查询请求。fail 状态表示,至少有一个哈希槽没有被绑定(说明有哈希槽没有被绑定到任意一个节点),或者在错误的状态(节点可以提供服务但是带有FAIL 标记),或者该节点无法联系到多数master节点。.

cluster_slots_assigned: 已分配到集群节点的哈希槽数量(不是没有被绑定的数量)。16384个哈希槽全部被分配到集群节点是集群正常运行的必要条件.

cluster_slots_ok: 哈希槽状态不是FAIL 和 PFAIL 的数量.

cluster_slots_pfail: 哈希槽状态是 PFAIL的数量。只要哈希槽状态没有被升级到FAIL状态,这些哈希槽仍然可以被正常处理。PFAIL状态表示我们当前不能和节点进行交互,但这种状态只是临时的错误状态。

cluster_slots_fail: 哈希槽状态是FAIL的数量。如果值不是0,那么集群节点将无法提供查询服务,除非cluster-require-full-coverage被设置为no .

cluster_known_nodes: 集群中节点数量,包括处于握手状态还没有成为集群正式成员的节点.

cluster_size: 至少包含一个哈希槽且能够提供服务的master节点数量.

cluster_current_epoch: 集群本地Current Epoch变量的值。这个值在节点故障转移过程时有用,它总是递增和唯一的。

cluster_my_epoch: 当前正在使用的节点的Config Epoch值. 这个是关联在本节点的版本值.

cluster_stats_messages_sent: 通过node-to-node二进制总线发送的消息数量.

cluster_stats_messages_received: 通过node-to-node二进制总线接收的消息数量.



集群的节点信息
使用cluster nodes可以查看集群的节点信息

127.0.0.1:7000> cluster nodes
0f972c205a469c25aad28790dfdc43989b5dcca3 127.0.0.1:7003@17003 slave 4e0062198602ae83f8981b1da12b37017ac7d1d0 0 1592989019686 4 connected
b6b367d00e42026e0edc0e7725695a1dddc385ed 127.0.0.1:7000@17000 myself,master - 0 1592989017000 1 connected 0-5460
4e0062198602ae83f8981b1da12b37017ac7d1d0 127.0.0.1:7001@17001 master - 0 1592989020693 2 connected 5461-10922
9195e10fb094bf4080b369bbe504dce8e29a3c52 127.0.0.1:7005@17005 slave b6b367d00e42026e0edc0e7725695a1dddc385ed 0 1592989020000 6 connected
61258728f35a1e91780aaed910240c9315c6a752 127.0.0.1:7004@17004 slave 163853328cae159d579405c3db5a769600e5c529 0 1592989020000 5 connected
163853328cae159d579405c3db5a769600e5c529 127.0.0.1:7002@17002 master - 0 1592989019000 3 connected 10923-16383

每行的组成结构如下:

ip:port …
每项的含义如下:

id: 节点ID,是一个40字节的随机字符串,这个值在节点启动的时候创建,并且永远不会改变(除非使用CLUSTER RESET HARD命令)。

ip:port: 客户端与节点通信使用的地址.

flags: 逗号分割的标记位,可能的值有: myself, master, slave, fail?, fail, handshake, noaddr, noflags

master: 如果节点是slave,并且已知master节点,则这里列出master节点ID,否则的话这里列出”-“。

ping-sent: 最近一次发送ping的时间,这个时间是一个unix毫秒时间戳,0代表没有发送过.

pong-recv: 最近一次收到pong的时间,使用unix时间戳表示.

config-epoch: 节点的epoch值(or of the current master if the node is a slave)。每当节点发生失败切换时,都会创建一个新的,独特的,递增的epoch。如果多个节点竞争同一个哈希槽时,epoch值更高的节点会抢夺到。

link-state: node-to-node集群总线使用的链接的状态,我们使用这个链接与集群中其他节点进行通信.值可以是 connected 和 disconnected.

slot: 哈希槽值或者一个哈希槽范围. 从第9个参数开始,后面最多可能有16384个 数(limit never reached)。代表当前节点可以提供服务的所有哈希槽值。如果只是一个值,那就是只有一个槽会被使用。如果是一个范围,这个值表示为起始槽-结束槽,节点将处理包括起始槽和结束槽在内的所有哈希槽。

各flags的含义
myself: 当前连接的节点.
master: 节点是master.
slave: 节点是slave.
fail?: 节点处于PFAIL 状态。 当前节点无法联系,但逻辑上是可达的 (非 FAIL 状态).
fail: 节点处于FAIL 状态. 大部分节点都无法与其取得联系将会将改节点由 PFAIL 状态升级至FAIL状态。
handshake: 还未取得信任的节点,当前正在与其进行握手.
noaddr: 没有地址的节点(No address known for this node).
noflags: 连个标记都没有(No flags at all).



redis-cli --cluster help

redis-cli --cluster help
Cluster Manager Commands:
  create         host1:port1 ... hostN:portN   #创建集群
                 --cluster-replicas <arg>      #从节点个数
  check          host:port                     #检查集群
                 --cluster-search-multiple-owners #检查是否有槽同时被分配给了多个节点
  info           host:port                     #查看集群状态
  fix            host:port                     #修复集群
                 --cluster-search-multiple-owners #修复槽的重复分配问题
  reshard        host:port                     #指定集群的任意一节点进行迁移slot,重新分slots
                 --cluster-from <arg>          #需要从哪些源节点上迁移slot,可从多个源节点完成迁移,以逗号隔开,传递的是节点的node id,还可以直接传递--from all,这样源节点就是集群的所有节点,不传递该参数的话,则会在迁移过程中提示用户输入
                 --cluster-to <arg>            #slot需要迁移的目的节点的node id,目的节点只能填写一个,不传递该参数的话,则会在迁移过程中提示用户输入
                 --cluster-slots <arg>         #需要迁移的slot数量,不传递该参数的话,则会在迁移过程中提示用户输入。
                 --cluster-yes                 #指定迁移时的确认输入
                 --cluster-timeout <arg>       #设置migrate命令的超时时间
                 --cluster-pipeline <arg>      #定义cluster getkeysinslot命令一次取出的key数量,不传的话使用默认值为10
                 --cluster-replace             #是否直接replace到目标节点
  rebalance      host:port                                      #指定集群的任意一节点进行平衡集群节点slot数量 
                 --cluster-weight <node1=w1...nodeN=wN>         #指定集群节点的权重
                 --cluster-use-empty-masters                    #设置可以让没有分配slot的主节点参与,默认不允许
                 --cluster-timeout <arg>                        #设置migrate命令的超时时间
                 --cluster-simulate                             #模拟rebalance操作,不会真正执行迁移操作
                 --cluster-pipeline <arg>                       #定义cluster getkeysinslot命令一次取出的key数量,默认值为10
                 --cluster-threshold <arg>                      #迁移的slot阈值超过threshold,执行rebalance操作
                 --cluster-replace                              #是否直接replace到目标节点
  add-node       new_host:new_port existing_host:existing_port  #添加节点,把新节点加入到指定的集群,默认添加主节点
                 --cluster-slave                                #新节点作为从节点,默认随机一个主节点
                 --cluster-master-id <arg>                      #给新节点指定主节点
  del-node       host:port node_id                              #删除给定的一个节点,成功后关闭该节点服务
  call           host:port command arg arg .. arg               #在集群的所有节点执行相关命令
  set-timeout    host:port milliseconds                         #设置cluster-node-timeout
  import         host:port                                      #将外部redis数据导入集群
                 --cluster-from <arg>                           #将指定实例的数据导入到集群
                 --cluster-copy                                 #migrate时指定copy
                 --cluster-replace                              #migrate时指定replace
  help

① 创建集群主节点

redis-cli --cluster create 192.168.163.132:6379 192.168.163.132:6380 192.168.163.132:6381

② 创建集群主从节点

/redis-cli --cluster create 192.168.163.132:6379 192.168.163.132:6380 192.168.163.132:6381 192.168.163.132:6382 192.168.163.132:6383 192.168.163.132:6384 --cluster-replicas 1

说明:–cluster-replicas 参数为数字,1表示每个主节点需要1个从节点。

通过该方式创建的带有从节点的机器不能够自己手动指定主节点,所以如果需要指定的话,需要自己手动指定,先使用①或③创建好主节点后,再通过④来处理。

③ 添加集群主节点

redis-cli --cluster add-node 192.168.91.128:7006 192.168.91.128.1:7000

我使用add-node命令将新节点的地址指定为第一个参数,并将集群中随机存在的节点的地址指定为第二个参数。

进入一个redis交互窗口,输入 cluster nodes
查看集群情况,是否有新增节点

④ 添加集群从节点

可以通过两种方式添加集群从节点。

第一种:不指定主节点

redis-cli --cluster add-node 192.168.91.128:7006 192.168.91.128:7000 --cluster-slave

请注意,此处的命令行与我们用于添加新主服务器的命令行完全相同(只在后面说明添加的节点为从节点),因此我们并未指定要向其添加副本的主服务器。在这种情况下,发生的事情是redis-cli将新节点添加为副本较少的主节点中的随机主节点的副本。

第二种:指定主节点

redis-cli --cluster add-node 192.168.91.128:7006 192.168.91.128:7000 --cluster-slave --cluster-master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e

说明:把7006 节点加入到7000 节点的集群中,并且当做node_id为 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e的从节点。如果不指定 --cluster-master-id 会随机分配到任意一个主节点。

这样,我们将新副本分配给特定的主节点。



⑤ 删除节点

要删除从节点,只需使用del-noderedis-cli命令:

redis-cli --cluster del-node 192.168.91.128:7000 `<node-id>`

第一个参数只是集群中的一个随机节点,第二个参数是您要删除的节点的ID。

您也可以用相同的方法删除主节点,但是要删除主节点,它必须为空。如果主节点不为空,则需要先将数据从其重新分片到所有其他主节点。

说明:指定IP、端口和node_id 来删除一个节点,从节点可以直接删除,主节点不能直接删除,删除之后,该节点会被shutdown。

注意:当被删除掉的节点重新起来之后不能自动加入集群,但其和主的复制还是正常的,也可以通过该节点看到集群信息(通过其他正常节点已经看不到该被del-node节点的信息)。

如果想要再次加入集群,则需要先在该节点执行cluster reset,再用add-node进行添加,进行增量同步复制。



⑥ 检查集群

redis-cli --cluster check 192.168.163.132:6384 
或者
redis-cli --cluster check 192.168.163.132:6384 --cluster-search-multiple-owners

说明:任意连接一个集群节点,进行集群状态检查

⑦ 集群信息查看

redis-cli --cluster info 192.168.163.132:6384

说明:检查key、slots、从节点个数的分配情况

⑧ 修复集群

redis-cli --cluster fix 192.168.163.132:6384 --cluster-search-multiple-owners

说明:修复集群和槽的重复分配问题

⑨ 设置集群的超时时间

redis-cli --cluster set-timeout 192.168.163.132:6382 10000

说明:连接到集群的任意一节点来设置集群的超时时间参数cluster-node-timeout



分片操作

重新分片基本上意味着将哈希槽从一组节点移动到另一组节点,并且像群集创建一样,它是使用redis-cli实用程序完成的。

要开始重新分片,只需键入:

redis-cli --cluster reshard 192.168.91.128:7000

您只需要指定一个节点,redis-cli将自动找到其他节点。

然后会提示你您想要移动多少个插槽(从1到16384)?输入你想移动的插槽数量即可

How many slots do you want to move (from 1 to 16384)?

输入数量后,会提示你输入接收节点的ID

What is the receiving node ID?

然后,你将被询问要从哪些节点获取这些密钥。我只是键入all以从所有其他主节点获取一些哈希槽。

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

最后,还会让你确定是否要继续重新分片,输入yes即可

Do you want to proceed with the proposed reshard plan (yes/no)? yes

开始分片,你可以看到哈希槽移动的信息

Moving slot 10969 from 192.168.91.128:7002 to 192.168.91.128:7000: 
Moving slot 10970 from 192.168.91.128:7002 to 192.168.91.128:7000:

还有一种重新分片的方式,就是编写重新分片操作脚本

重新分片可以自动执行,而无需以交互方式手动输入参数。可以使用如下命令行来实现:

redis-cli reshard <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes

from为移动的哈希槽原来所在的节点ID,to为哈希槽移动后的节点ID

例:

redis-cli reshard 192.168.91.128:7000--cluster-from b6b367d00e42026e0edc0e7725695a1dddc385ed --cluster-to 4e0062198602ae83f8981b1da12b37017ac7d1d0 --cluster-slots 100 --cluster-yes

平衡集群中各个节点的slot数量

redis-cli --cluster rebalance 192.168.91.128:7000

只需要输入一个集群中的节点即可

出现以下信息,表示不需要调整,各个节点的哈希槽都在2%的差值

*** No rebalancing needed! All nodes are within the 2.00% threshold.