1、Redis集群介绍
Redis 集群(Redis Cluster)是Redis提供的一种分布式部署方式,旨在提供高可用性。如果某个主节点发生故障,集群能够自动进行故障转移,将副本提升为主节点,从而保证数据的持续可用,Redis 集群非常适合于大规模缓存系统和大数据量场景。
2、搭建集群的几种方式
- 主从复制(Master-Slave):这种模式下,主节点(Master)负责数据写入和读取,而从节点(Slave)则只能用于数据读取和备份,不能够写入数据。若主节点发生故障,需人工介入,将某个从节点提升为新的主节点。该模式没有自动故障转移,需要手动处理故障,因此可用性较差。最少需要2台服务器搭建一主一从或者多台服务器搭建一主多从。在资源不允许的情况下,可以借助高可用工具实现自动故障转移。如:Keepalived + Redis主从实现主备双活。
- 哨兵模式(Redis Sentinel) : 哨兵模式下,需要额外搭建哨兵(Sentinel)服务用于监控Redis集群中的主节点,并且能够在主节点发生故障时自动进行故障转移,通过选举的方式,将从节点升级为主节点。它提供高可用性和自动恢复能力。常见的集群方式为:1主2从 + 3个Sentinel进程,哨兵(Sentinel)进程可以部署在相同的3个节点上,以减少服务器资源。比较适用于需要高可用的中小型应用,数据量不是特别大的场景。
- 分片集群(Redis Cluster):这一模式支持数据分片(Sharding)存储和多节点水平扩展,有效的提高了内存利用率和写入性能。插入的数据会根据一定的规则(哈希槽)被分布到不同的节点上,每个节点负责数据的一个子集(通过哈希槽的范围),它会自动管理数据的分布和迁移。它采用了去中心化的多主多从架构,最低配置要求为3个主节点(Master)和3个从节点(Slave),通常情况下可以在3台服务器中每台服务器配置一主一从进行搭建,虽然这样会影响一定的性能,但是可以减少服务器所需的资源。如果需要发挥其最大的价值,至少需要6台服务器节点才可以。该集群非常适用于更大规模和更高要求的数据处理场景。
3、选择集群模式
这里根据所属的业务系统需要的Redis需求进行合适的选择。使用Redis Cluster 模式搭建分片集群的要求比较高,客户端必须该支持集群模式,而且配置Redis Cluster 需要比普通的Redis主从模式复杂的多,需要的成本比较高。只有当应用需要高性能、高吞吐量,并且对数据分布和扩展性有需求时,Redis Cluster 是更好的选择。使用Redis Sentinel 模式搭建集群相对来说不是特别复杂,只需要搭建Redis主从模式后在启动相关的Sentinel 即可。如果数据量不是特别大,使用Redis集群只是用来提供高可用性和故障转移,可以考虑使用 Redis Sentinel 。本篇使用 哨兵模式(Redis Sentinel) 进行搭建Redis集群。
哨兵模式(Redis Sentinel)相关介绍:
Redis哨兵模式(Redis Sentinel)首次引入是在 Redis 2.8.0 版本中。该版本于 2013年12月 发布。Redis Sentinel 的设计初衷是为了弥补 Redis 在高可用性和自动故障转移方面的不足,特别是对于主从复制架构中的主节点宕机的容错处理。通过Redis Sentinel 可以实现自动检测故障和自动故障转移,从而提高 Redis 的可用性和可靠性。在这一模式中,哨兵负责实时监控主节点的运行状况。如果主节点出现故障,哨兵将基于预设的投票机制,自动将某个从节点晋升为新的主节点,以保障服务的连续性和数据的可用性。哨兵本身是一个独立的进程,运行在Redis本身进程之外。它通过持续监控 Redis 服务器的状态,包括主节点和从节点,并定期通过 ping 主从节点来确认它们是否仍然可用,来判断被监控的Redis实例是否正常运行来确保Redis服务的稳定性。
4、环境准备
4.1、服务器信息
根据以上搭建的几种方式和相关建议,在3台服务器节点的情况下,首选Redis Sentinel哨兵模式进行搭建。以下是服务器信息:
服务器 | IP 地址 | 部署应用 |
---|---|---|
node1 | 192.168.42.131 | Redis Master +Sentinel |
node2 | 192.168.42.132 | Redis Slave + Sentinel |
node3 | 192.168.42.133 | Redis Slave + Sentinel |
4.2、软件版本
- 操作系统: CentOS 7.9
- Redis 版本: 5.0
5、配置Redis主从复制
5.1、创建目录
分别在三台服务器中创建以下目录:
sh
# 选择Redis存储文件目录,创建以下目录
mkdir -p /root/docker/redis/config /root/docker/redis/data /root/docker/redis/sentinel
# config 存入redis配置文件信息 如:redis.conf
# data 存入持久化Redis数据
# sentinel 存入哨兵的配置文件信息 如:sentinel.conf
下载配置文件redis.conf
到本地,并上传到服务器config
目录,下载地址:https://github.com/redis/redis/blob/5.0.4/redis.conf
5.2、配置Redis配置文件
在 node1
、node2
和 node3
上更新Redis配置文件信息 vim ~/docker/redis/config/redis.conf
,配置密码和主从关系。
主节点(node1):
ini
# 运行端口
port 6379
# 允许外部所有IP访问
bind 0.0.0.0
# 是否以守护进程运行,Docker运行必须设置为no。
daemonize no
# redis密码
requirepass "1234qwer"
# 配置主从连接密码
masterauth "1234qwer"
# 开启持久化
appendonly yes
#对外固定开放IP地址
slave-announce-ip 192.168.42.131
#对外固定开放端口
slave-announce-port 6379
从节点(node2):
ini
port 6379
bind 0.0.0.0
daemonize no
requirepass "1234qwer"
masterauth "1234qwer"
appendonly yes
# 对外固定开放IP地址
slave-announce-ip 192.168.42.132
# 对外固定开放端口
slave-announce-port 6379
# 配置主节点的IP和端口
REPLICAOF 192.168.42.131 6379
从节点(node3)
ini
port 6379
bind 0.0.0.0
daemonize no
requirepass "1234qwer"
masterauth "1234qwer"
appendonly yes
# 对外固定开放IP地址
slave-announce-ip 192.168.42.133
# 对外固定开放端口
slave-announce-port 6379
# 配置主节点的IP和端口
REPLICAOF 192.168.42.131 6379
5.3、启动Redis容器
主节点(node1):
bash
docker run -d -p 6379:6379 --restart=always --privileged=true --name redis-master -v ~/docker/redis/config/redis.conf:/etc/redis/redis.conf -v ~/docker/redis/data:/data redis:5.0 redis-server /etc/redis/redis.conf
从节点(node2):
bash
docker run -d -p 6379:6379 --restart=always --privileged=true --name redis-slave -v ~/docker/redis/config/redis.conf:/etc/redis/redis.conf -v ~/docker/redis/data:/data redis:5.0 redis-server /etc/redis/redis.conf
从节点(node3):
sh
docker run -d -p 6379:6379 --restart=always --privileged=true --name redis-slave -v ~/docker/redis/config/redis.conf:/etc/redis/redis.conf -v ~/docker/redis/data:/data redis:5.0 redis-server /etc/redis/redis.conf
5.4、验证主从复制
登录redis
输入:info replication
可以查看Redis
集群配置信息。如果搭建成功,会显示节点信息。
主节点(node1)显示以下信息:
sh
# 首先通过docker进入redis容器
docker exec -it redis-master bash
# 进入成功后,登录redis
redis-cli -p 6379
# 登录成功,进行密码认证,然后查看集群配置信息
127.0.0.1:6379> auth 1234qwer
ok
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.42.132,port=6379,state=online,offset=280,lag=0
slave1:ip=192.168.42.133,port=6379,state=online,offset=280,lag=0
master_replid:a052149baf6e1dbb345f55ceb37476e95efca431
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:280
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:280
从节点(node2)显示以下信息:
sh
# 首先通过docker进入redis容器
docker exec -it redis-slave bash
# 进入成功后,登录redis
redis-cli -p 6379
# 登录成功,进行密码认证,然后查看集群配置信息
127.0.0.1:6379> auth 1234qwer
ok
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.42.131
master_port:6379
master_link_status:up
master_last_io_seconds_ago:10
master_sync_in_progress:0
slave_repl_offset:448
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:a052149baf6e1dbb345f55ceb37476e95efca431
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:448
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:434
从节点(node3)显示以下信息:
sh
# 首先通过docker进入redis容器
docker exec -it redis-slave bash
# 进入成功后,登录redis
redis-cli -p 6379
# 登录成功,进行密码认证,然后查看集群配置信息
127.0.0.1:6379> auth 1234qwer
ok
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.42.131
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:532
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:a052149baf6e1dbb345f55ceb37476e95efca431
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:532
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:532
输出以上信息,说明Redis主从配置已经连接成功了,接下来验证一下存取数据。
5.5、验证存取数据
在两个从节点存入数据会报错。
sh
127.0.0.1:6379> set verify-key "Test Verify is Success"
(error) READONLY You can't write against a read only replica.
因为从节点只可以读取数据不可以写入数据,要想写入数据需要在主节点进行。主节点可以读写数据。登录主节点存入数据:
sh
127.0.0.1:6379> set verify-key "Test Verify is Success"
OK
127.0.0.1:6379> get verify-key
"Test Verify is Success"
然后分别在两个从节点读取数据,看看是否可以读取成功。
sh
# 登录 192.168.42.132 节点redis信息
127.0.0.1:6379> get verify-key
"Test Verify is Success"
# 登录 192.168.42.133 节点redis信息
127.0.0.1:6379> get verify-key
"Test Verify is Success"
获取成功,说明主从复制搭建成功。
6、配置 Redis 哨兵
6.1、主节点(node1)配置启动
进入:/root/docker/redis/sentinel
目录,下载sentinel.conf
文件并上传的该目录,配置哨兵连接。 文件下载地址: https://github.com/redis/redis/blob/5.0.4/sentinel.conf
下载成功后,修改配置文件。执行命令vim /root/docker/redis/sentinel/sentinel.conf
properties
# 哨兵节点的端口号
port 26379
bind 0.0.0.0
logfile "/var/log/redis-sentinel.log"
# 关闭保护模式,允许外部访问,Docker环境中必须设置为 no
protected-mode no
# 禁止Redis以守护进程方式运行
daemonize no
# 哨兵工作目录
dir /tmp
sentinel monitor mymaster 192.168.42.131 6379 2
# 解析:
# - mymaster:主节点的名称标识
# - 49.235.180.130:主节点的IP地址
# - 6379:主节点的端口号
# - 2:判定主节点故障需要的哨兵投票数(至少2个哨兵认为主节点故障才会进行故障转移)
#redis节点密码
sentinel auth-pass mymaster 1234qwer
# 解析:
# - mymaster:对应的主节点名称
# - 1234qwer:Redis节点的访问密码
# 主观下线时间,单位毫秒
sentinel down-after-milliseconds mymaster 10000
# 解析:如果10秒内无法连接主节点,则认为主节点主观下线
# 同步配置
sentinel parallel-syncs mymaster 1
# sentinel parallel-syncs:并行同步配置,mymaster:主节点的别名,1:并行同步的从节点数量。
#作用和影响:
#1. 控制故障转移期间的数据同步行为,当值为1时:从节点逐个同步,当值大于1时:多个从节点并行同步
#示例场景:
# parallel-syncs = 1 时:主节点故障,slave1被选为新主节点 slave2开始与slave1同步,slave3等待slave2同步完成后再同步,过程较慢但主节点压力小
# parallel-syncs = 2 时:主节点故障,slave1被选为新主节点,slave2和slave3同时与slave1同步,过程较快但主节点压力大
# 故障转移超时时间
sentinel failover-timeout mymaster 600000
# 解析:故障转移的超时时间为600秒(10分钟)
sentinel deny-scripts-reconfig yes
# 解析:禁止通过脚本修改哨兵配置,提高安全性
# 对外宣告的IP地址
sentinel announce-ip "192.168.42.131"
# 对外宣告的端口号
sentinel announce-port 26379
# 解析:
# - 用于在Docker或NAT网络环境中,声明哨兵节点的实际可访问地址
# - 确保其他节点可以正确连接到该哨兵节点
启动哨兵:
bash
docker run -d -p 26379:26379 --restart=always --privileged=true --name redis-sentinel -v /root/docker/redis/sentinel/sentinel.conf:/etc/redis/sentinel.conf redis:5.0 redis-sentinel /etc/redis/sentinel.conf
6.2、从节点(node2)配置启动
下载并修改配置文件。执行命令vim /root/docker/redis/sentinel/sentinel.conf
sh
# 配置文件和主节点启动的哨兵配置文件一致,只需要更改一下对外监听的哨兵地址即可
# 对外宣告的IP地址
sentinel announce-ip "192.168.42.132"
# 对外宣告的端口号
sentinel announce-port 26379
启动哨兵:
sh
docker run -d -p 26379:26379 --restart=always --privileged=true --name redis-sentinel -v /root/docker/redis/sentinel/sentinel.conf:/etc/redis/sentinel.conf redis:5.0 redis-sentinel /etc/redis/sentinel.conf
6.3、从节点(node3)配置启动
下载并修改配置文件。执行命令vim /root/docker/redis/sentinel/sentinel.conf
sh
# 配置文件和主节点启动的哨兵配置文件一致,只需要更改一下对外监听的哨兵地址即可
# 对外宣告的IP地址
sentinel announce-ip "192.168.42.133"
# 对外宣告的端口号
sentinel announce-port 26379
启动哨兵:
sh
docker run -d -p 26379:26379 --restart=always --privileged=true --name redis-sentinel -v /root/docker/redis/sentinel/sentinel.conf:/etc/redis/sentinel.conf redis:5.0 redis-sentinel /etc/redis/sentinel.conf
6.4、验证哨兵集群
首先选择一台服务器进行登录哨兵,可以在主节点或从节点执行以下命令,进入哨兵容器:
sh
docker exec -it redis-sentinel bash
连接哨兵客户端:
sh
redis-cli -p 26379
查看哨兵信息:
sh
# info sentinel
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.42.131:6379,slaves=2,sentinels=3
#输出以上信息配置成功
查看哨兵信息,如果发现已经集成成功了,接下来就可以验证哨兵模式了。在哨兵模式下,当master服务器宕机之后,哨兵自动会在从 节点服务器里面投票选举一个master服务器来,这个master服务器也可以进行读写操作。
先把主节点关闭掉:
sh
docker stop redis-master
再次查看哨兵信息:
sh
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.42.132:6379,slaves=2,sentinels=3
# 根据最后一行信息,可以看出主节点的IP进行变化了。由192.168.42.131 -> 192.168.42.132
7、SpringBoot连接Redis哨兵模式
7.1、引入依赖
在 pom.xml
中添加依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
7.2、配置 application.yml
yaml
spring:
redis:
#密码
password: 1234qwer
timeout: 5000
sentinel:
# 对应前面sentinel的配置文件信息
master: mymaster
# 三个哨兵的ip端口
nodes: 192.168.42.131:26379,192.168.42.132:26379,192.168.42.133:26379
7.3、编写测试代码
创建 RedisConfig使用Jedis客户端连接
java
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.password}")
private String password;
// 新增哨兵配置
@Value("${spring.redis.sentinel.master}")
private String masterName;
@Value("${spring.redis.sentinel.nodes}")
private String sentinelNodes;
@Bean
public JedisSentinelPool jedisSentinelPool() {
// 解析哨兵节点
Set<String> sentinels = new HashSet<>(Arrays.asList(sentinelNodes.split(",")));
// 创建哨兵连接池
JedisSentinelPool sentinelPool = new JedisSentinelPool(masterName, sentinels, createPoolConfig(), timeout, password,0);
log.info("使用哨兵模式,主节点名称:{} JedisSentinelPool注入成功!!", masterName);
return sentinelPool;
}
private JedisPoolConfig createPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(50);
jedisPoolConfig.setMinIdle(5);
jedisPoolConfig.setMaxWaitMillis(10000);
jedisPoolConfig.setJmxEnabled(true);
return jedisPoolConfig;
}
}
创建 JedisTemplate操作Redis类
java
@Component
@ConditionalOnClass(RedisConfig.class)
public class JedisTemplate {
@Autowired(required = false)
private JedisSentinelPool jedisSentinelPool;
/**
* 保存数据
* @param key
* @param value
* @param seconds 小于等于0时为不限制时长
*/
public final void setStringData(String key, String value, int seconds) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
boolean flag = jedis.exists(key);
if (flag) {
jedis.del(key);
}
jedis.set(key, value);
if (seconds > 0) {
jedis.expire(key, seconds);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* 根据key获取redis里面的字符串
* @param key
* @return
*/
public String getStringData(String key) {
String str = null;
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
str = jedis.get(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
}
return str;
}
/**
* 删除一个key
* @param key
*/
public void deleteKey(String key) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
jedis.del(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
}
}
}
创建RedisTestController测试Web控制器
java
@RestController
public class RedisTestController {
@Autowired
private JedisTemplate jedisTemplate;
@GetMapping("/redis/test/{key}")
public Response getRedisSentinelTest(@PathVariable("key") String key){
String randomNumeric = RandomStringUtils.randomNumeric(12);
jedisTemplate.setStringData(key,"哈哈哈" + randomNumeric, 180);
String stringData = jedisTemplate.getStringData(key);
System.out.println(stringData);
return Response.success(stringData);
}
}
7.4、启动项目
sh
2025-02-22 17:40:14.223 INFO -[JedisSentinelPool.java:198]- Trying to find master from available Sentinels...
2025-02-22 17:40:14.328 INFO -[JedisSentinelPool.java:254]- Redis master running at 192.168.42.131:6379, starting Sentinel listeners...
2025-02-22 17:40:14.345 INFO -[JedisSentinelPool.java:188]- Created JedisPool to master at 192.168.42.131:6379
2025-02-22 17:40:14.345 INFO -[RedisConfig.java:42]- 使用哨兵模式,主节点名称:mymaster JedisSentinelPool注入成功!!
2025-02-22 17:40:48.609 INFO -[DirectJDKLog.java:173]- Starting ProtocolHandler ["http-nio-9090"]
2025-02-22 17:40:48.630 INFO -[TomcatWebServer.java:220]- Tomcat started on port(s): 9090 (http) with context path ''
2025-02-22 17:40:48.642 INFO -[StartupInfoLogger.java:61]- Started App in 2.892 seconds (JVM running for 3.562)
2025-02-22 17:41:05.914 INFO -[DirectJDKLog.java:173]- Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-02-22 17:41:05.915 INFO -[FrameworkServlet.java:525]- Initializing Servlet 'dispatcherServlet'
2025-02-22 17:41:05.929 INFO -[FrameworkServlet.java:547]- Completed initialization in 14 ms
调用接口使用PostMan调用接口进行测试:http://localhost:9090/redis/test/1234 ,测试哨兵是否创建成功。
8、总结
到此Redis哨兵集群就搭建完成了。Redis哨兵为我们提供了强大的监控和自动修复功能,这使得Redis服务在面临各种故障时,能够快速自动恢复,减少人工干预。回顾整个搭建过程,搭建并不是特别复杂,主要也就3个步骤,包括:1、配置Redis主从复制。2、设置Redis哨兵节点。3、验证高可用性。最后,希望本文能帮助你了解Redis哨兵模式的搭建流程,并为你提供参考。如果你在搭建过程中遇到问题,欢迎讨论或查阅Redis官方文档,进一步优化配置。