前言
Redis 系列第二十七篇,也是Cluster
集群模式第二篇。 上篇我们已经通过画图与对比的方式将Cluster
虚拟槽寻址思路、取余hash
和一致性hash
寻址的原理弄清楚了,还有不熟悉的好哥哥可以看你竟然还不知道 hash slot 这篇了解一下。这一篇的话主要是对Cluster
集群的搭建与使用,上一篇又说到分成两篇的,想想篇幅还是不要那么长,于是乎就有了一篇。
这一篇的话基本上都是一些实践性的内容,好哥哥们还是一样不要偷懒哦。有杠精好哥哥会说了,怎么哨兵模式的搭建你怎么不弄?有这么杠的好哥哥估计没有认真看图解 Redis 哨兵模式,在这一片总结的地方已经说了原因,好哥哥们别闹。
概述
在 图解 Redis 哨兵模式一文中有提到哨兵模式的一些局限性,比如说不支持主从复制、不能够支持超大数据量的存储。在 Redis 的 3.0
版本正式推出了 Cluster
作为 Redis 的分布式解决方案。当遇到单机内存、并发、流量等瓶颈时,可以采用Cluster
架构方案达到负载均衡的目的。
Cluster
非常优雅的解决了在哨兵或者主从复制两种模式下的一些问题,当然Cluster
中也存在主从复制的功能。在学习Cluster
集群模式前,我们需要把Cluster
搭建起来,整个过程分为Redis实例准备
、节点握手
、分配槽空间
。至于实例准备这个的话我们用的还是一台机器然后弄多个实例出来,下面让我们开始吧。
Redis 实例准备
Cluster
集群模式一般由多个主节点和多个从节点组成,节点数量至少为 6 个才能保证组成完整高可用的集群。解释一下为什么要六个节点,如上图,整个集群环境一共三台机器,假设服务器1.1
宕掉了,这个时候集群环境还是可以继续跑的,因为在服务器1.3
上面有一台M1
的从节点S1
。假设低于三台的话,那整个集群环境就会丢失某一部分数据,因为已经没有从节点可以切换到主节点了。
搭建Cluster
集群需要每个节点都开启配置cluster-enabled yes
,然后的话所有节点的配置尽量放在统一的目录下,由于我们这边使用的是一台服务器,所以只能用名字加端口号来区分。一般划分为conf
、data
、log
三个目录,分别存放配置、数据和日志相关文件。主要配置如下:
# 节点端口
port 6379
# 开启集群模式
cluster-enabled yes
# 节点超时时间,单位毫秒
cluster-node-timeout 15000
# 集群内部配置文件
cluster-config-file "nodes-6379.conf"
其他配置和单机模式一致即可,配置文件命名规则redis-{port}.conf
,准备好配置后启动所有节点,执行以下命令:
redis-server conf/redis-6379.conf
redis-server conf/redis-6380.conf
redis-server conf/redis-6381.conf
redis-server conf/redis-6382.conf
redis-server conf/redis-6383.conf
redis-server conf/redis-6384.conf
第一次启动时如果没有集群配置文件,会自动创建一份,文件名称采用cluster-config-file
参数项控制,建议采用node-{port}.conf
格式定义,通过使用端口号区分不同节点,防止同一机器下多个节点彼此覆盖,造成集群信息异常。如果启动时存在集群配置文件,节点会使用配置文件内容初始化集群信息。
集群模式的 Redis 除了原有的配置文件之外又加了一份集群配置文件。当集群内节点信息发生变化,如添加节点、节点下线、故障转移等。节点会自动保存集群状态到配置文件中。需要注意的是,Redis 自动维护集群配置文件,不要手动修改,防止节点重启时产生集群信息错乱。
首次启动后生成的配置文件内容如下:
#cat data/nodes-6379.conf
cfb28ef1deee4e0fa78da86abe5d24566744411e 127.0.0.1:6379 myself,master - 0 0 0 connected
vars currentEpoch 0 lastVoteEpoch 0
文件内容记录了集群初始状态,这里最重要的是节点ID
,它是一个40
位16
进制字符串,用于唯一标识集群内一个节点,之后很多集群操作都要借助于节点ID
来完成。需要注意是,节点ID
不同于运行ID
(runid
)。节点ID
在集群初始化时只创建一次,节点重启时会加载集群配置文件进行重用,而 Redis 的运行ID
每次重启都会变化。执行cluster nodes
命令获取6380
集群节点状态:
127.0.0.1:6380>cluster nodes
8e41673d59c9568aa9d29fb174ce733345b3e8f1 127.0.0.1:6380 myself,master - 0 0 0 connected
由于没有将其余的几台实例连接成为一个集群,所以这里是没有节点的。
节点握手
节点握手是指一批运行在集群模式下的节点通过Gossip协议
彼此通信,达到感知对方的过程。节点握手是集群彼此通信的第一步,由客户端发起命令: cluster meet{ip}{port}
。
过程如下:
- 节点
6379
本地创建6380
节点信息对象,并发送meet
消息。 - 节点
6380
接受到meet
消息后,保存6379
节点信息并回复pong
消息。 - 之后节点
6379
和6380
彼此定期通过ping/pong
消息进行正常的节点通信。
下面分别执行meet
命令让其他节点加入到集群中:
127.0.0.1:6379>cluster meet 127.0.0.1 6381
127.0.0.1:6379>cluster meet 127.0.0.1 6382
127.0.0.1:6379>cluster meet 127.0.0.1 6383
127.0.0.1:6379>cluster meet 127.0.0.1 6384
我们只需要在集群内任意节点上执行cluster meet
命令加入新节点,握手状态会通过消息在集群内传播,这样其他节点会自动发现新节点并发起握手流程。最后执行cluster nodes
命令确认6
个节点都彼此感知并组成集群:
127.0.0.1:6379> cluster nodes
4fa7eac4080f0b667ffeab9b87841da49b84a6e4 127.0.0.1:6384 master - 0 1468073975551
5 connected
cfb28ef1deee4e0fa78da86abe5d24566744411e 127.0.0.1:6379 myself,master - 0 0 0 connected
be9485a6a729fc98c5151374bc30277e89a461d8 127.0.0.1:6383 master - 0 1468073978579
4 connected
40622f9e7adc8ebd77fca0de9edfe691cb8a74fb 127.0.0.1:6382 master - 0 1468073980598
3 connected
8e41673d59c9568aa9d29fb174ce733345b3e8f1 127.0.0.1:6380 master - 0 1468073974541
1 connected
40b8d09d44294d2e23c7c768efc8fcd153446746 127.0.0.1:6381 master - 0 1468073979589
2 connected
然后,建立握手之后集群还不能正常工作的,这个时候的集群处于下线状态,所有的数据读写都被禁止。通过如下命令可以看到:
## 设置一个key到Redis
127.0.0.1:6379> set hello redis
(error) CLUSTERDOWN The cluster is down
## 查看集群状态
127.0.0.1:6379> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:0
.......
从输出内容可以看到,被分配的槽(cluster_slots_assigned
)是0
,由于目前所有的槽没有分配到节点,因此集群无法完成槽到节点的映射。只有当16384
个槽全部分配给节点后,集群才进入在线状态。
分配槽空间
Redis 集群把所有的数据映射到16384
个槽中。每个key
会映射为一个固定的槽,只有当节点分配了槽,才能响应和这些槽关联的键命令。通过cluster addslots
命令为节点分配槽。这里利用bash
特性批量设置槽(slots
),把16384
个slot
平均分配给6379
、6380
、6381
三个节点(三主三从),命令如下:
## 分配槽空间
redis-cli -h 127.0.0.1 -p 6379 cluster addslots {0...5461}
redis-cli -h 127.0.0.1 -p 6380 cluster addslots {5462...10922}
redis-cli -h 127.0.0.1 -p 6381 cluster addslots {10923...16383}
## 查看集群状态
127.0.0.1:6379> 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:5
cluster_my_epoch:0
cluster_stats_messages_sent:4874
cluster_stats_messages_received:4726
当前集群状态是OK
,集群进入在线状态。所有的槽都已经分配给节点,执行cluster nodes
命令可以看到节点和槽的分配关系:
127.0.0.1:6379> cluster nodes
4fa7eac4080f0b667ffeab9b87841da49b84a6e4 127.0.0.1:6384 master - 0 14680762401235 connected
cfb28ef1deee4e0fa78da86abe5d24566744411e 127.0.0.1:6379 myself,master - 0 0 0 connected0-5461
be9485a6a729fc98c5151374bc30277e89a461d8 127.0.0.1:6383 master - 0 14680762396224 connected
40622f9e7adc8ebd77fca0de9edfe691cb8a74fb 127.0.0.1:6382 master - 0 14680762406283 connected
8e41673d59c9568aa9d29fb174ce733345b3e8f1 127.0.0.1:6380 master - 0 14680762376061 connected
5462-10922
40b8d09d44294d2e23c7c768efc8fcd153446746 127.0.0.1:6381 master - 0 14680762386122 connected
10923-16383
主从复制
经过上面的步骤,目前还有三个节点没有使用,作为一个完整的集群,每个负责处理槽的节点应该具有从节点,保证当它出现故障时可以自动进行故障转移。集群模式下,Reids 节点角色分为主节点和从节点。首次启动的节点和被分配槽的节点都是主节点,从节点负责复制主节点槽信息和相关的数据。使用clusterreplicate{nodeId}
命令让一个节点成为从节点。其中命令执行必须在对应的从节点上执行,nodeId
是要复制主节点的节点ID
,命令如下:
## 操作主从复制
127.0.0.1:6382>cluster replicate cfb28ef1deee4e0fa78da86abe5d24566744411e
OK
127.0.0.1:6383>cluster replicate 8e41673d59c9568aa9d29fb174ce733345b3e8f1
OK
127.0.0.1:6384>cluster replicate 40b8d09d44294d2e23c7c768efc8fcd153446746
OK
## 查看集群状态
127.0.0.1:6379> cluster nodes
4fa7eac4080f0b667ffeab9b87841da49b84a6e4 127.0.0.1:6384 slave 40b8d09d44294d2e23c7c768efc8fcd153446746 0 1468076865939 5 connected
cfb28ef1deee4e0fa78da86abe5d24566744411e 127.0.0.1:6379 myself,master - 0 0 0 connected 0-5461
be9485a6a729fc98c5151374bc30277e89a461d8 127.0.0.1:6383 slave 8e41673d59c9568aa9d29fb174ce733345b3e8f1 0 1468076868966 4 connected
40622f9e7adc8ebd77fca0de9edfe691cb8a74fb 127.0.0.1:6382 slave cfb28ef1deee4e0fa78da86abe5d24566744411e 0 1468076869976 3 connected
8e41673d59c9568aa9d29fb174ce733345b3e8f1 127.0.0.1:6380 master - 0 1468076870987 1 connected 5462-10922
40b8d09d44294d2e23c7c768efc8fcd153446746 127.0.0.1:6381 master - 0 1468076867957 2 connected 10923-16383
好了,到这里的话整个集群就搭好了,由6
个节点构成,3
个主节点负责处理槽和相关数据,3
个从节点负责故障转移。手动搭建整个流程还是很繁琐的,也是很容易出错的。不过对于理解集群建立的流程和细节来说还是很有帮助的。
总结
整个搭建过程还是挺麻烦的,Redis 官方也提供了redis-trib.rb
工具用于快速搭建集群。这里的话我们就不弄了,用手工搭建出来后,对于理解整个集群还是很有帮助的,好哥哥们不要偷懒哦,动手实践一下基本上就能知道整个过程和一些细节了。后面的话还有一篇关于cluster
一些原理性的内容,下篇应该就能弄完了。