当前位置: 首页 > news >正文

NoSQL之Redis集群

目录

一:Redis 集群方式

二:集群模式简介

三:数据分片方式

1:客户端分片

2:代理分片

3:服务器端分片

四:负载均衡的实现

五:故障的处理

1:故障转移

2:多slave选举

六:Redis群集部署

创建 redis 群集

测试群集

集群信息查看

添加节点

添加节点的另一种方法

删除节点

集群排错思路


一:Redis 集群方式

Redis 有三种模式:分别是主从复制、哨兵模式、Cluster

模式优点缺陷
主从模式1. 实现数据多机备份
2. 读操作负载均衡
3. 简单故障恢复
1. 故障恢复无法自动化
2. 写操作无法负载均衡
3. 存储能力受单机限制
哨兵模式1. 在主从复制基础上实现自动化故障恢复1. 写操作无法负载均衡
2. 存储能力受单机限制
3. 哨兵无法对从节点自动故障转移
4. 从节点故障可能导致读取服务不可用
集群模式1. 解决写操作负载均衡问题
2. 突破单机存储限制
3. 高可用方案完善
1. 配置和管理相对复杂
2. 需要更多节点支持
3. 网络分区可能导致部分服务不可用
模式版本支持优点缺点
主从模式Redis 2.8 之前1. 解决数据备份问题
2. 读写分离,提高服务器性能
1. Master 故障需人工介入,无法自动故障转移
2. Master 无法动态扩容
哨兵模式Redis 2.8 及之后1. 监测 Master 状态
2. 自动主从切换,实现故障自愈
3. 从节点自动跟随新 Master
1. Slave 节点下线时,Sentinel 不进行故障转移,客户端可能无法获取可用从节点
2. Master 无法动态扩容
Redis Cluster 模式Redis 3.0 及之后1. 满足分布式需求
2. 解决单机内存、并发和流量瓶颈,实现负载均衡
3. 支持动态扩容
4. 无中心化 P2P 模式
5. 通过 Gossip 协议同步节点信息
6. 自动故障转移,Slot 迁移中数据可用
7. 自动分片数据到不同节点
8. 部分节点故障仍可处理命令
1. 架构较新,最佳实践较少
2. 客户端需缓存路由表以提升性能
3. 节点发现和 Reshard 操作不够自动化
4. 不支持多 Keys 命令(需跨节点移动数据)
5. 仅支持默认 0 号数据库,不支持 SELECT 命令

二:集群模式简介

特性Redis Cluster 集群模式
版本支持Redis 3.0 及以上
节点组成由多个主节点(Master)和从节点(Slave)组成,主节点负责读写和集群维护,从节点仅备份数据。
数据分布数据分片存储在多个主节点上,通过哈希槽(Slot,共16384个)分配数据。
高可用机制1. 主从复制:Slave 实时同步 Master 数据
2. 故障转移:Master 宕机时,Slave 通过投票自动晋升为新的 Master。
故障检测基于投票容错机制,超过半数节点认为某节点失效时触发故障转移(最少需3个主节点)。
扩展性无中心化架构,支持水平扩展(官方建议不超过1000个节点)。
客户端访问客户端可连接任意节点,节点内部通过重定向(MOVED/ASK)引导请求到正确分片。
优势1. 高性能:无代理层,直接访问节点
2. 高可用:自动故障转移
3. 海量数据支持:分片存储突破单机限制。
适用场景海量数据、高并发、高可用需求场景(如电商、社交平台等)。
配置复杂度配置简单,但需预先规划分片和节点拓扑。

三:数据分片方式

