Redis集群搭建

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介: Redis主从实现读写分离,提升并发能力;哨兵保障高可用,自动故障恢复;分片集群支持海量数据存储与高并发读写,三者结合构建高性能、高可用分布式缓存架构。

1.Redis主从
单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,这里讲一种方案就是搭建主从集群,实现读写分离。
1.1.主从集群结构
下图就是一个简单的Redis主从集群结构:

如图所示,集群中有一个master节点、两个slave节点(现在叫replica)。当我们通过Redis的Java客户端访问主从集群时,应该做好路由:
● 如果是写操作,应该访问master节点,master会自动将数据同步给两个slave节点
● 如果是读操作,建议访问各个slave节点,从而分担并发压力
1.2.搭建主从集群
我们会在同一个虚拟机中利用3个Docker容器来搭建主从集群,容器信息如下:
容器名 角色 IP 映射端口
r1 master 192.168.150.101 7001
r2 slave 192.168.150.101 7002
r3 slave 192.168.150.101 7003
1.2.1.启动多个Redis实例
我们利用课前资料提供的docker-compose文件来构建主从集群:

文件内容如下:
version: "6.2.7"

services:
r1:
image: redis:6.2.7
container_name: r1
network_mode: "host"
entrypoint: ["redis-server", "--port", "7001"]
r2:
image: redis:6.2.7
container_name: r2
network_mode: "host"
entrypoint: ["redis-server", "--port", "7002"]
r3:
image: redis:6.2.7
container_name: r3
network_mode: "host"
entrypoint: ["redis-server", "--port", "7003"]
将其上传至虚拟机的/root/redis目录下:

执行命令,运行集群:
docker-compose up -d
结果:

由于采用的是host模式,我们看不到端口映射。不过能直接在宿主机通过ps命令查看到Redis进程:

1.2.2.建立集群
虽然我们启动了3个Redis实例,但是它们并没有形成主从关系。我们需要通过命令来配置主从关系:

Redis5.0以前

slaveof

Redis5.0以后

replicaof
有临时和永久两种模式:
● 永久生效:在redis.conf文件中利用slaveof命令指定master节点
● 临时生效:直接利用redis-cli控制台输入slaveof命令,指定master节点
我们测试临时模式,首先连接r2,让其以r1为master

连接r2

docker exec -it r2 redis-cli -p 7002

认r1主,也就是7001

slaveof 192.168.150.101 7001
然后连接r3,让其以r1为master

连接r3

docker exec -it r3 redis-cli -p 7003

认r1主,也就是7001

slaveof 192.168.150.101 7001
然后连接r1,查看集群状态:

连接r1

docker exec -it r1 redis-cli -p 7001

查看集群状态

info replication
结果如下:
127.0.0.1:7001> info replication

Replication

role:master
connected_slaves:2
slave0:ip=192.168.150.101,port=7002,state=online,offset=140,lag=1
slave1:ip=192.168.150.101,port=7003,state=online,offset=140,lag=1
master_failover_state:no-failover
master_replid:16d90568498908b322178ca12078114e6c518b86
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:140
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:140
可以看到,当前节点r1:7001的角色是master,有两个slave与其连接:
● slave0:port是7002,也就是r2节点
● slave1:port是7003,也就是r3节点
1.2.3.测试
依次在r1、r2、r3节点上执行下面命令:
set num 123

get num
你会发现,只有在r1这个节点上可以执行set命令(写操作)

其它两个节点只能执行get命令(读操作)。也就是说读写操作已经分离了。

2.Redis哨兵
主从结构中master节点的作用非常重要,一旦故障就会导致集群不可用。那么有什么办法能保证主从集群的高可用性呢?
2.1.哨兵集群介绍
Redis提供了哨兵(Sentinel)机制来监控主从集群监控状态,确保集群的高可用性。
哨兵集群作用原理图:

哨兵的作用如下:
● 状态监控:Sentinel 会不断检查您的master和slave是否按预期工作
● 故障恢复(failover):如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后会成为slave
● 状态通知:Sentinel充当Redis客户端的服务发现来源,当集群发生failover时,会将最新集群信息推送给Redis的客户端
2.2.搭建哨兵集群
首先,我们停掉之前的redis集群:

老版本DockerCompose

docker-compose down

新版本Docker

docker compose down
然后,我们找到课前资料提供的sentinel.conf文件:

其内容如下:
sentinel announce-ip "192.168.150.101"
sentinel monitor hmaster 192.168.150.101 7001 2
sentinel down-after-milliseconds hmaster 5000
sentinel failover-timeout hmaster 60000
说明:
● sentinel announce-ip "192.168.150.101":声明当前sentinel的ip
● sentinel monitor hmaster 192.168.150.101 7001 2:指定集群的主节点信息
○ hmaster:主节点名称,自定义,任意写
○ 192.168.150.101 7001:主节点的ip和端口
○ 2:认定master下线时的quorum值
● sentinel down-after-milliseconds hmaster 5000:声明master节点超时多久后被标记下线
● sentinel failover-timeout hmaster 60000:在第一次故障转移失败后多久再次重试
我们在虚拟机的/root/redis目录下新建3个文件夹:s1、s2、s3:

将课前资料提供的sentinel.conf文件分别拷贝一份到3个文件夹中。
接着修改docker-compose.yaml文件,内容如下:
version: "6.2.7"

services:
r1:
image: redis:6.2.7
container_name: r1
network_mode: "host"
entrypoint: ["redis-server", "--port", "7001"]
r2:
image: redis:6.2.7
container_name: r2
network_mode: "host"
entrypoint: ["redis-server", "--port", "7002", "--slaveof", "192.168.101.68", "7001"]
r3:
image: redis:6.2.7
container_name: r3
network_mode: "host"
entrypoint: ["redis-server", "--port", "7003", "--slaveof", "192.168.101.68", "7001"]
s1:
image: redis:6.2.7
container_name: s1
volumes:

  - /root/redis/s1:/etc/redis
network_mode: "host"
entrypoint: ["redis-sentinel", "/etc/redis/sentinel.conf", "--port", "27001"]

s2:
image: redis:6.2.7
container_name: s2
volumes:

  - /root/redis/s2:/etc/redis
network_mode: "host"
entrypoint: ["redis-sentinel", "/etc/redis/sentinel.conf", "--port", "27002"]

s3:
image: redis:6.2.7
container_name: s3
volumes:

  - /root/redis/s3:/etc/redis
network_mode: "host"
entrypoint: ["redis-sentinel", "/etc/redis/sentinel.conf", "--port", "27003"]

直接运行命令,启动集群:
docker-compose up -d
运行结果:

我们以s1节点为例,查看其运行日志:

Sentinel ID is 8e91bd24ea8e5eb2aee38f1cf796dcb26bb88acf

+monitor master hmaster 192.168.150.101 7001 quorum 2

  • +slave slave 192.168.150.101:7003 192.168.150.101 7003 @ hmaster 192.168.150.101 7001
  • +sentinel sentinel 5bafeb97fc16a82b431c339f67b015a51dad5e4f 192.168.150.101 27002 @ hmaster 192.168.150.101 7001
  • +sentinel sentinel 56546568a2f7977da36abd3d2d7324c6c3f06b8d 192.168.150.101 27003 @ hmaster 192.168.150.101 7001
  • +slave slave 192.168.150.101:7002 192.168.150.101 7002 @ hmaster 192.168.150.101 7001
    可以看到sentinel已经联系到了7001这个节点,并且与其它几个哨兵也建立了链接。哨兵信息如下:
    ● 27001:Sentinel ID是8e91bd24ea8e5eb2aee38f1cf796dcb26bb88acf
    ● 27002:Sentinel ID是5bafeb97fc16a82b431c339f67b015a51dad5e4f
    ● 27003:Sentinel ID是56546568a2f7977da36abd3d2d7324c6c3f06b8d
    2.3.演示failover
    接下来,我们演示一下当主节点故障时,哨兵是如何完成集群故障恢复(failover)的。
    停止r1
    docker stop r1
    登录r2,查看集群状态:

稍微等待一段时间后,会发现sentinel节点触发了failover:
继续查看集群状态发现主节点为r2

3.Redis分片集群
主从模式可以解决高可用、高并发读的问题。但依然有两个问题没有解决:
● 海量数据存储
● 高并发写
要解决这两个问题就需要用到分片集群了。分片的意思,就是把数据拆分存储到不同节点,这样整个集群的存储数据量就更大了。
Redis分片集群的结构如图:

分片集群特征:
● 集群中有多个master,每个master保存不同分片数据 ,解决海量数据存储问题
● 每个master都可以有多个slave节点 ,确保高可用
● master之间通过ping监测彼此健康状态 ,类似哨兵作用
● 客户端请求可以访问集群任意节点,最终都会被转发到数据所在节点
3.1.搭建分片集群
Redis分片集群最少也需要3个master节点,由于我们的机器性能有限,我们只给每个master配置1个slave,形成最小的分片集群:

计划部署的节点信息如下:
容器名 角色 IP 映射端口
r1 master 192.168.150.101 7001
r2 master 192.168.150.101 7002
r3 master 192.168.150.101 7003
r4 slave 192.168.150.101 7004
r5 slave 192.168.150.101 7005
r6 slave 192.168.150.101 7006
3.1.1.集群配置
分片集群中的Redis节点必须开启集群模式,一般在配置文件中添加下面参数:
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
其中有3个我们没见过的参数:
● cluster-enabled:是否开启集群模式
● cluster-config-file:集群模式的配置文件名称,无需手动创建,由集群自动维护
● cluster-node-timeout:集群中节点之间心跳超时时间
一般搭建部署集群肯定是给每个节点都配置上述参数,不过考虑到我们计划用docker-compose部署,因此可以直接在启动命令中指定参数,偷个懒。
在虚拟机的/root目录下新建一个redis-cluster目录,然后在其中新建一个docker-compose.yaml文件,内容如下:
version: "3.2"

services:
r1:
image: redis
container_name: r1
network_mode: "host"
entrypoint: ["redis-server", "--port", "7001", "--cluster-enabled", "yes", "--cluster-config-file", "node.conf"]
r2:
image: redis
container_name: r2
network_mode: "host"
entrypoint: ["redis-server", "--port", "7002", "--cluster-enabled", "yes", "--cluster-config-file", "node.conf"]
r3:
image: redis
container_name: r3
network_mode: "host"
entrypoint: ["redis-server", "--port", "7003", "--cluster-enabled", "yes", "--cluster-config-file", "node.conf"]
r4:
image: redis
container_name: r4
network_mode: "host"
entrypoint: ["redis-server", "--port", "7004", "--cluster-enabled", "yes", "--cluster-config-file", "node.conf"]
r5:
image: redis
container_name: r5
network_mode: "host"
entrypoint: ["redis-server", "--port", "7005", "--cluster-enabled", "yes", "--cluster-config-file", "node.conf"]
r6:
image: redis
container_name: r6
network_mode: "host"
entrypoint: ["redis-server", "--port", "7006", "--cluster-enabled", "yes", "--cluster-config-file", "node.conf"]
注意:使用Docker部署Redis集群,network模式必须采用host
3.1.2.启动集群
进入/root/redis-cluster目录,使用命令启动redis:
docker-compose up -d
启动成功,可以通过命令查看启动进程:
ps -ef | grep redis

结果:

root 4822 4743 0 14:29 ? 00:00:02 redis-server :7002 [cluster]
root 4827 4745 0 14:29 ? 00:00:01 redis-server
:7005 [cluster]
root 4897 4778 0 14:29 ? 00:00:01 redis-server :7004 [cluster]
root 4903 4759 0 14:29 ? 00:00:01 redis-server
:7006 [cluster]
root 4905 4775 0 14:29 ? 00:00:02 redis-server :7001 [cluster]
root 4912 4732 0 14:29 ? 00:00:01 redis-server
:7003 [cluster]
可以发现每个redis节点都以cluster模式运行。不过节点与节点之间并未建立连接。
接下来,我们使用命令创建集群:

进入任意节点容器

docker exec -it r1 bash

然后,执行命令

redis-cli --cluster create --cluster-replicas 1 \
192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003 \
192.168.150.101:7004 192.168.150.101:7005 192.168.150.101:7006
命令说明:
● redis-cli --cluster:代表集群操作命令
● create:代表是创建集群
● --cluster-replicas 1 :指定集群中每个master的副本个数为1
○ 此时节点总数 ÷ (replicas + 1) 得到的就是master的数量n。因此节点列表中的前n个节点就是master,其它节点都是slave节点,随机分配到不同master
输入命令后控制台会弹出下面的信息:

这里展示了集群中master与slave节点分配情况,并询问你是否同意。节点信息如下:
● 7001是master,节点id后6位是da134f
● 7002是master,节点id后6位是862fa0
● 7003是master,节点id后6位是ad5083
● 7004是slave,节点id后6位是391f8b,认ad5083(7003)为master
● 7005是slave,节点id后6位是e152cd,认da134f(7001)为master
● 7006是slave,节点id后6位是4a018a,认862fa0(7002)为master
输入yes然后回车。会发现集群开始创建,并输出下列信息:

接着,我们可以通过命令查看集群状态:
redis-cli -p 7001 cluster nodes
结果:

3.2.Java客户端连接分片集群
RedisTemplate底层同样基于lettuce实现了分片集群的支持,而使用的步骤与哨兵模式基本一致,参考2.5节:
1)引入redis的starter依赖
引入SpringDataRedis的依赖:


org.springframework.boot
spring-boot-starter-data-redis

2)配置分片集群地址
与传统单点模式不同,需要配置每个redis实例的地址,如下:
spring:
redis:
cluster:
nodes:

    - 192.168.150.101:7001
    - 192.168.150.101:7002
    - 192.168.150.101:7003
    - 192.168.150.101:8001
    - 192.168.150.101:8002
    - 192.168.150.101:8003

