Redis集群之cluster搭建
redis主从集群,哨兵集群,可以应对高并发读的场景,但是高并发写与海量数据存储的问题依然不能解决,主从之间数据同步的缺陷就限制了主服务器内存不能设置的太高,为解决并发写与高可用的问题引入了分片集群(cluster)Cluster集群模式也被称为切片集群是Redis官方推荐使用的一种模式,Cluster方案采用哈希槽(hash slot)来处理实例之间的映射关系,在集群中总共有16384个哈希槽,
文章目录
前言
redis主从集群,哨兵集群,可以应对高并发读的场景,但是高并发写与海量数据存储的问题依然不能解决,主从之间数据同步的缺陷就限制了主服务器内存不能设置的太高,为解决并发写与高可用的问题引入了分片集群(cluster)
一、什么是cluster集群?
Cluster集群模式也被称为切片集群是Redis官方推荐使用的一种模式,Cluster方案采用哈希槽(hash slot)来处理实例之间的映射关系,在集群中总共有16384个哈希槽,默认形式是将16384个哈希槽分配给所有的节点,即哈希槽与集群节点绑定。每个节点分配一段哈希槽类似数据分区,每个键值按照CRC16算法得到哈希值再将其对16384取模CRC16(key) modulo 16384通过最终的结果得到key值存在的哈希槽位置。集群中的节点分为主节点和从节点:只有主节点负责读写请求和集群信息的维护;从节点只进行主节点数据和状态信息的复制。Redis Cluster,是Redis 3.0开始引入的分布式存储方案。
二、Cluster集群概述
1.集群作用
集群的作用,可以归纳为两点:
- 数据分区: 数据分区(或称数据分片)是集群最核心的功能。集群将数据分散到多个节点,一方面突破了Redis单机内存大小的限制,存储容量大大增加;另一方面每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力。Redis单机内存大小受限问题,在介绍持久化和主从复制时都有提及;例如,如果单机内存太大,bgsave和bgrewriteaof的fork操作可能导致主进程阻塞,主从环境下主机切换时可能导致从节点长时间无法提供服务,全量复制阶段主节点的复制缓冲区可能溢出……等
- 高可用: 集群支持主从复制和主节点的自动故障转移(与哨兵类似),当任一节点发生故障时,从节点可以代替主节点, 集群仍然可以对外提供服务。以及当某master节点故障时,其他master仍然可提供服务
2.集群特征
- 集群中有多个master,每个master保存不同的数据
- 每个master都可以有多个slave节点
- master之间通过ping,彼此间检测健康状态
- 客户端可以请求访问集群中任意节点,最终都会被转发到正确的节点上
3.应用场景
Redis集群模式适用于需要横向扩展和高可用性的场景。
当数据量大,单个Redis节点无法满足需求时,可以通过搭建Redis集群来提供更大的存储容量和处理能力。同时,Redis集群模式通过数据分片和数据复制实现高可用性,即使其中某个节点发生故障,整个集群仍然可用。
三、cluster集群搭建
本文是基于redis5.0版本搭建,本文在一台虚拟机中使用不同的端口号模拟不同的redis示例redis集群架构图如下:
ip:端口 | 角色 |
---|---|
127.0.0.1:6379 | master |
127.0.0.1:6380 | master |
127.0.0.1:6381 | master |
127.0.0.1:6382 | slave |
127.0.0.1:6383 | slave |
127.0.0.1:6384 | slave |
1. 创建运行实例目录
- 在redis的安装目录中创建文件夹以运行不同的实例,创建目录
mkdir -p /data/soft/redis_5_0_0/{redis-6379,redis-6380,redis-6381,redis-6382,redis-6383,redis-6384}/{conf,run,logs,dbcache}
- redis-6379代表运行的实例
目录介绍:
conf : 实例配置文件目录
dbcache: rdb数据目录
logs : 运行日志目录
run: 实例pid文件目录
# /data/soft/redis_5_0_0 该目录为redis的安装目录
[root@master redis_5_0_0] cd /data/soft/redis_5_0_0
[root@master redis_5_0_0]#
[root@master redis_5_0_0]# ls
bin redis-6379 redis-6380 redis-6381 redis-6382 redis-6383 redis-6384
[root@master redis-6379]# cd redis-6379
[root@master redis-6379]# ls
conf dbcache logs run
2.修改redis配置文件及分发
- 修改redis.conf 配置文件,如下:
daemonize yes #开启后台运行
requirepass 123456 #设置redis数据库密码
masterauth 123456 #设置集群节点间访问密码
protected-mode no
port 6379
pidfile /data/soft/redis_5_0_0/redis-6379/run/redis_6379.pid
logfile “/data/soft/redis_5_0_0/redis-6379/logs/redis.log”
dir /data/soft/redis_5_0_0/redis-6379/dbcache/
#开启redis-cluster
cluster-enabled yes
#设置节点之间超时时间
cluster-node-timeout 15000
#指定cluster-config-file,不能与别的节点相同
cluster-config-file nodes-6379.conf
- 将redis.conf分发复制到不同实例的conf文件夹中
# 分发redis.conf配置文件,在redis.conf配置文件路径中执行如下命令
[root@master redis_5_0_0] echo redis-6379/conf/redis-6379.conf redis-6380/conf/redis-6380.conf redis-6381/conf/redis-6381.conf redis-6382/conf/redis-6382.conf redis-6383/conf/redis-6383.conf redis-6384/conf/redis-6384.conf | xargs -t -n 1 cp redis.conf
- 将配置文件中含有端口配置改为对应的实例端口
vim redis-6380.conf
:1,$s/6379/6380/g # 命令模式下执行,将配置文件中的6379改为6380
3.分别启动redis实例
运行一下命令启动实例:
printf ‘%s\n’ redis-6379/conf/redis-6379.conf redis-6380/conf/redis-6380.conf redis-6381/conf/redis-6381.conf redis-6382/conf/redis-6382.conf redis-6383/conf/redis-6383.conf redis-6384/conf/redis-6384.conf | xargs -I{} -t /data/soft/redis_5_0_0/bin/redis-server {}
- 只是启动6台redis服务器,服务器之间没有任何的关联
[root@master redis_5_0_0]# printf '%s\n' redis-6379/conf/redis-6379.conf redis-6380/conf/redis-6380.conf redis-6381/conf/redis-6381.conf redis-6382/conf/redis-6382.conf redis-6383/conf/redis-6383.conf redis-6384/conf/redis-6384.conf | xargs -I{} -t /data/soft/redis_5_0_0/bin/redis-server {}
/data/soft/redis_5_0_0/bin/redis-server redis-6379/conf/redis-6379.conf
/data/soft/redis_5_0_0/bin/redis-server redis-6380/conf/redis-6380.conf
/data/soft/redis_5_0_0/bin/redis-server redis-6381/conf/redis-6381.conf
/data/soft/redis_5_0_0/bin/redis-server redis-6382/conf/redis-6382.conf
/data/soft/redis_5_0_0/bin/redis-server redis-6383/conf/redis-6383.conf
/data/soft/redis_5_0_0/bin/redis-server redis-6384/conf/redis-6384.conf
[root@master redis_5_0_0]# ps -axu | grep redis | grep -v grep
root 2134 0.3 0.6 163192 11804 ? Ssl 22:49 0:00 /data/soft/redis_5_0_0/bin/redis-server 127.0.0.1:6379 [cluster]
root 2139 0.3 0.4 157048 7716 ? Ssl 22:49 0:00 /data/soft/redis_5_0_0/bin/redis-server 127.0.0.1:6380 [cluster]
root 2144 0.0 0.4 157048 7720 ? Ssl 22:49 0:00 /data/soft/redis_5_0_0/bin/redis-server 127.0.0.1:6381 [cluster]
root 2149 0.0 0.4 157048 7720 ? Ssl 22:49 0:00 /data/soft/redis_5_0_0/bin/redis-server 127.0.0.1:6382 [cluster]
root 2154 0.0 0.4 157048 7720 ? Ssl 22:49 0:00 /data/soft/redis_5_0_0/bin/redis-server 127.0.0.1:6383 [cluster]
root 2159 2.3 0.4 157048 7724 ? Ssl 22:49 0:00 /data/soft/redis_5_0_0/bin/redis-server 127.0.0.1:6384 [cluster]
4.创建集群
Redis5.0之前集群命令都是用安装包下的src/redis-trib.rb 来实现的,因为redis-trib.rb是由Ruby实现的所以需要安装Ruby的运行环境, 本文中以Redis5.0.0为例来安装故不需要Ruby环境。可以直接在redis-cli 中直接使用集群相关的操作命令
- 命令解释:
redis-cli --cluster : 代表集群操作命令
create :代表是创建集群
cluster-replicas 1: 指定集群中每个master的副本数为1,此时主节点master的总数就是 集群节点总数除以(replicas+1)等于N,因此节点中的前N个为master节点,其他节点都是slave节点,随机分配到不同的master
# 执行创建集群命令
[root@master redis_5_0_0]# /data/soft/redis_5_0_0/bin/redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 --cluster-replicas 1 -a 123456
# 查看集群节点信息
# 6484是6380的从节点
# 6383是6379的从节点
# 6382是6381的从节点
[root@master redis_5_0_0]# redis-cli -p 6379
127.0.0.1:6379> AUTH 123456
127.0.0.1:6379> CLUSTER NODES
cfeecfe2803b211051ab5944cdf5ee022b55dd0c 127.0.0.1:6384@16384 slave 3ed64d2aa3ee633c88f4bbc7d7f1233ce5991f73 0 1714230693190 6 connected
21ea85f10415e26d2fcc3b2920968d8f849a113c 127.0.0.1:6381@16381 master - 0 1714230693000 3 connected 10923-16383
3ed64d2aa3ee633c88f4bbc7d7f1233ce5991f73 127.0.0.1:6380@16380 master - 0 1714230693000 2 connected 5461-10922
b3ddc7b9ae0dea7dc4a280c225c252a3986163c2 127.0.0.1:6379@16379 myself,master - 0 1714230691000 1 connected 0-5460
73f62cf8f45b0432b3df37c5fa21e74bfe6ab179 127.0.0.1:6382@16382 slave 21ea85f10415e26d2fcc3b2920968d8f849a113c 0 1714230692181 4 connected
50492b7275b66373670cf600fab29709e8da886d 127.0.0.1:6383@16383 slave b3ddc7b9ae0dea7dc4a280c225c252a3986163c2 0 1714230691000 5 connected
四、cluster实践
1. 查询判断slot插槽与实例的绑定
客户端登录redis,使用 CLUSTER NODES 可以查看主从节点,已经主节点分配的slot(哈希槽)
127.0.0.1:6379> CLUSTER NODES
cfeecfe2803b211051ab5944cdf5ee022b55dd0c 127.0.0.1:6384@16384 slave 3ed64d2aa3ee633c88f4bbc7d7f1233ce5991f73 0 1714305487728 6 connected
21ea85f10415e26d2fcc3b2920968d8f849a113c 127.0.0.1:6381@16381 master - 0 1714305487000 3 connected 10923-16383
3ed64d2aa3ee633c88f4bbc7d7f1233ce5991f73 127.0.0.1:6380@16380 master - 0 1714305486000 2 connected 5461-10922
b3ddc7b9ae0dea7dc4a280c225c252a3986163c2 127.0.0.1:6379@16379 myself,master - 0 1714305488000 1 connected 0-5460
73f62cf8f45b0432b3df37c5fa21e74bfe6ab179 127.0.0.1:6382@16382 slave 21ea85f10415e26d2fcc3b2920968d8f849a113c 0 1714305489758 4 connected
50492b7275b66373670cf600fab29709e8da886d 127.0.0.1:6383@16383 slave b3ddc7b9ae0dea7dc4a280c225c252a3986163c2 0 1714305488742 5 connected
上述集群节点信息中,每列的含义
-
第一列表示节点ID,集群中唯一的
-
第二列表示节点的ip与端口号
-
第三列表示节点的状态与角色,常见的标识包括: myself:表示当前节点是执行命令的节点,sl master:表示节点是主节点,slave:表示节点是副本节点,fail?:表示节点可能处于故障状态
-
第四列 如果是主节点,则用-占位,如果是副本节点,则显示该副本节点的主节点是哪个(主节点的ID)
-
第五列用于检测节点之间的网络连接情况Ping/Pong响应的时间
-
第六列表示13位时间戳
-
第七列在集群中选择新的主节点的内部计数器
-
第八列显示节点之间的连接状态 可以时connected(连接正常),disconnected(连接断开)
-
第九列节点负责的哈希槽范围
以此可以判断
主节点 127.0.0.1:6379 从节点端口 6383 插槽范围 0-5460
主节点127.0.0.1:6380 从节点端口 6384 插槽范围 5461-10922
主节点127.0.0.1:6381 从节点端口 6382 插槽范围 10923-16383
2.如何判断某个key应该在哪个实例分布
使用 命令 CLUSTER KEYSLOT key 可以查看 key对应的slot(哈希槽)
[root@master ~]# redis-cli -p 6380
127.0.0.1:6380>
127.0.0.1:6379> CLUSTER KEYSLOT good_info_id:123123534534
(integer) 2834
127.0.0.1:6380> set good_info_id:123123534534 123123123
(error) MOVED 2834 127.0.0.1:6379
127.0.0.1:6380>
key: good_info_id:123123534534 根据crc16计算哈希值为2834,2834对16384取余得到slot值为2834,slot为2834对应的实例为127.0.0.1:6379,此时在客户端为127.0.0.1:6380运行出现MOVED的错误。
解决方式
1. 直接更换实例连接 redis-cli -p 6379
2. 在连接时使用 redis-cli时增加 -c参数
[root@master ~]# redis-cli -p 6380 -c
127.0.0.1:6380> AUTH 123456
OK
127.0.0.1:6380> set good_info_id:123123534534 123123123
-> Redirected to slot [2834] located at 127.0.0.1:6379
(error) NOAUTH Authentication required.
127.0.0.1:6379>
3.如何将同一类数据固定的保存在同一个实例
数据key不是与节点绑定,而是与插槽绑定,redis会根据key的有效部分计算插槽值,情况分两种
-
- key中包含 {},且{}中至少包含一个字符,那么{}中的部分为有效部分
-
- 二是key中不包含{},那么整个key都是有效部分
例如: key是good_info那么就根据good_info计算,如果是{shops:}good_info则根据shops:计算,
计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot的值,取余计算后的值为4010,4010与端口号为6379的实例绑定
127.0.0.1:6379> set {shops:}good_info 1231231
OK
127.0.0.1:6379> set {shops:}conf_info 1231231
OK
127.0.0.1:6379> keys *
1) "{shops:}conf_info"
2) "{shops:}good_info"`
3.如何将一个节点添加到集群
在集群中如何增加一个节点?以及如何将同一实例下的{shops:}good_info,迁移到新节点?
将新增的redis实例127.0.0.1:6385 的节点添加到新集群中,新增节点redis配置与搭建集群配置类似,在此就不再赘述。新增节点主要有两个操作: 一将新增节点加入集群, 二 将集群中的部分 Slot 迁移至新增的节点,如有固定业务key需迁移,还需确定固定业务key的槽点主要操作,受先查看一下命令帮助文档
- 查看命令帮助 /data/soft/redis_5_0_0/bin/redis-cli --cluster help
- new_host:new_port:为要新添加的主节点 IP 和端口
- existing_host:existing_port:表示的是环境中已存在的最后一个主节点的 IP 和端口,这个可以通过 查看节点信息得知,根据 slots 槽数,127.0.0.1:6381 对应的节点槽数是 10923-16383,16383表示的是最后的槽数
- –cluster-master-id:表示的是最后一个主节点的节点 ID,表示的是新添加的节点是这个节点的从节点
- –cluster-slave: 表示添加的节点为副本节点(slave)
无参数-–cluster-master-id, --cluster-slave时新加的节点默认是主节点
迁移过程如下:
- 使用如下命令将新节点加入新集群中 /data/soft/redis_5_0_0/bin/redis-cli -a 123456 --cluster add-node 127.0.0.1:6385 127.0.0.1:6381
- 查看key的哈希槽位置 命令 CLUSTER KEYSLOT key。 {shops:}good_info 对应的哈希槽为4010
- 将集群中的部分 Slot 迁移至新增的节点,使用如下命令:redis-cli -a 123456 --cluster reshard 127.0.0.1:6385
注意 :6379的节点范围为0-5460只要将4010槽点范围迁移至新节点即可,其他源节点必须是主节点。
#查看新节点无任何数据
127.0.0.1:6385> keys *
(empty list or set)
127.0.0.1:6385>
# 查看key对应的slot槽点
[root@master bin]# ./redis-cli -p 6379
127.0.0.1:6379> AUTH 123456
127.0.0.1:6379> CLUSTER KEYSLOT {shops:}good_info
(integer) 4010
# 添加完成后,查看新节点数据
127.0.0.1:6379> get {shops:}good_info
-> Redirected to slot [4010] located at 127.0.0.1:6385
(error) NOAUTH Authentication required.
127.0.0.1:6385> AUTH 123456
OK
127.0.0.1:6385> get {shops:}good_info
"1231231"
127.0.0.1:6385>
127.0.0.1:6380> set {shops:}good_info 445566
-> Redirected to slot [4010] located at 127.0.0.1:6385
OK
127.0.0.1:6385> keys *
1) "{shops:}conf_info"
2) "{shops:}good_info"
127.0.0.1:6385>
下图为添加节点后集群所有节点
执行添加节点命令后,执行过程如下
总结: 在集群增加节点过程中可以发现,数据与slot绑定,而不是与节点直接绑定,可以更方便的实现数据在不同节点之间的迁移维护。
4.故障转移
当集群中的一个master节点宕机时会发生什么呢?
现在使用linux中watch命令实时查看集群信息变化,使用 如下命令:watch /data/soft/redis_5_0_0/bin/redis-cli -p 6380 -a 123456 cluster nodes来观察集群节点6379出现故障时集群变化。
集群节点状态变化之前
关闭6379的节点后,6379状态为fail?,可能出现故障
等待几秒后6379状态为fail,集群判断出现故障,将6379的slave从节点6383提升为master
启动6379节点后,6379又变为slave从节点
总结: 整个变化过程中首先是6379实例与其他实例失去连接,然后是疑似宕机,最后确定下线,自动提升一个slave节点为新的master
5.数据迁移
在实际应用场景中,有时会对主节点所在的机器进行各方面的维护等,需要对主节进行下线,也就是手动故障转移
案例:在故障转移中,6379已成为slave,现将6379 重新提升为master,使6383成为slave
在要提升为主节点的slave节点中执行如下命令: CLUSTER FAILOVER
注意:使谁成为主节点master,就在主节点master对应的从节点上执行 CLUSTER FAILOVER命令
执行命令如下:
[root@master redis_5_0_0]# /data/soft/redis_5_0_0/bin/redis-cli -c -p 6379 -a 123456
127.0.0.1:6379> CLUSTER FAILOVER
执行CLUSTER FAILOVER 后,集群节点变化如下:手动执行failover,支持三种不同的参数,
- 缺省值,严格按照保证数据完整性流程执行
- force 强制执行省略offset一致性性校验
- takeover 直接执行第5步忽略一致性,忽略master的状态,和其他master的意见
failover 执行时序图
五、cluster集群的优缺点
1.cluster集群优点
- 高可用多主多从:服务故障的情况,影响范围小,Redis集群有多个master,可以减小访问瞬断问题的影响,若集群中有一个master挂了,正好需要向这个master写数据,这个操作需要等待但向其他master节点写数据不受影响
- 高并发:Redis集群有多个master,可以提供更高的并发量,包括写与读
- 数据分布,存储数据量大:Redis集群可以分片存储,这样就可以存储更多的数据
- 负载均衡:客户端可以直接连接 Redis Cluster 的任何节点,数据会自动分配到正确的节点
- 故障转移和重新分配:当一个主节点失效时,其从节点会自动升级为新的主节点,并重新分配数据
- 可扩展伸缩性:Redis Cluster 可以通过增加新的节点来线性扩展
- 无中心架构:去中心化,无中心架构,高可用的实现不需要额外引入集群(类似哨兵集群),主节点中每台机器都有哨兵节点的作用,客户端可与集群主节点的任何一台机器通信,完成数据的写入读写
2.cluster集群缺点
- 数据分布不均匀:Redis Cluster 的数据分布基于哈希槽,可能导致数据分布不均,可能导致在某些节点上的负载比其他节点更高(请求倾斜)。可能产生数据倾斜的原因: 节点和槽分配严重不均,不同槽对应键数量差异过大,集合对象包含大量元素等。
- 不支持多个数据库:Redis Cluster 不支持多个数据库,所有数据都在数据库0上。
- 不保证强一致性:Redis Cluster 数据通过异步复制,不保证数据的强一致性,可能会出现写入丢失的情况。
- 不支持Lua脚本执行:Redis Cluster 不支持在所有节点上执行Lua脚本
- 数据分析,隔离困难:多个业务使用同一套集群的时候,不能够依据统计区分冷热数据,资源隔离性较差,非常容易出现互相影响,Key批量操作限制,事务操作支持有限,避免产生hot-key,导致主库节点成为系统的短板。避免产生big-key,导致网卡撑爆、慢查询
- 带宽消耗:集群内Gossip消息通信本身会消耗带宽, 官方建议集群最大规模在1000以内, 也是出于对消息通信成本的考虑, 因此单集群不适合部署超大规模的节点。集群内所有节点通过ping/pong消息彼此交换信息, 节点间消息通信对带宽的消耗体现在以下几个方面:
消息发送频率:跟cluster-node-timeout密切相关, 当节点发现与其他节点最后通信时间超过cluster-node-timeout/2时会直接发送ping消息。
消息数据量:每个消息主要的数据占用包含: slots槽数组(2KB空间) 和整个集群1/10的状态数据(10个节点状态数据约1KB) 。- 运维复杂:Redis Cluster 运维较复杂,例如,节点的增加和删除都需要对集群的重分配和重新平衡。
总结
以上就是今天主要讲的内容,简单介绍一下什么是Redis的Cluster集群,集群的特点,应用场景,如何搭建Cluster集群,以及常见的Clusetr集群操作。结合上篇文章 Redis集群之主从架构
Redis集群(Cluster)模式 适用于需要横向扩展和高可用性的场景,通过数据分片和数据复制来提供扩展性和容错性;
Redis主从模式 适用于读写分离和数据备份的场景,通过数据复制和读写分离来提高读取性能和数据的冗余备份能力。
具体选择哪种模式取决于应用的需求和对于扩展性、高可用性和读取性能的重要性。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)