特性说明
分片基础使用 CRC16 算法对 key 进行哈希,然后对 16384 取模确定 Slot 编号:HASH_SLOT = CRC16(key) % 16384
Slot 分配1. 集群预分配 16384 个 Slot
2. 每个 Master 节点负责一部分 Slot
3. Slave 节点不分配 Slot,仅备份数据
请求路由1. 客户端连接任意节点发送请求
2. 若请求的 key 不属于当前节点,返回 MOVED 重定向到正确节点
3. 客户端自动重发请求到目标节点
分片优势1. 数据均匀分布,避免热点问题
2. 高并发:多节点并行处理
3. 故障隔离:单节点故障仅影响局部数据
分片类型1. 客户端分片:由客户端计算 Slot 并直连节点(如 Jedis Cluster)
2. 代理分片:通过中间件(如 Twemproxy)路由请求
3. 混合分片:结合客户端与代理的优势
动态扩缩容支持通过 CLUSTER ADDSLOTS 或工具(如 redis-trib)调整 Slot 分配,但需手动迁移数据
限制1. 不支持跨 Slot 的多 Key 操作(如 MGET 需所有 key 在同一 Slot)
2. 事务仅限于单节点操作

1:客户端分片

         客户端分片方案是将分片工作放在业务程序端。程序代码根据预先设置的路由规则,直接对多个 Redis 实例进行分布式访问。这样的好处是,群集不依赖于第三方分布式中间件,实现方法和代码都自己掌控,可随时调整,不用担心踩到坑。这实际上是一种静态分片技术Redis 实例的增减,都得手工调整分片程序。基于此分片机制的开源产品,现在仍不多见。
         这种分片机制的性能比代理式更好(少了一个中间分发环节),但缺点是升级麻烦,对研发人员的个人依赖性强,需要有较强的程序开发能力做后盾。如果主力程序员离职,可能新的负责人会选择重写一遍。所以这种方式下可运维性较差,一旦出现故障,定位和解决都得研发人员和运维人员配合解决,故障时间变长。因此这种方案,难以进行标准化运维,不太适合中小公司。

2:代理分片

          代理分片方案是将分片工作交给专门的代理程序来做。代理程序接收到来自业务程序的数据请求,根据路由规则,将这些请求分发给正确的 Redis 实例并返回给业务程序。这种机制下,一般会选用第三方代理程序(而不是自己研发)。因为后端有多个 Redis 实例,所以这类程序又称为分布式中间件。这种分片机制的好处是业务程序不用关心后端 Redis实例,维护起来也方便。虽然会因此带来些性能损耗,但对于Redis 这种内存读写型应用相对而言是能容忍的。这是比较推荐的集群实现方案。像 Twemproxy、Codis 就是基于该机制的开源产品的其中代表,应用非常广泛。

特性TwemproxyCodis
开发方Twitter 开源豌豆荚开源(Go/C 语言开发)
架构单层代理,无中心节点基于 Group 的主从架构(1 Master + N Slave)
分片机制静态哈希分片,不支持动态调整预分片 1024 Slot,支持动态迁移(Auto Rebalance)
扩容/缩容不支持平滑扩缩容,需停机调整支持在线数据迁移,扩容缩容更灵活
高可用性依赖 Keepalived 实现代理层高可用内置故障转移(通过 Dashboard 切换 Master/Slave)
运维支持无控制面板,纯命令行操作提供可视化 Dashboard,简化运维
性能损耗约 20% 性能下降(相比直连 Redis)优化后性能优于 Twemproxy
数据迁移需手动迁移数据,复杂度高支持热迁移(基于修改的 CodisServer)
依赖组件无额外依赖依赖 Zookeeper/Etcd 存储路由信息
适用场景小规模静态集群,对性能要求不苛刻的场景中大规模集群,需频繁扩缩容或高可用要求的场景

3:服务器端分片

       服务器端分片是 Redis 官方的集群分片技术。Redis-Cluster 将所有 Key 映射到16384个 slot 中,集群中每个 Redis 实例负责一部分,业务程序是通过集成的Redis-Cluster 客户端进行操作。客户端可以向任一实例发出请求,如果所需数据不在该实例中,则该实例引导客户端自动去对应实例读写数据。Redis-Cluster 成员之间的管理包括节点名称、IP、端口、状态、角色等,都通过节点与之间两两通讯,定期交换信息并更新。

四:负载均衡的实现

