「进击 Redis」二十七、Redis cluster 集群搭建 | 七日打卡

631 阅读11分钟

前言

Redis 系列第二十七篇,也是Cluster 集群模式第二篇。 上篇我们已经通过画图与对比的方式将Cluster 虚拟槽寻址思路、取余hash一致性hash寻址的原理弄清楚了,还有不熟悉的好哥哥可以看你竟然还不知道 hash slot 这篇了解一下。这一篇的话主要是对Cluster 集群的搭建与使用,上一篇又说到分成两篇的,想想篇幅还是不要那么长,于是乎就有了一篇。

这一篇的话基本上都是一些实践性的内容,好哥哥们还是一样不要偷懒哦。有杠精好哥哥会说了,怎么哨兵模式的搭建你怎么不弄?有这么杠的好哥哥估计没有认真看图解 Redis 哨兵模式,在这一片总结的地方已经说了原因,好哥哥们别闹。
bienao

概述

图解 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,然后的话所有节点的配置尽量放在统一的目录下,由于我们这边使用的是一台服务器,所以只能用名字加端口号来区分。一般划分为confdatalog三个目录,分别存放配置、数据和日志相关文件。主要配置如下:

# 节点端口
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,它是一个4016进制字符串,用于唯一标识集群内一个节点,之后很多集群操作都要借助于节点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}meet
过程如下:

  1. 节点6379本地创建6380节点信息对象,并发送meet消息。
  2. 节点6380接受到meet消息后,保存6379节点信息并回复pong消息。
  3. 之后节点63796380彼此定期通过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),把16384slot平均分配给637963806381三个节点(三主三从),命令如下:

## 分配槽空间
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一些原理性的内容,下篇应该就能弄完了。

本期就到这啦,有不对的地方欢迎好哥哥们评论区留言,另外求关注、求点赞

上一篇: 你竟然还不知道 hash slot