目录
1. 引言
本文记录了Redis常用的主从Master/Replica、哨兵Sentinel模式的docker-compose部署以及Spring Redis Lettuce的代码集成配置示例。
集成模式 | 适用场景 | 节点要求 | Spring Data Redis - Lettuce支持 |
---|---|---|---|
Master / Replica 主从复制 | 数据备份 读写分离 | Master: 1 Replica: 1…N | 配置一个节点(Master Or Replica)后自动获取其他节点, 亦可静态指定全部节点, 不支持自动故障切换。 |
Sentinel | 读写分离 高可用HA 自动故障切换Failover | Setinel: >=3 Master: 1 Replica: 1…N | 静态指定全部sentinel节点, 且支持自动故障切换。 |
Cluster | 数据分片 读写分离 高可用HA 自动故障切换Failover 待续… |
2. Master / Replica
主从复制,主负责写,从负责读,并不提供高可用HA及故障切换Failover。
官方文档:https://redis.io/docs/manual/replication
2.1 redis.conf相关配置
redis.conf中核心配置(REPLICATION):
详细配置说明可参见:https://github.com/redis/redis/blob/6.2/redis.conf
# 设置master ip和port
slaveof <masterip> <masterport>
# 设置master密码(master通过requirepass设置)
masterauth <master-password>
# slave与master连接断开或者还处在初始复制阶段时,是否提以供服务
# yes 返回旧数据 | no 返回错误SYNC(除了INFO和SLAVEOF命令)
slave-serve-stale-data yes
# Slave只读模式
# yes 推荐 | no
slave-read-only yes
# master端全量同步full synchronization(无法partial或者初始Slave连接)时,RDB文件是否经过master磁盘
# yes RDB不落盘 | no RDB落盘
repl-diskless-sync no
# diskless延迟同步时长(单位:秒),等待更多Slave到达,避免后到的Slave排队等待下一次RDB传输
# 默认5秒,设置0(即0秒)则立即开始同步
repl-diskless-sync-delay 5
# slave定时向master发送ping的时间间隔(单位:秒),默认10s
# repl-ping-slave-period 10
# slave端是否使用无磁盘记在RDB
# disabled 落盘RDB后再加载| on-empty-db 直接加载 | swapdb RAM拷贝
repl-diskless-load disabled
# 超时时长(单位:秒),需比repl-ping-slave-period长
# The following option sets the replication timeout for:
# 1) Bulk transfer I/O during SYNC, from the point of view of slave.
# 2) Master timeout from the point of view of slaves (data, pings).
# 3) Slave timeout from the point of view of masters (REPLCONF ACK pings).
# repl-timeout 60
# 是否禁用TCP_NODELAY
repl-disable-tcp-nodelay no
# master端记录slave离线后的差异数据的日志大小(避免slave重连后进行全量同步)
# 仅有slave连接时才创建此日志
# repl-backlog-size 1mb
# backlog到期时长(单位:秒),即在指定时间范围内没有slave连接,则清理日志
# 0则表示一直保留
# repl-backlog-ttl 3600
# slave优先级,越小则表示优先级越大(默认100)
# Sentinel根据此优先级选举master,越小则优先被选举
# 0则表示不参与master选举
slave-priority 100
# 设置是否可被Sentinel报告显示:sentinel replicas <master>
# 此设置不影响参与master选举,若不想此replica参与master选举则需通过slave-priority 0进行设置
# replica-announced yes
# 少于指定已连接的slave数量则拒绝write请求
# 例如需要至少3个slave同时在线,并且lag <= 10s
# 默认0即禁用此机制
# min-slaves-to-write 3
# 超过多久未ping成功即为断开连接
# 默认10秒
# min-slaves-max-lag 10
# 特殊网络环境下设置replica的IP和Port
# replica-announce-ip 5.5.5.5
# replica-announce-port 1234
2.2 快速启动(docker-compose)
本示例基于Bitnami系列docker镜像bitnami/redis:6.2.6
:
https://hub.docker.com/r/bitnami/redis
https://github.com/bitnami/bitnami-docker-redis
Docker镜像bitnami/redis:6.2.6配置说明:
配置项(环境变量) | 说明 | 对应redis.conf配置 |
---|---|---|
REDIS_PORT_NUMBER | 当前Redis启动端口 | port <port> |
REDIS_PASSWORD | 当前Redis节点密码 | requirepass <passw> |
REDIS_REPLICATION_MODE | Replication模式,即指定该容器为Master还是Slave,可选值:master | slave | |
REDIS_REPLICA_IP | Slave的声明IP,默认$(get_machine_ip)返回容器IP | replica-announce-ip |
REDIS_REPLICA_PORT | Slave的声明port,默认REDIS_MASTER_PORT_NUMBER | replica-announce-port |
REDIS_MASTER_HOST | Master IP,用于Slave连接Master | slaveof <masterip> <masterport> |
REDIS_MASTER_PORT_NUMBER | Master Port,用于Slave连接Master,默认6379 | slaveof <masterip> <masterport> |
REDIS_MASTER_PASSWORD | Master 密码,用于Slave连接Master(亦可通过REDIS_MASTER_PASSWORD_FILE挂载密码内容文件) | masterauth <master-password> |
节点规划:
启动节点 | 启动节点IP | 角色 | Redis映射Port |
---|---|---|---|
ubuntu-server-1 | 192.168.3.101 | master | 6379 |
ubuntu-server-2 | 192.168.3.102 | slave | 6381 |
Master docker-compose.yaml:
version: '2'
services:
redis-master:
image: bitnami/redis:6.2.6
container_name: redis-master
# 使用宿主机网络
network_mode: host
ports:
- '6379'
volumes:
# 挂载数据目录
- ./redis-data:/bitnami/redis/data
environment:
# 当前Redis自身的端口、密码等设置
- REDIS_PORT_NUMBER=6379
- REDIS_PASSWORD=mypassw123456
# 当前Redis启动模式(master / slave)
- REDIS_REPLICATION_MODE=master
# 设置时区
- TZ=Asia/Shanghai
Replica(即Slave) docker-compose.yaml:
version: '2'
services:
redis-replica:
image: bitnami/redis:6.2.6
container_name: redis-replica
# 使用宿主机网络
network_mode: host
ports:
- '6381'
volumes:
# 挂载数据目录
- ./redis-data:/bitnami/redis/data
environment:
# 当前Redis自身的端口、密码等设置
- REDIS_PORT_NUMBER=6381
- REDIS_PASSWORD=mypassw123456
# 当前Redis启动模式(master / slave)
- REDIS_REPLICATION_MODE=slave
# 此处配置对应Master相关配置(IP、Port、Password),可根据环境适当调整
- REDIS_MASTER_HOST=192.168.3.101
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_PASSWORD=mypassw123456
# 此处配置对应当前Replica的可被外部访问的声明IP和Port,可根据环境适当调整
- REDIS_REPLICA_IP=192.168.3.102
- REDIS_REPLICA_PORT=6381
# 设置时区
- TZ=Asia/Shanghai
分别在各自节点通过docker-compose up -d
即可启动Redis Master和Slave节点。
docker-compose up -d
需要特别注意:
- 此模式下Master仅有一个,后续可根据需要扩展添加新的Replica节点。
- Master和Replica的
密码(REDIS_PASSWORD、REDIS_MASTER_PASSWORD)需全部一样
,否则Lettuce库无法分别设置密码。 - 可通过
REDIS_REPLICA_IP、REDIS_REPLICA_PORT
声明Replica的IP和Port(适用于特殊网络环境,例如覆盖docker容器内部IP与Port为外部可访问的IP和Port),例如下图中没有正确设置IP和Port则通过info replication命令发现的即是Docker容器的内部IP,是无法直接被外部程序直接访问的。
验证安装结果:
连接redis容器,执行如下命令查看节点状态:
# 查看Master/Replica信息
info replication
# 查询当前节点角色(master/replica)
role
亦可直接在Master上新加个Key,观察Replica是否自动同步包含相同的Key,若包含相同的Key则说明Master-Replica部署成功。
2.3 SpringBoot Redis代码集成
示例程序依赖Spring Boot 2.6.6(spring-boot-starter-data-redis - Lettuce实现),
旨在实现Redis读写分离的场景
。
配置文件application.yml示例
spring:
# Spring Data Redis配置
redis:
client-type: lettuce
# 此处仅配置一个Redis节点即可(Master Or Replica均可),Lettuce会根据info replication命令自定发现其他节点
host: 192.168.3.101
port: 6379
password: mypassw123456
database: 0
# lettuce连接池配置
lettuce:
pool:
enabled: true
max-active: 8
max-idle: 8
min-idle: 5
time-between-eviction-runs: 30s
max-wait: 5s
shutdown-timeout: 100ms
配置代码示例
开启Lettuce客户端读写分离配置代码示例:
@Configuration
public class SpringRedisConfig {
/**
* 开启Lettuce客户端读写分离配置(Write to Master, Read from Replica)
*/
@Bean
public LettuceClientConfigurationBuilderCustomizer lettuceClientConfigurationBuilderCustomizer() {
return lettuceClientConfigurationBuilder -> {
//从replica进行read操作(若replica不可用则回退到从master执行read操作)
lettuceClientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
};
}
}
若无法通过一个Redis节点自动发现其他节点,例如通过info replication命令发现的为内部不可访问的Ip和Port、未正确设置replica-announce-ip和replica-announce-port等,则亦可以静态指定Redis相关节点(可被程序访问到的连接信息),配置示例代码如下:
@Configuration
public class SpringRedisConfig {
/**
* 自定义Lettuce连接工厂,
* 静态指定Redis节点信息,
* 开启Lettuce客户端读写分离配置(Write to Master, Read from Replica)
*/
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
//从replica进行read操作(若replica不可用则回退到从master执行read操作)
.readFrom(ReadFrom.REPLICA_PREFERRED)
.build();
//静态指定Redis节点连接信息(声明时可先指定Master节点信息)
RedisStaticMasterReplicaConfiguration staticMasterReplicaConfiguration = new RedisStaticMasterReplicaConfiguration("192.168.3.101", 6379);
staticMasterReplicaConfiguration.setPassword("mypassw123456");
//添加其他Replica节点信息
staticMasterReplicaConfiguration.addNode("192.168.3.102", 6381);
return new LettuceConnectionFactory(staticMasterReplicaConfiguration, clientConfig);
}
}
注:
静态指定IP这种方式无法使用Redis Pub/Sub功能。
ERROR org.springframework.data.redis.listener.RedisMessageListenerContainer - Connection failure occurred. Restarting subscription task after 5000 ms
具体说明可参见:
https://docs.spring.io/spring-data/redis/docs/current/reference/html/#redis:write-to-master-read-from-replica
验证程序执行结果
Lettuce通过info replication
自动发现节点日志如下:
Lettuce执行读写分离日志如下:
3. Sentinel(哨兵)
Sentinel提供高可用的Master/Replica集群部署,
主从复制,主负责写,从负责读,并配合客户端可提供高可用HA及故障切换Failover。
官方文档:https://redis.io/docs/manual/sentinel/
Sentinel(独立于Redis)为可单独启动的进程,同样支持分布式部署,其主要功能如下:
- 监控 Master、Replica健康状态
- 通过API向用户、程序 通知 Master、Replica的异常状态
- 自动故障切换,即当Sentinel检测到Master异常,即开启Failover进程
- 从Replica中选举1个为新的Master
- 通知其他Replica重新配置(重新redis.conf、sentinel.conf文件)使用新选举的Master
- 通知其他连接对应Redis服务的应用程序重新配置使用新的连接地址(Master, Replica)
- 配置提供者,可作为Redis客户端Client端服务发现的权限来源提供者。
3.1 sentinel.conf配置说明
Sentinel启动时需要提供对应的配置文件,通常名称为sentinel.conf:
# 启动方式1:通过redis-sentinel命令启动
redis-sentinel /path/to/sentinel.conf
# 启动方式2:通过redis-server命令以Sentinel模式启动
redis-server /path/to/sentinel.conf --sentinel
Sentinel亦会将状态信息保存到此配置文件中,Sentinel重启后会加载此文件。
sentinel.conf核心配置说明
详细配置说明可参见:https://github.com/redis/redis/blob/6.2/sentinel.conf
# Sentinel启动端口
port 26379
# 保护模式(默认关闭,即允许除localhost外的访问)
protected-mode no
# daemonized 守护进程启动
daemonize no
# daemonize启动时会将pid写入此文件
pidfile /var/run/redis-sentinel.pid
# 日志文件目录,空则输出到标准输出流。
logfile ""
# 声明Sentinel的IP和Port,适用于特殊网络环境下设置Sentinel的IP和Port
# sentinel announce-ip <ip>
# sentinel announce-port <port>
# 工作目录
dir /tmp
# =======================================================================
# ======================= Sentinel核心配置 ===============================
# =======================================================================
# 格式:sentinel monitor <master-name> <ip> <redis-port> <quorum>
# master-name格式:[A-z0-9.-_]
# 设置sentinel监控的集群(通过集群名<master-name>进行区分)的Master连接信息,
# 无需提供Replica信息,sentinel会自动发现其他Replica节点,
# 并且仅当至少指定数量(<quorum>)的sentinel节点认为Master节点不可用S_DOWN,才会真正认为Master异常O_DOWN(Objectively Down),
# 并且仅当sentinel节点数量过半(与<quorum>无关)才会真正触发Failover(选举新的Master节点)
sentinel monitor mymaster 127.0.0.1 6379 2
# 格式:sentinel auth-pass <master-name> <password>
# 格式:sentinel auth-user <master-name> <username>
# 设置被监控的Redis集群的连接密码信息(Master/Replica密码需相同)
# sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
# 格式:sentinel down-after-milliseconds <master-name> <milliseconds>
# 设置Master不可连接超过指定时间后,即认为Master异常S_DOWN(Subjectively Down)
# 默认30秒
sentinel down-after-milliseconds mymaster 30000
# 设置sentinel自身的密码(多Sentinel需密码相同)
# requirepass <password>
# sentinel sentinel-user <username>
# 格式:sentinel parallel-syncs <master-name> <numreplicas>
# 设置同时向新选举的Master进行同步操作的的Replica数量,
# Replica在同步过程中存在阻塞,影响查询操作,
# 可以使用较低数值减少查询阻塞(保留多余的Replica依旧提供查询服务)
sentinel parallel-syncs mymaster 1
# 格式:sentinel failover-timeout <master-name> <milliseconds>
# 设置Failover的超时时长,默认3分钟。
sentinel failover-timeout mymaster 180000
3.2 快速启动(docker-compose)
本示例基于Bitnami系列docker镜像
bitnami/redis:6.2.6
此镜像同之前Master/Replica部署使用的Redis镜像相同bitnami/redis-sentinel:6.2.6
https://hub.docker.com/r/bitnami/redis-sentinel
https://github.com/bitnami/bitnami-docker-redis-sentinel
Docker镜像bitnami/redis-sentinel:6.2.6配置说明:
配置项(环境变量) | 说明 | 对应sentinel.conf配置 |
---|---|---|
REDIS_MASTER_SET | 待监控的Redis Master名称, 默认mymaster | sentinel monitor <master-name> <ip> <redis-port> <quorum> |
REDIS_MASTER_HOST | 待监控的Redis Master IP | sentinel monitor <master-name> <ip> <redis-port> <quorum> |
REDIS_MASTER_PORT_NUMBER | 待监控的Redis Master端口, 默认6379 | sentinel monitor <master-name> <ip> <redis-port> <quorum> |
REDIS_SENTINEL_QUORUM | 即多少个Sentinel实例检测到Master异常S_DOWN才认为Master真正不可达O_DOWN, 默认2 | sentinel monitor <master-name> <ip> <redis-port> <quorum> |
REDIS_MASTER_PASSWORD | 被监控的Redis Master的连接密码 | sentinel auth-pass <master-name> <password> |
REDIS_MASTER_USER | 被监控的Redis Master的连接用户名 | sentinel auth-user <master-name> <username> |
REDIS_SENTINEL_PORT_NUMBER | Sentinel启动端口, 默认26379 | port <sentinel-port> |
REDIS_SENTINEL_PASSWORD | Sentinel自身的认证密码 | |
REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS | 即Master多久不可用才被认为异常S_DOWN, 默认60000(1分钟) | sentinel down-after-milliseconds <master-name><milliseconds> |
REDIS_SENTINEL_FAILOVER_TIMEOUT | Failover超时, 默认180000(3分钟) | sentinel failover-timeout <master-name> <milliseconds> |
REDIS_SENTINEL_ANNOUNCE_IP | 声明Sentinel的IP,适用于特殊网络环境下设置Sentinel的IP | sentinel announce-ip <ip> |
REDIS_SENTINEL_ANNOUNCE_PORT | 声明Sentinel的Port,适用于特殊网络环境下设置Sentinel的Port, 默认使用REDIS_SENTINEL_PORT_NUMBER配置 | sentinel announce-port <port> |
节点规划:
启动节点 | 启动节点IP | 角色 | Redis映射Port |
---|---|---|---|
ubuntu-server-1 | 192.168.3.101 | master + sentinel | redis: 6379 sentinel: 26379 |
ubuntu-server-2 | 192.168.3.102 | slave + sentinel | redis: 6381 sentinel: 26381 |
ubuntu-server-2 | 192.168.3.102 | slave + sentinel | redis: 6382 sentinel: 26382 |
方式1 - 使用环境变量配置【此方式有问题,若不感兴趣可直接跳到 - 方式2】
注:
使用此方式部署后,sentinel在重启后会出现问题,
实际部署可采用 - 方式2。
Master docker-compose.yaml:
version: '2'
services:
redis-master:
image: bitnami/redis:6.2.6
container_name: redis-master
# 使用宿主机网络
network_mode: host
ports:
- '6379'
volumes:
# 挂载数据目录
- ./redis-data:/bitnami/redis/data
environment:
# 当前Replica自身的端口、密码等设置
- REDIS_PORT_NUMBER=6379
- REDIS_PASSWORD=mypassw123456
# 当前Redis启动模式(master / slave)
- REDIS_REPLICATION_MODE=master
# 此处配置对应当前Replica的可被外部访问的声明IP和Port,可根据环境适当调整
# 在Master Down掉后再重启便会成为Slave,此时需要用到此配置
- REDIS_REPLICA_IP=192.168.3.101
- REDIS_REPLICA_PORT=6379
# 设置时区
- TZ=Asia/Shanghai
redis-sentinel:
image: bitnami/redis-sentinel:6.2.6
container_name: redis-sentinel
# 使用宿主机网络
network_mode: host
ports:
- '26379'
environment:
# 设置sentinel启动端口、认证密码等
- REDIS_SENTINEL_PORT_NUMBER=26379
- REDIS_SENTINEL_PASSWORD=mypassw123456
# 设置被监控的Redis Maser信息
- REDIS_MASTER_SET=luo-sentinel-master
- REDIS_MASTER_HOST=192.168.3.101
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_SENTINEL_QUORUM=2
- REDIS_MASTER_PASSWORD=mypassw123456
# 设置Sentinel S_DOWN检测时间(即超过多久未收到PING响应则认为异常)
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=5000
# 此处配置对应当前Sentinel的可被外部访问的声明IP和Port,可根据环境适当调整
- REDIS_SENTINEL_ANNOUNCE_IP=192.168.3.101
- REDIS_SENTINEL_ANNOUNCE_PORT=26379
# 设置时区
- TZ=Asia/Shanghai
Replica-1 docker-compose.yaml:
version: '2'
services:
redis-replica:
image: bitnami/redis:6.2.6
container_name: redis-replica-1
# 使用宿主机网络
network_mode: host
ports:
- '6381'
volumes:
- ./redis-data:/bitnami/redis/data
environment:
# 当前Redis自身的端口、密码等设置
- REDIS_PORT_NUMBER=6381
- REDIS_PASSWORD=mypassw123456
# REDIS启动模式(master/slave)
- REDIS_REPLICATION_MODE=slave
# 此处配置对应Master相关配置(IP、Port、Password),可根据环境适当调整
- REDIS_MASTER_HOST=192.168.3.101
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_PASSWORD=mypassw123456
# 此处配置对应当前Replica的可被外部访问的声明IP和Port,可根据环境适当调整
- REDIS_REPLICA_IP=192.168.3.102
- REDIS_REPLICA_PORT=6381
# 设置时区
- TZ=Asia/Shanghai
redis-sentinel:
image: bitnami/redis-sentinel:6.2.6
container_name: redis-sentinel-1
# 使用宿主机网络
network_mode: host
ports:
- '26381'
environment:
# 设置sentinel启动端口、认证密码
- REDIS_SENTINEL_PORT_NUMBER=26381
- REDIS_SENTINEL_PASSWORD=mypassw123456
# 设置被监控的Redis Maser信息
- REDIS_MASTER_SET=luo-sentinel-master
- REDIS_MASTER_HOST=192.168.3.101
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_SENTINEL_QUORUM=2
- REDIS_MASTER_PASSWORD=mypassw123456
# 设置Sentinel S_DOWN检测时间(即超过多久未收到PING响应则认为异常)
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=5000
# 此处配置对应当前Sentinel的可被外部访问的声明IP和Port,可根据环境适当调整
- REDIS_SENTINEL_ANNOUNCE_IP=192.168.3.102
- REDIS_SENTINEL_ANNOUNCE_PORT=26381
# 设置时区
- TZ=Asia/Shanghai
Replica-2 docker-compose.yaml:
version: '2'
services:
redis-replica:
image: bitnami/redis:6.2.6
container_name: redis-replica-2
# 使用宿主机网络
network_mode: host
ports:
- '6382'
volumes:
- ./redis-data:/bitnami/redis/data
environment:
# 当前Redis自身的端口、密码等设置
- REDIS_PORT_NUMBER=6382
- REDIS_PASSWORD=mypassw123456
# REDIS启动模式(master/slave)
- REDIS_REPLICATION_MODE=slave
# 此处配置对应Master相关配置(IP、Port、Password),可根据环境适当调整
- REDIS_MASTER_HOST=192.168.3.101
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_PASSWORD=mypassw123456
# 此处配置对应当前Replica的可被外部访问的声明IP和Port,可根据环境适当调整
- REDIS_REPLICA_IP=192.168.3.102
- REDIS_REPLICA_PORT=6382
# 设置时区
- TZ=Asia/Shanghai
redis-sentinel:
image: bitnami/redis-sentinel:6.2.6
container_name: redis-sentinel-2
# 使用宿主机网络
network_mode: host
ports:
- '26382'
environment:
# 设置sentinel启动端口、认证密码
- REDIS_SENTINEL_PORT_NUMBER=26382
- REDIS_SENTINEL_PASSWORD=mypassw123456
# 设置被监控的Redis Maser信息
- REDIS_MASTER_SET=luo-sentinel-master
- REDIS_MASTER_HOST=192.168.3.101
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_SENTINEL_QUORUM=2
- REDIS_MASTER_PASSWORD=mypassw123456
# 设置Sentinel S_DOWN检测时间(即超过多久未收到PING响应则认为异常)
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=5000
# 此处配置对应当前Sentinel的可被外部访问的声明IP和Port,可根据环境适当调整
- REDIS_SENTINEL_ANNOUNCE_IP=192.168.3.102
- REDIS_SENTINEL_ANNOUNCE_PORT=26382
# 设置时区
- TZ=Asia/Shanghai
此种方式部署后,在Sentinel重启后,Sentinel状态异常如下图:
之后Master再次挂掉后,既无法选取新的Master,选举Master异常日志如下:
由于Sentinel会重写sentinel.conf文件,猜测该文件有持久化的作用,
而使用此方法每次重启后持久化状态丢失,
所以最终调整方案将此配置文件挂载出来,可参见方式2。
方式2 - 挂载sentinel.conf配置文件
该方式通过自定义sentinel.conf配置文件并挂载进容器对应位置,
在重启sentinel容器后,可重复读取之前已被sentinel修改过的sentinel.conf文件。
Master docker-compose.yaml:
version: '2'
services:
redis-master:
image: bitnami/redis:6.2.6
container_name: redis-master
# 使用宿主机网络
network_mode: host
ports:
- '6379'
volumes:
# 挂载数据目录
- ./redis-data:/bitnami/redis/data
environment:
# 当前Redis自身的端口、密码等设置
- REDIS_PORT_NUMBER=6379
- REDIS_PASSWORD=mypassw123456
# 当前Redis启动模式(master / slave)
- REDIS_REPLICATION_MODE=master
# 此处配置对应当前Replica的可被外部访问的声明IP和Port,可根据环境适当调整
# 在Master Down掉后再重启便会成为Slave,此时需要用到此配置
- REDIS_REPLICA_IP=192.168.3.101
- REDIS_REPLICA_PORT=6379
# 设置时区
- TZ=Asia/Shanghai
redis-sentinel:
image: bitnami/redis-sentinel:6.2.6
container_name: redis-sentinel
# 使用宿主机网络
network_mode: host
ports:
- '26379'
volumes:
# 挂载sentinel配置文件./redis-sentinel/conf/sentinel.conf
- ./sentinel-data:/bitnami
environment:
# 设置时区
- TZ=Asia/Shanghai
Master ./sentinel-data/redis-sentinel/conf/sentinel.conf
# Sentinel启动端口
port 26379
# 绑定地址(任意IP V4均可)
bind 0.0.0.0
# 保护模式(默认关闭,即允许除localhost外的访问)
daemonize no
# 设置sentinel自身的密码(多Sentinel需密码相同)
requirepass "mypassw123456"
# daemonize启动时会将pid写入此文件
pidfile "/opt/bitnami/redis-sentinel/tmp/redis-sentinel.pid"
# 日志文件目录,空则输出到标准输出流。
logfile ""
# 工作目录
dir "/tmp"
# =======================================================================
# ======================= Sentinel核心配置 ===============================
# =======================================================================
# 格式:sentinel monitor <master-name> <ip> <redis-port> <quorum>
# master-name格式:[A-z0-9.-_]
# 设置sentinel监控的集群(通过集群名<master-name>进行区分)的Master连接信息,
# 无需提供Replica信息,sentinel会自动发现其他Replica节点,
# 并且仅当至少指定数量(<quorum>)的sentinel节点认为Master节点不可用S_DOWN,才会真正认为Master异常O_DOWN(Objectively Down),
# 并且仅当sentinel节点数量过半(与<quorum>无关)才会真正触发Failover(选举新的Master节点)
sentinel monitor luo-sentinel-master 192.168.3.101 6379 2
# 格式:sentinel down-after-milliseconds <master-name> <milliseconds>
# 设置Master不可连接超过指定时间后,即认为Master异常S_DOWN(Subjectively Down)
# 默认30秒
sentinel down-after-milliseconds luo-sentinel-master 5000
# 格式:sentinel auth-pass <master-name> <password>
# 格式:sentinel auth-user <master-name> <username>
# 设置被监控的Redis集群的连接密码信息(Master/Replica密码需相同)
sentinel auth-pass luo-sentinel-master mypassw123456
# 声明Sentinel的IP和Port,适用于特殊网络环境下设置Sentinel的IP和Port
sentinel announce-ip "192.168.3.101"
sentinel announce-port 26379
# 其他默认配置
sentinel deny-scripts-reconfig yes
sentinel resolve-hostnames yes
sentinel announce-hostnames no
acllog-max-len 128
Replica-1 docker-compose.yaml:
version: '2'
services:
redis-replica:
image: bitnami/redis:6.2.6
container_name: redis-replica-1
# 使用宿主机网络
network_mode: host
ports:
- '6381'
volumes:
- ./redis-data:/bitnami/redis/data
environment:
# 当前Redis自身的端口、密码等设置
- REDIS_PORT_NUMBER=6381
- REDIS_PASSWORD=mypassw123456
# 当前Redis启动模式(master / slave)
- REDIS_REPLICATION_MODE=slave
# 此处配置对应Master相关配置(IP、Port、Password),可根据环境适当调整
- REDIS_MASTER_HOST=192.168.3.101
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_PASSWORD=mypassw123456
# 此处配置对应当前Replica的可被外部访问的声明IP和Port,可根据环境适当调整
- REDIS_REPLICA_IP=192.168.3.102
- REDIS_REPLICA_PORT=6381
# 设置时区
- TZ=Asia/Shanghai
redis-sentinel:
image: bitnami/redis-sentinel:6.2.6
container_name: redis-sentinel-1
# 使用宿主机网络
network_mode: host
ports:
- '26381'
volumes:
# 挂载sentinel配置文件./redis-sentinel/conf/sentinel.conf
- ./sentinel-data:/bitnami
environment:
# 设置时区
- TZ=Asia/Shanghai
Replica-1 ./sentinel-data/redis-sentinel/conf/sentinel.conf
# Sentinel启动端口
port 26381
# 绑定地址(任意IP V4均可)
bind 0.0.0.0
# 保护模式(默认关闭,即允许除localhost外的访问)
daemonize no
# 设置sentinel自身的密码(多Sentinel需密码相同)
requirepass "mypassw123456"
# daemonize启动时会将pid写入此文件
pidfile "/opt/bitnami/redis-sentinel/tmp/redis-sentinel.pid"
# 日志文件目录,空则输出到标准输出流。
logfile ""
# 工作目录
dir "/tmp"
# =======================================================================
# ======================= Sentinel核心配置 ===============================
# =======================================================================
# 格式:sentinel monitor <master-name> <ip> <redis-port> <quorum>
# master-name格式:[A-z0-9.-_]
# 设置sentinel监控的集群(通过集群名<master-name>进行区分)的Master连接信息,
# 无需提供Replica信息,sentinel会自动发现其他Replica节点,
# 并且仅当至少指定数量(<quorum>)的sentinel节点认为Master节点不可用S_DOWN,才会真正认为Master异常O_DOWN(Objectively Down),
# 并且仅当sentinel节点数量过半(与<quorum>无关)才会真正触发Failover(选举新的Master节点)
sentinel monitor luo-sentinel-master 192.168.3.101 6379 2
# 格式:sentinel down-after-milliseconds <master-name> <milliseconds>
# 设置Master不可连接超过指定时间后,即认为Master异常S_DOWN(Subjectively Down)
# 默认30秒
sentinel down-after-milliseconds luo-sentinel-master 5000
# 格式:sentinel auth-pass <master-name> <password>
# 格式:sentinel auth-user <master-name> <username>
# 设置被监控的Redis集群的连接密码信息(Master/Replica密码需相同)
sentinel auth-pass luo-sentinel-master mypassw123456
# 声明Sentinel的IP和Port,适用于特殊网络环境下设置Sentinel的IP和Port
sentinel announce-ip "192.168.3.102"
sentinel announce-port 26381
# 其他默认配置
sentinel deny-scripts-reconfig yes
sentinel resolve-hostnames yes
sentinel announce-hostnames no
acllog-max-len 128
Replica-2 docker-compose.yaml:
version: '2'
services:
redis-replica:
image: bitnami/redis:6.2.6
container_name: redis-replica-2
# 使用宿主机网络
network_mode: host
ports:
- '6382'
volumes:
- ./redis-data:/bitnami/redis/data
environment:
# 当前Redis自身的端口、密码等设置
- REDIS_PORT_NUMBER=6382
- REDIS_PASSWORD=mypassw123456
# 当前Redis启动模式(master / slave)
- REDIS_REPLICATION_MODE=slave
# 此处配置对应Master相关配置(IP、Port、Password),可根据环境适当调整
- REDIS_MASTER_HOST=192.168.3.101
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_PASSWORD=mypassw123456
# 此处配置对应当前Replica的可被外部访问的声明IP和Port,可根据环境适当调整
- REDIS_REPLICA_IP=192.168.3.102
- REDIS_REPLICA_PORT=6382
# 设置时区
- TZ=Asia/Shanghai
redis-sentinel:
image: bitnami/redis-sentinel:6.2.6
container_name: redis-sentinel-2
# 使用宿主机网络
network_mode: host
ports:
- '26382'
volumes:
# 挂载sentinel配置文件./redis-sentinel/conf/sentinel.conf
- ./sentinel-data:/bitnami
environment:
# 设置时区
- TZ=Asia/Shanghai
Replica-2 ./sentinel-data/redis-sentinel/conf/sentinel.conf
# Sentinel启动端口
port 26382
# 绑定地址(任意IP V4均可)
bind 0.0.0.0
# 保护模式(默认关闭,即允许除localhost外的访问)
daemonize no
# 设置sentinel自身的密码(多Sentinel需密码相同)
requirepass "mypassw123456"
# daemonize启动时会将pid写入此文件
pidfile "/opt/bitnami/redis-sentinel/tmp/redis-sentinel.pid"
# 日志文件目录,空则输出到标准输出流。
logfile ""
# 工作目录
dir "/tmp"
# =======================================================================
# ======================= Sentinel核心配置 ===============================
# =======================================================================
# 格式:sentinel monitor <master-name> <ip> <redis-port> <quorum>
# master-name格式:[A-z0-9.-_]
# 设置sentinel监控的集群(通过集群名<master-name>进行区分)的Master连接信息,
# 无需提供Replica信息,sentinel会自动发现其他Replica节点,
# 并且仅当至少指定数量(<quorum>)的sentinel节点认为Master节点不可用S_DOWN,才会真正认为Master异常O_DOWN(Objectively Down),
# 并且仅当sentinel节点数量过半(与<quorum>无关)才会真正触发Failover(选举新的Master节点)
sentinel monitor luo-sentinel-master 192.168.3.101 6379 2
# 格式:sentinel down-after-milliseconds <master-name> <milliseconds>
# 设置Master不可连接超过指定时间后,即认为Master异常S_DOWN(Subjectively Down)
# 默认30秒
sentinel down-after-milliseconds luo-sentinel-master 5000
# 格式:sentinel auth-pass <master-name> <password>
# 格式:sentinel auth-user <master-name> <username>
# 设置被监控的Redis集群的连接密码信息(Master/Replica密码需相同)
sentinel auth-pass luo-sentinel-master mypassw123456
# 声明Sentinel的IP和Port,适用于特殊网络环境下设置Sentinel的IP和Port
sentinel announce-ip "192.168.3.102"
sentinel announce-port 26382
# 其他默认配置
sentinel deny-scripts-reconfig yes
sentinel resolve-hostnames yes
sentinel announce-hostnames no
acllog-max-len 128
分别在各自节点通过docker-compose up -d
即可启动Redis Master和Slave节点。
docker-compose up -d
需要特别注意:
- 此模式下Master仅有一个,后续可根据需要扩展添加新的Replica节点。
- Master和Replica的
密码(REDIS_PASSWORD、REDIS_MASTER_PASSWORD)需全部一样
,否则Lettuce库无法分别设置密码。 - 可通过
REDIS_REPLICA_IP、REDIS_REPLICA_PORT
声明Replica的IP和Port(适用于特殊网络环境,例如覆盖docker容器内部IP与Port为外部可访问的IP和Port),例如下图中没有正确设置IP和Port则通过info replication命令发现的即是Docker容器的内部IP,是无法直接被外部程序直接访问的。
注:上面几条和之前Master/Replica模式相同,下面的为Sentinel需要注意的。
- 多个Sentinel的自身认证密码
requirepass
需全部一样。 - 可通过
sentinel announce-ip、sentinel announce-port
声明Sentinel的IP和Port(适用于特殊网络环境,例如覆盖docker容器内部IP与Port为外部可访问的IP和Port)。
验证安装结果:
连接Sentinel容器,执行如下命令查看节点状态:
# 进入Sentinel Docker容器,通过redis-cli连接Sentinel
redis-cli -h 127.0.0.1 -p 26379 -a mypassw123456
# 然后执行如下命令
# 查看Sentinel监控的Master信息
# 其中的luo-sentinel-master对应之前docker-compose.yaml文件中设置的Master名称
sentinel master luo-sentinel-master
# 查看连接到Master的Replica信息
sentinel replicas mymaster
# 查看其它Sentinel节点信息
sentinel sentinels mymaster
3.3 SpringBoot Redis代码集成
示例程序依赖Spring Boot 2.6.6(spring-boot-starter-data-redis - Lettuce实现),
旨在实现Redis读写分离的场景
。
配置文件application.yml示例
spring:
# Spring Data Redis配置
redis:
sentinel:
# sentinel Master名称
master: luo-sentinel-master
# sentinel连接密码
password: mypassw123456
# sentinel节点
nodes:
- 192.168.3.101:26379
- 192.168.3.102:26381
- 192.168.3.102:26382
# 此处设置Redis连接密码
password: mypassw123456
client-type: lettuce
database: 0
# lettuce连接池配置
lettuce:
pool:
enabled: true
max-active: 8
max-idle: 8
min-idle: 5
time-between-eviction-runs: 30s
max-wait: 5s
shutdown-timeout: 100ms
配置代码示例
开启Lettuce客户端读写分离配置代码示例:
@Configuration
public class SpringRedisConfig {
/**
* 开启Lettuce客户端读写分离配置(Write to Master, Read from Replica)
*/
@Bean
public LettuceClientConfigurationBuilderCustomizer lettuceClientConfigurationBuilderCustomizer() {
return lettuceClientConfigurationBuilder -> {
//从replica进行read操作(若replica不可用则回退到从master执行read操作)
lettuceClientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
};
}
}
验证程序执行结果
Lettuce通过sentinel master
和sentinel slaves(>=5.0后为sentinel replicas)
自动发现节点日志如下:
Lettuce执行读写分离日志如下:
3.4 测试Sentinel自动故障切换
我测试的方法比较暴力,我直接把Master节点192.168.3.101上的Redis Master和Sentinel容器直接停掉,
docker-compose down
此观察Replica节点192.168.3.102上的Sentinel容器日志:
# 查看其它任一存活的sentinel日志(本文中提到的redis-sentinel-1和redis-sentinel-2均可)
docker logs -f redis-sentinel-2
在切换过程中也可以通过sentinel master | replicas
查看对应的节点状态:
Lettuce监听Sentinel自动故障切换日志如下:
Sentinel间每隔2秒过向Channel频道
__sentinel__:hello
发送消息(ip, port, runid、current config等)实现自动发现,
且每个Sentinel都订阅所有Master / Replica的对应Channel频道__sentinel__:hello
,并且Sentinel收到新的配置版本后会自动覆盖旧版本。
且Lettuce订阅sentinel对应的相关Channel,如+sdown, +odown, +switch-master,…,通过订阅相关频道以便第一时间感知节点变化,
且配合sentinel master, sentinel replicas等命令第一时间获取最新的Master / Replica分布,实现自动切换新的Master和Replica。
Lettuce查询新的Master / Replica信息:
之后再通过Lettuce执行Redis请求,可发现已自动完成Master / Replica切换,如下图:
自己也可以多试几次切换看看效果。
后续
后续会单独再开一遍博客记录Cluster模式…
参考:
https://docs.spring.io/spring-boot/docs/2.6.6/reference/htmlsingle/#application-properties.data.spring.redis.client-name
https://docs.spring.io/spring-boot/docs/2.6.6/reference/htmlsingle/#data.nosql.redis
https://docs.spring.io/spring-data/redis/docs/current/reference/html/#redis
https://www.baeldung.com/spring-data-redis-properties
https://www.baeldung.com/spring-boot-redis-cache
https://www.baeldung.com/spring-embedded-redis
https://www.vinsguru.com/redis-master-slave-with-spring-boot
https://docs.spring.io/spring-data/redis/docs/current/reference/html/#redis:write-to-master-read-from-replica
https://programs.wiki/wiki/springboot-redis-master-slave-replication-sentinel-and-read-write-separation.html