机制实现方式核心作用
客户端路由1. 客户端通过 CRC16(key) % 16384 计算 Slot
2. 直连目标节点或根据 MOVED 重定向
避免代理层开销,直接分散请求到不同节点
自动迁移(Rebalance)1. 节点增减时触发 Slot 迁移
2. 使用 CLUSTER ADDSLOTS 和 RESHARD 命令调整分布
动态扩缩容时保持数据均匀分布
故障检测与恢复1. 节点间通过 Gossip 协议健康检测
2. 半数以上节点确认故障后触发从节点晋升
自动容灾,保障高可用性
分片+副本1. 数据分片到多个主节点
2. 每个主节点配置从节点(副本)
1. 提升并发能力
2. 故障时无缝切换

与传统方案的对比

特性Redis ClusterTwemproxy/Codis
负载均衡客户端智能路由 + 自动迁移依赖代理层静态分片
扩展性无中心化,支持线性扩展代理层可能成为瓶颈
故障恢复内置 Gossip 协议和投票机制需额外工具(如 Sentinel)

五:故障的处理

1:故障转移

步骤触发条件执行动作集群状态变化
1主节点被多数节点判定为 FAIL从节点发起选举(基于配置纪元+运行ID)集群进入故障转移准备阶段
2从节点赢得选举执行 SLAVEOF NO ONE 晋升为新主节点原主节点槽位标记为「待迁移」
3新主节点生效1. 撤销原主节点槽位指派
2. 将槽位重新指派给自己
集群路由表更新
4新主节点广播发送 PONG 消息宣告主权其他节点更新本地节点列表
5客户端重定向1. 客户端收到 MOVED 响应
2. 自动连接新主节点
业务请求恢复处理
6槽位完整性检查若集群配置 cluster-require-full-coverage=no 允许部分槽位缺失时继续提供服务关键区别:
• yes(默认):必须16384个槽全部分配才可用
• no:容忍部分故障

故障转移耗时分析

阶段耗时参考影响因素
故障检测1~15秒cluster-node-timeout 参数设置
选举+晋升1~2秒从节点数量及网络延迟
槽位重新分配瞬时完成无数据迁移时仅元数据更新
全集群状态同步1~5秒集群规模及 Gossip 协议传播效率

2:多slave选举

步骤触发条件参与角色关键动作选举规则
1主节点被判定为 FAIL 状态所有从节点广播 CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST 请求投票每个从节点独立发起选举
2收到投票请求的主节点具有投票权的主节点检查是否已投票:
• 未投票 → 返回 CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK
• 已投票 → 忽略请求
每个主节点仅能投一票(先到先得)
3从节点收集投票参与选举的从节点统计收到的 ACK 消息数量需获得 半数以上主节点+1 的票数(N/2+1)
4票数达标胜出从节点执行 SLAVEOF NO ONE 晋升为新主节点立即接管原主节点的 Slot 并广播 PONG 通知集群
5票数不足(选举超时)所有从节点进入新一轮选举周期随机延迟后重新发起投票(避免冲突)

六:Redis群集部署

资源列表

操作系统主机名配置IP地址角色Slot分配建议从属关系
OpenEuler24master12C4G192.168.10.101Master0-5460对应 slave1
OpenEuler24master22C4G192.168.10.102Master5461-10922对应 slave2
OpenEuler24master32C4G192.168.10.103Master10923-16383对应 slave3
OpenEuler24slave12C4G192.168.10.104Slave不分配 Slot复制 master1 数据
OpenEuler24slave22C4G192.168.10.105Slave不分配 Slot复制 master2 数据
OpenEuler24slave32C4G192.168.10.106Slave不分配 Slot复制 master3 数据

安装 redis(每个节点都要安装)