3)配置读写分离
还要配置读写分离,让java客户端将写请求发送到master节点,读请求发送到slave节点。定义一个bean即可:
@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){
return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}
这个bean中配置的就是读写策略,包括四种:
● MASTER:从主节点读取
● MASTER_PREFERRED:优先从master节点读取,master不可用才读取slave
● REPLICA:从slave节点读取
● REPLICA_PREFERRED:优先从slave节点读取,所有的slave都不可用才读取master

相关文章
|
2月前
|
Java Sentinel 微服务
服务保护、分布式事务
本课程聚焦微服务保护核心技能,涵盖雪崩问题、熔断降级、限流隔离等机制,学习Sentinel实现熔断、降级、限流策略配置,掌握FallbackFactory降级逻辑编写,理解CAP原理与Seata分布式事务,全面提升微服务高可用设计能力。
|
JavaScript 安全 Windows
NPM包的安装、更新、卸载
NPM包的安装、更新、卸载
|
2月前
|
测试技术 数据处理 微服务
基于稳定版量化交易系统开发案例设计的功能需求实现
在数字化时代,量化交易系统需兼顾高效性与稳定性。本文聚焦稳定版系统开发,探讨案例设计与功能需求,涵盖微服务架构、实时行情、信号生成、风控等核心环节,为构建精准、可靠的量化交易体系提供实践指导。
|
2月前
|
存储 Java 编译器
Java泛型类型擦除以及类型擦除带来的问题
Java泛型在编译时会进行类型擦除,所有泛型信息被移除,仅保留原始类型(如Object或限定类型)。例如,List<String>和List<Integer>在运行时均为List。类型检查在编译期完成,针对引用而非对象本身。擦除后通过桥方法解决多态冲突,并自动插入强制转换。静态成员不能使用类的泛型参数,基本类型需用包装类。
|
2月前
|
监控 算法 Unix
Thread.sleep(0) 到底有什么
Thread.Sleep用于让线程暂停执行一段时间,不参与CPU竞争。Sleep(1000)并不保证精确唤醒时间,因系统调度受优先级和资源影响;而Sleep(0)则触发系统立即重新分配CPU,给予其他线程执行机会,避免界面假死。理解其原理有助于优化多线程程序性能与响应性。
|
2月前
|
监控 算法 Unix
Thread.sleep(0) 到底有什么用
Thread.Sleep用于让线程暂停执行一段时间,期间不参与CPU竞争。Sleep(1000)不保证精确唤醒时间,受系统调度影响;而Sleep(0)会触发系统立即重新分配CPU,给其他线程执行机会,避免界面假死。两者作用不可忽视。
|
2月前
|
监控 算法 Unix
Thread.sleep(0) 到底有什么用(读完
本简介旨在简要介绍所提供的内容,突出其核心要点与价值。通过精炼语言,概括主题思想,帮助读者快速理解主要内容,适用于推广、导读或信息传递场景,力求在240字符内清晰传达关键信息。
|
2月前
|
缓存 算法 搜索推荐
线程池
线程池是将多个线程统一管理的“池化”技术,避免频繁创建销毁线程带来的开销。Java中通过`ExecutorService`和`ThreadPoolExecutor`等类实现,核心原理是复用线程、任务队列调度及合理的拒绝策略。`ScheduledThreadPoolExecutor`支持延时与周期性任务,基于`DelayedWorkQueue`实现延迟调度。`Executors`工厂类提供多种线程汛建造方法,如固定大小、缓存型、单线程等,适用于不同并发场景,提升系统性能与资源利用率。
|
2月前
|
关系型数据库 MySQL Java
开发环境搭建
工欲善其事,必先利其器。学习前请确保电脑内存16G以上(建议32G),推荐使用便携显示器分屏开发以提升效率。下载并配置虚拟机(IP:192.168.101.68)、安装VMware、FinalShell远程连接,导入CentOS7虚拟机并启动Docker、MySQL等服务。IDEA中配置JDK11、Maven(3.8.6)及本地仓库,设置编码与自动导包。安装Git并配置账号信息。通过Gitee Fork黑马商城项目,克隆到本地,创建hmall数据库并导入SQL脚本。前端使用nginx部署,启动后访问http://localhost:18080登录测试。
|
2月前
|
canal 消息中间件 关系型数据库
配置数据同步环境
配置Canal+RabbitMQ实现MySQL数据同步,通过开启Binlog行模式、创建专用用户并授权,部署Canal监听指定表变更,将数据实时发送至RabbitMQ指定队列,确保hm-item库中item_sync表的增删改操作同步至消息队列,支持后续数据消费与处理。