[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# setenforce 0[root@localhost ~]# dnf -y install gcc* zlib-devel tar
[root@localhost ~]# tar xzvf redis-5.0.14.tar.gz
[root@localhost ~]# cd redis-5.0.14/[root@localhost redis-5.0.14]# make
[root@localhost redis-5.0.14]# make PREFIX=/usr/local/redis install
[root@localhost ~]# ln -s /usr/local/redis/bin/* /usr/local/bin/
[root@localhost redis-5.0.14]# cd /root/redis-5.0.14/utils/
[root@localhost utils]# ./install_server.sh

修改配置文件(每个节点都要配置,只有 IP 地址不同,其他都相同)

[root@localhost ~]# vim /etc/redis/6379.conf
bind 0.0.0.0    ##70行
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
supervised no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile /var/log/redis_6379.log
appendonly yes    ##开启 aof 持久化,700行
cluster-enabled yes    ##83行,去掉注释符,表示启用群集
cluster-config-file nodes-6379.conf    ##841行,去掉注释
cluster-node-timeout 15000    ##847行,去掉注释
cluster-require-full-coverage no    ##924行,去掉注释,将yes改为no

注释:
开启 Cluster:cluster-enabled yes
集群配置文件:cluster-config-file nodes-7000.conf。这个配置文件不是要我们去配的,而是 Redis 运行时保存配置的文件,所以我们也不可以修改这个文件。
集群超时时间:cluster-node-timeout 15000。结点超时多久则认为它宕机了。
槽是否全覆盖:cluster-require-full-coverage no。默认是 yes,只要有结点宕机导致 16384 个槽没全被覆盖,整个集群就全部停止服务,所以一定要改为 no

[root@localhost ~]# /etc/init.d/redis_6379 restart
[root@localhost ~]# netstat -anpt | grep 6379
tcp        0      0 192.168.10.101:6379     0.0.0.0:*               LISTEN      20315/redis-server 
tcp        0      0 192.168.10.101:16379    0.0.0.0:*               LISTEN      20315/redis-server 

创建 redis 群集

任意一个节点

[root@localhost ~]# redis-cli --cluster create --cluster-replicas 1 192.168.10.101:6379 192.168.10.102:6379 192.168.10.103:6379 192.168.10.104:6379 192.168.10.105:6379 192.168.10.106:6379

备注:
需要至少 3 个 master 节点,副本数至少为 1,即每个 master 需要一个从节点

测试群集

[root@localhost ~]# redis-cli -h 192.168.10.106 -p 6379 -c
192.168.10.106:6379> set centos 7.3192.168.10.106:6379> get centos
192.168.10.106:6379> quit[root@localhost ~]# redis-cli -h 192.168.10.105 -p 6379 -c
192.168.10.105:6379> get centos
192.168.10.105:6379> quit

集群信息查看

[root@localhost ~]# redis-cli
192.168.10.106:6379> cluster nodes[root@localhost ~]# redis-cli --cluster check 192.168.10.101:6379

添加节点

例如存在节点 192.168.10.107(并且已在配置文件中开启集群相关配置),把 192.168.10.107 加入现有集群

[root@localhost ~]# redis-cli -c -p 6379 cluster meet 192.168.10.107 6379
OK
[root@localhost ~]# redis-cli
127.0.0.1:6379> cluster nodes

注意:
添加完后此新节点是 master 的角色

添加节点的另一种方法

例如存在节点 192.168.10.108(并且已在配置文件中开启集群相关配置),把 192.168.10.108 加入现有集群

[root@localhost ~]# redis-cli --cluster add-node 192.168.10.108:6379 192.168.10.101:6379

注意:
10.108 是要新添加的节点,10.101 可以是当前集群中的任意一个节点

删除节点

清除 10.108 的槽位信息

[root@localhost ~]# redis-cli -h 192.168.10.108 -p 6379
192.168.10.109:6379> flushall
OK
192.168.10.109:6379> cluster reset
OK

删除10.108的节点

[root@localhost ~]# redis-cli --cluster del-node 192.168.10.108:6379 fe75330496c2c2af9c5a02b9819d6b2e8a4d8a2

注意:此ID为10.108的ID
如果删除的 slave 节点,直接删除即可,如果删除的是 master 节点,需要先清除槽信息再删除,并且建议清除 redis 实例中的集群配置文件并重启实例,例如 /var/lib/redis/6379/nodes-6379.conf

修改新节点为其他节点的从节点

[root@localhost ~]# redis-cli -h 192.168.10.108 -p 6379
192.168.10.108:6379> cluster replicate 5472bbc9226737ca2199e146080ddaa41686a694

注意:10.108 需要先加入到集群,再设置为其他 master 的 slave。

重新分配槽位
重新分片基本上意味着将 slot 重新分配,就像集群创建一样,它是使用 redis-cli 实用程序完成的。
平均分配所有的槽位,使用以下命令会自动将 16384 个槽位自动分配给集群的每一个 master,不用手动指定槽为分配。

[root@localhost ~]# redis-cli --cluster rebalance --cluster-threshold 1 --cluster-use-empty-masters 192.168.10.101:6379

只需要指定一个老的节点 (192.168.10.101:6379),redis 会自动查找其他节点。

如果某个 master 节点没有槽位,可以使用以下命令分槽:

[root@localhost ~]# redis-cli -h 127.0.0.1 -p 6379 CLUSTER ADDSLOTS {0..5460}

集群排错思路

/usr/local/rvm/gems/ruby-2.4.5/gems/redis-4.1.0/lib/redis/client.rb:124:in `call': ERR Slot 0 is already busy (Redis::CommandError)from /usr/local/rvm/gems/ruby-2.4.5/gems/redis-4.1.0/lib/redis.rb:3282:in `block in cluster'from /usr/local/rvm/gems/ruby-2.4.5/gems/redis-4.1.0/lib/redis.rb:50:in `block in synchronize'from /usr/local/rvm/rubies/ruby-2.4.5/lib/ruby/2.4.0/monitor.rb:214:in `mon_synchronize'from /usr/local/rvm/gems/ruby-2.4.5/gems/redis-4.1.0/lib/redis.rb:50:in `synchronize'from /usr/local/rvm/gems/ruby-2.4.5/gems/redis-4.1.0/lib/redis.rb:3281:in `cluster'from ./redis-trib.rb:212:in `flush_node_config'from ./redis-trib.rb:906:in `block in flush_nodes_config'from ./redis-trib.rb:905:in `each'from ./redis-trib.rb:905:in `flush_nodes_config'from ./redis-trib.rb:1426:in `create_cluster_cmd'from ./redis-trib.rb:1830:in `<main>'

注意 1:
在创建 redis 集群服务时,提示以下错误:

错误提示是说:slot 插槽被占用了、这是因为 搭建集群前时,以前 redis 的旧数据和配置信息没有清理干净。

注意 2:
如果配置文件中没有监听 127.0.0.1,在使用 /etc/init.d/redis_6379.conf start 启动 redis 服务时(停止或重启都是如此),会提示连接 127.0.0.1:6379 失败

解决方法:
使用如下方法启动

[root@localhost ~]# redis-server /etc/redis/6379.conf

使用如下命令关闭

[root@localhost ~]# redis-cli -h 192.168.10.103 -p 6379 shutdown

注意 3:
配置文件中如果没有监听 127.0.0.1 的地址,在连接是需要使用如下方法:

注意 3:
配置文件中如果没有监听 127.0.0.1 的地址,在连接是需要使用如下方法:

这里的 ip 为本机监听的 ip

注意 4:
在做群集的时候各个节点不要监听 127.0.0.1 的地址,否则,在建立群集时会有如下情况

>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.10.101:6379
192.168.10.102:6379
192.168.10.103:6379
Adding replica 192.168.10.104:6379 to 192.168.10.101:6379
Adding replica 192.168.10.105:6379 to 192.168.10.102:6379
Adding replica 192.168.10.106:6379 to 192.168.10.103:6379
M: 4d0690c0de9b90f0fda50a900c0502b4f33c35 192.168.10.101:6379slots:0-5460 (5461 slots) master
M: 9bcde42b8b5f3f1b0c228787c5776a01eaed2e1 192.168.10.102:6379slots:5461-10922 (5462 slots) master
M: 0f786b42a3e7ab0fd738b0d6618d0d1e1f4893 192.168.10.103:6379slots:10923-16383 (5461 slots) master
S: 61165389d4ba128f308ef8d83b2a6fc68e558 192.168.10.104:6379replicates 4d0690c0de9b90f0fda50a900c0502b4f33c35
S: efe896c745ece4001d8c8458b8a67a45a243a29 192.168.10.105:6379replicates 9bcde42b8b5f3f1b0c228787c5776a01eaed2e1
S: 418c2502edac8f9ce4b1540cf89ffbc0f01c 192.168.10.106:6379replicates 0f786b42a3e7ab0fd738b0d6618d0d1e1f4893
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join........

系统会一直停留在这,这是在等待其他节点并到群集中,需要在其他 slave 的主机上接受其 master 才可以

Adding replica 192.168.10.104:6379 to 192.168.10.101:6379
Adding replica 192.168.10.105:6379 to 192.168.10.102:6379
Adding replica 192.168.10.106:6379 to 192.168.10.103:6379

按照这里的提示登录其他slave

127.0.0.1:6379> CLUSTER MEET 192.168.10.101 6379

然后等待连接即可

其他注意事项:

1.redis master 宕机,恢复后不会自动切为主
2.扩容 redis cluster 如果我们大量使用 redis cluster 的话,有一个痛点就是扩容的机器加入集群的时候,分配主从。现在只能使用命令去操作,非常的凌乱。而且如果 redis cluster 是线上集群或者是有数据的话,极其容易丢操作或数据。
3.redis cluster 从节点支持可读的前提下得在执行 readonly 执行,程序读取从节点时也需要执行。一次连接需要执行一次,客户端关闭即失效。
4.redis cluster 启动必须以绝对路径的方式启动,如果不用绝对路径启动,会产生新的 nodes.conf 文件,集群的主从对应关系就会变乱,从而导致集群奔溃。

http://www.lqws.cn/news/526645.html

相关文章:

  • 智慧生产管控数字化平台(源码+文档+讲解+演示)
  • Datax报错:在有总bps限速条件下,单个channel的bps值不能为空,也不能为非正数
  • Flutter 多平台项目开发指南
  • 使用Charles中文版抓包工具进行高效的API调试与性能优化
  • openharmony 性能检测工具
  • [架构之美]Spring Boot 3.5.3新特性解析及JDK21集成
  • Socket 编程 TCP
  • 小程序入门:理解小程序页面配置
  • ZYNQ GP总线深度实战:智能灯光控制器的PS-PL交互艺术
  • 128K 长文本处理实战:腾讯混元 + 云函数 SCF 构建 PDF 摘要生成器
  • 如何解决本地DNS解析失败问题?以连接AWS ElastiCache Redis为例
  • 华曦达港股IPO递表,AI Home生态构建智能生活新蓝图
  • dockercompose快速安装ELK
  • 设计模式 | 原型模式
  • 分布式I/O在风电行业的应用
  • 向量数据库milvus中文全文检索取不到数据的处理办法
  • Python 惰性求值实战:用生成器重构 Sentence 类
  • Milvus中 Collections 级多租户 和 分区级多租户 的区别
  • kubernetes架构原理
  • 【Docker基础】Docker容器管理:docker rm及其参数详解
  • Axure版TDesign 组件库-免费版
  • Ubuntu中使用netcat发送16进制网络数据包
  • android 11.0 打开ALOGV ALOGI ALOGD日志输出的方法
  • git 多用户管理 跨平台
  • 远程玩3A大作要多少帧?ToDesk、向日葵、UU远程性能对决
  • mysql 安装vc++2013 没有权限问题。
  • 使用 DHTMLX Gantt 添加迷你地图:提升大型项目可视化与导航体验
  • 996引擎-假人系统
  • el-select封装下拉加载组件
  • 《量子计算对加密体系的降维打击:RSA2048在Shor算法下的生存时间预测》的终极解析,结合量子算法推演/后量子加密实战/蒙特卡洛预测模型