30_Redis哨兵模式

embedded/2025/1/16 21:51:48/

在Redis主从复制模式中,因为系统不具备自动恢复的功能,所以当主服务器(master)宕机后,需要手动把一台从服务器(slave)切换为主服务器。在这个过程中,不仅需要人为干预,而且还会造成一段时间内服务器处于不可用状态,同时数据安全性也得不到保障,因此主从模式的可用性较低,不适用于线上生产环境。

1.哨兵模式介绍

Sentinel是Redis的高可用性的解决方案。由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器,以及所有从服务器,并在被监视的主服务器进入下线状态时,Sentinel会自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。

Redis哨兵模式是一种特殊的模式,Redis为其提供了专属的哨兵命令,它是一个独立的进程,能够独立运行。哨兵模式的结构如下图所示。

Redis哨兵模式的作用如下:

  • 监控:哨兵节点会以每30秒一次的频率对每个Redis节点发送PING命令,并通过Redis节点的回复来判断其运行状态。
  • 自动故障恢复:当哨兵监测到主服务器发生故障时,会自动在从节点中选择一台机器,并将其提升为主服务器,当故障实例恢复后也以新的master为主。
  • 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移(Failover)时,会将最新信息通过PubSub发布订阅模式推送给Redis的客户端以及其他的从节点。

2.哨兵模式原理

2.1 集群监控原理

Sentinel基于心跳机制监测服务状态,每隔30秒向集群的每个实例发送PING命令。

2.1.1 主观下线

主观下线,适用于主服务器和从服务器。如果在规定的时间内(配置参数down-after-milliseconds),Sentinel节点没有收到目标服务器的有效回复(Sentinel基于心跳机制监测服务状态),则判定该服务器为“主观下线”。例如Sentinel-1向主服务发送PING命令,在规定时间内没收到主服务器PONG回复,则Sentinel-1判定主服务器为“主观下线”。

2.1.2 客观下线

客观下线,只适用于主服务器。Sentinel-1发现主服务器出现了故障,它会通过相应的命令,询问其它Sentinel节点对主服务器的状态判断。如果超过指定数量(配置参数quorum)的Sentinel节点认为主服务器down掉(主观下线),则Sentinel-1节点判定主服务为“客观下线”。quorum值最好超过Sentinel实例数量的一半。

2.2 集群故障恢复原理

投票选举(底层使用的是Raft算法),所有Sentinel节点会通过投票机制,按照谁发现谁去处理的原则,例如是由Sentinel-1发现的,则选举Sentinel-1为领头节点去做Failover(故障转移)操作;Sentinel-1节点则按照一定的规则在所有从节点中选择一个最优的作为主服务器,然后通过发布订功能通知其余的从节点(slave)更改配置文件,跟随新上任的主服务器(master)。至此就完成了主从切换的操作。

一旦发现master故障,Sentinel需要在salve中选择一个作为新的master。选择依据见下:

  • 首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点。
  • 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举。
  • 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高。
  • 最后是判断slave节点的运行id大小,越小优先级越高。

当选出一个新的master后(假设选举的是salve1节点),该如何实现切换呢?流程如下:

  • Sentinel给备选的slave1节点发送"REPLICAOF NO ONE"命令,让该节点成为master。
  • Sentinel给所有其它slave节点发送"REPLICAOF 192.168.230.132 6379"命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
  • 最后,Sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点。

对上述过程可简要概述为,Sentinel负责监控主从节点的“健康”状态。当主节点挂掉时,自动选择一个最优的从节点切换为主节点。客户端来连接Redis集群时,会首先连接Sentinel,通过Sentinel来查询主节点的地址,然后再去连接主节点进行数据交互。当主节点发生故障时,客户端会重新向Sentinel要地址,Sentinel会将最新的主节点地址告诉客户端。因此应用程序无需重启即可自动完成主从节点切换。

3.搭建哨兵模式集群

这里我们搭建一个三节点形成的Sentinel哨兵模式集群,来监控之前的Redis主从复制模式集群。

Redis哨兵模式集群搭建设计,信息如下表所示。

主机名

IP地址

Redis服务/Sentinel服务

角色

node1

192.168.230.131

192.168.230.131:6379

master

node2

192.168.230.132

192.168.230.132:6379

slave

node3

192.168.230.133

192.168.230.133:6379

slave

node1

192.168.230.131

192.168.230.131:26379

sentinel

node2

192.168.230.132

192.168.230.132:26379

sentinel

node3

192.168.230.133

192.168.230.133:26379

sentinel

在Redis的安装目录下(/usr/local/src/redis-7.2.5),有一个sentinel.conf配置文件,该文件专门用于配置哨兵模式的相关参数信息。文件中用于配置Redis哨兵模式最核心的一个参数是monitor,其语法格式见下。

# 默认值:sentinel monitor mymaster 127.0.0.1 6379 2
sentinel monitor <master-name> <ip> <redis-port> <quorum>

上述语句的含义是,让Sentinel去监控一个地址为ip:redis-port的主服务器。对该命令中涉及到的几个参数做如下的说明。

参数

作用

master-name

被监控主机名,被监控主机名的命名由开发者进行自定义。主名称不应包含特殊字符或空格。

ip

主节点Redis服务IP地址。

redis-port

主节点Redis服务端口。

quorum

票数,只有在至少quorum个Sentinel同意的情况下才将其视为O_DOWN(Objectively DOWN)状态。即表示当有多少个Sentinel认为主服务器宕机时,它才算真正的宕机掉,通常数量为半数或半数以上才会认为主机已经宕机,quorum需要根据Sentinel的数量设置。

3.1 搭建主从复制模式

接下来,我们在三台虚拟机中使用主从复制模式搭建一个拥有三台服务器的Redis集群,具体操作步骤见下。

1.将三台Redis服务器的redis.conf配置文件(/usr/local/src/redis-7.2.5/redis.conf)做以下参数的配置。

# 允许访问的地址,默认是“bind 127.0.0.1 -::1”,会导致只能在本地访问。修改为“bind 0.0.0.0 -::1”则可以在任意IP访问,生产环境不要设置为“bind 0.0.0.0 -::1”
bind 0.0.0.0 -::1
# 守护进程,修改为yes后即可后台运行,默认值为no
daemonize yes
# 保护模式,no表示关闭保护模式,默认值为yes
protected-mode no
# 密码,设置后redis-cli访问必须输入密码,默认没有配置密码
requirepass 123456

2.在mater主机和两个slave从机的redis.conf配置文件,添加复制同步的密码参数配置,即master主机的requirepass参数的取值。该配置项必须添加,否则主机将拒绝从机请求。

# 配置复制同步密码(即master主机的requirepass参数的取值)
masterauth 123456

3.按照顺序逐一启动三台Redis服务器,并通过客户端连接到Redis服务。

# 检测6379端口是否在监听
$ netstat -lntp | grep 6379
# 进入Redis安装目录 
$ cd /usr/local/src/redis-7.2.5
# 指定配置文件启动redis服务
$ redis-server redis.conf
$ redis-cli -h 127.0.0.1 -p 6379 -a 123456

4.依次查看三台Redis服务器的信息,发现三台Redis服务器的角色都是master。

127.0.0.1:6379> info replication

5.然后将第二台和第三台Redis服务器设置成192.168.230.131的从服务器。

127.0.0.1:6379> REPLICAOF 192.168.230.131 6379
OK

6.查看master主机的信息,发现此时有两台slave从机连接在master主机上,日志信息如下所示。

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.230.132,port=6379,state=online,offset=14,lag=1
slave1:ip=192.168.230.133,port=6379,state=online,offset=14,lag=1
master_failover_state:no-failover
master_replid:8d667e34232c22c8a145bfa36eea058e876b5f6a
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14

3.2 配置Sentinel哨兵模式

1.实际开发当中,不要直接修改sentinel.conf文件,在三台主机上我们先将这个配置文件备份一份。

$ cp sentinel.conf sentinel.conf.backup

2.分别在三台Redis服务器的sentinel.conf文件中,添加下面的配置内容。

# 守护进程,修改为yes后即可后台运行,默认值为no
daemonize yes
# 让Sentinel去监控一个地址为ip:port的主服务器
sentinel monitor mymaster 192.168.230.131 6379 2
# 若主服务器设置了密码,则哨兵必须也配置密码,否则哨兵无法对主从服务器进行监控,该密码与主服务器密码相同
sentinel auth-pass mymaster 123456

auth-pass命令用于设置用于与master主服务器和slave从服务器进行身份验证的密码。需要注意的是,master密码也用于slave,因此如果你想使用Sentinel监视这些实例,则无法在master实例和slave实例中设置不同的密码。

默认情况下,Redis Sentinel不作为守护进程运行。如果需要,请使用“yes”。请注意,Redis在守护进程化时会在/var/run/Redis-sentinel.pid中写入一个pid文件。

3.3 启动Sentinel哨兵模式

1.在三台服务器上,按照顺序逐一启动Sentinel哨兵,命令见下。

$ redis-sentinel sentinel.conf

2.在第一台Redis机器(192.168.230.131)上执行添加字符串操作并查看键的值。

127.0.0.1:6379> SET city xian
OK
127.0.0.1:6379> GET city
"xian"

3.然后在第二台和第三台Redis机器上,查看对应city键的值便可获取到,如下所示。

127.0.0.1:6379> GET city
"xian"

至此,Redis Sentinel哨兵模式的集群搭建完毕,同时启动了Sentinel哨兵集群。此时,就算主服务器挂了,该集群仍然可以正常运转。

3.4 停止主服务器服务

下面模拟主服务意外宕机的情况,首先直接将主服务器的Redis服务终止,然后查看从服务器是否被提升为了主服务器。具体操纵演示步骤见下。

1..关闭Redis主服务器master(192.168.230.131),执行以下命令。

127.0.0.1:6379> SHUTDOWN
(0.75s)
not connected> EXIT

2.在192.168.230.132机器上,查看Redis主从复制的集群信息。通过查询结果发现,该从服务器将192.168.230.133服务器做为master连接。

127.0.0.1:6379> info replication
Error: Server closed the connectionnot connected> info replication
# Replication
role:slave
master_host:192.168.230.133
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_read_repl_offset:109506
slave_repl_offset:109506
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:5719a81cea24fba3fad543bbbe4467a5ba7abcd4
master_replid2:f3b539f424774450b26de565fb92502737f108b4
master_repl_offset:109506
second_repl_offset:105831
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:109492

3.在192.168.230.133机器上,查看Redis主从复制的集群信息。通过查询结果发现,才服务器的角色从原来的slave变成了master,且192.168.230.132变成了它的的从服务器。

127.0.0.1:6379> info replication
Error: Server closed the connectionnot connected> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.230.132,port=6379,state=online,offset=113435,lag=1
master_failover_state:no-failover
master_replid:5719a81cea24fba3fad543bbbe4467a5ba7abcd4
master_replid2:f3b539f424774450b26de565fb92502737f108b4
master_repl_offset:113435
second_repl_offset:105831
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:113421

在Redis集群中开启哨兵模式后,如果主服务器master宕机,此时所有的从服务器slave在后台会自动发起激烈的投票,重新选出新的主服务器master。这就是开启哨兵模式后所发挥的作用。

思考问题:假设此时192.168.230.131机器(原来的主服务器)恢复正常运行状态,那么集群环境的状态将会怎样?

4.重新启动192.168.230.131机器的Redis服务。

[root@node1 redis-7.2.5]# redis-server redis.conf
[root@node1 redis-7.2.5]# redis-cli -h 127.0.0.1 -p 6379 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> KEYS *
Error: Server closed the connection
not connected> KEYS *
1) "city"

5.查看192.168.230.131机器的Redis信息并观察日志的输入内容。

  • 重新归来的Redis服务启动成功后,立刻查看此台机器的Redis服务信息,发现角色为master。
  • 几秒后再次查看当前机器的Redis服务信息,此时发现角色变成slave。原因是在Redis集群中开启了哨兵模式,哨兵检测到有新的Redis服务器被启动,立刻将该Redis服务拉入到现有的集群中以从服务器的身份加入。
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.230.133
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_read_repl_offset:182056
slave_repl_offset:182056
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:5719a81cea24fba3fad543bbbe4467a5ba7abcd4
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:182056
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:168030
repl_backlog_histlen:14027

哨兵模式也是有缺点的,由于所有的写操作都是在master上完成的,然后再同步到slave上,因此两台机器之间通信会有延迟。当系统很繁忙的时候,延迟问题会加重;slave机器数量增加,问题也会加重。

4.RedisTemplate连接Sentinel

在Sentinel集群监管下的Redis主从集群,其节点会因为自动故障转移而发生变化,Redis的客户端必须感知这种变化,及时更新连接信息。Spring的RedisTemplate底层利用Lettuce实现了节点的感知和自动切换。

下面我们通过一个测试示例来实现RedisTemplate集成Sentinel哨兵机制,具体实现步骤见下。

4.1 基础环境搭建

1.创建Spring Boot项目。使用Spring Initializr方式创建一个名为springboot-cache-demo的Spring Boot项目,效果如下图所示。

2.引入相关依赖。在项目的pom.xml文件中添加Web模块中的Spring Data Redis依赖启动器、Spring Web依赖、Lombok依赖,以及Spring Boot单元测试依赖,示例代码如下。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.8</version><relativePath/></parent><groupId>com.ytx</groupId><artifactId>redis-advanced-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>redis-advanced-demo</name><description>redis-advanced-demo</description><url/><licenses><license/></licenses><developers><developer/></developers><scm><connection/><developerConnection/><tag/><url/></scm><properties><java.version>21</java.version></properties><dependencies><!-- Spring Data Redis依赖启动器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build>
</project>

3.在项目的resources目录下新建全局配置文件application.yml,并编写对应的日志级别的配置。

logging:level:io.lettuce.core: debugpattern:dateformat: MM-dd HH:mm:ss:SSS

4.编写Web访问层类。在项目中创建名为com.ytx.controller的包,并在该包下创建一个名为HelloRedisController的控制器类。

package com.ytx.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;@RestController
public class HelloRedisController {@Autowiredprivate StringRedisTemplate redisTemplate;@GetMapping("/set/{key}/{value}")public String hi(@PathVariable String key, @PathVariable String value) {redisTemplate.opsForValue().set(key, value);return "success";}@GetMapping("/get/{key}")public String hi(@PathVariable String key) {return redisTemplate.opsForValue().get(key);}
}

4.2 配置Sentinel

1.配置Redis Sentinel的连接信息。在项目的全局配置文件application.yml中添加Redis数据库服务器的连接配置,示例代码如下。

spring:data:redis:sentinel:master: mymasternodes: # 指定Redis的Sentinel哨兵集群相关信息- 192.168.230.131:26379- 192.168.230.132:26379- 192.168.230.133:26379password: 123456 # Redis密码

2.接下来我们在项目中创建名为com.ytx.config的包,在该包下创建一个Redis自定义配置类RedisConfig,示例代码如下。

package com.ytx.config;
import io.lettuce.core.ReadFrom;
import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/** 定义一个Redis配置类 */
@Configuration
public class RedisConfig {/** 配置读写分离 */@Beanpublic LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer() {return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);}
}

在上述代码中,使用了io.lettuce.core.ReadFrom类,该类中提供了对Redis的读写策略,具体介绍见下表。

属性

作用

MASTER

从主节点读取。

MASTER_PREFERRED

优先从master节点读取,master不可用才读取replica。

REPLICA

从slave(replica)节点读取。

REPLICA _PREFERRED

优先从slave(replica)节点读取,所有的slave都不可用才读取master。

3.启动项目,项目启动成功后,通过浏览器访问http://localhost:8080/set/country/China向Redis数据库中插入一条数据,结果如下图所示。

4.然后在通过浏览器访问http://localhost:8080/get/country查询key为country的数据,结果如下图所示。

5.总结

这一节主要介绍了 Redis Sentinel 模式、原理、搭建及与 RedisTemplate 连接,目的是提升 Redis 集群可用性。核心内容包含以下三部分:

  • 哨兵模式介绍与原理:它是 Redis 高可用解决方案,由 Sentinel 实例组成系统监控主从服务器。通过每 30 秒一次的 PING 命令监测,有主观下线(节点未及时回复判定)和客观下线(多 Sentinel 认定主服务器故障)机制。故障恢复依靠投票选举,依规则选最优从节点升主节点并通知其他节点,确保客户端无需重启即可切换连接。
  • 搭建集群步骤:先搭建主从复制集群,配置 redis.conf 文件(如设置 bind、daemonize 等参数,添加复制密码),启动服务并设置主从关系。接着配置 Sentinel,备份并修改 sentinel.conf(设置守护进程、监控主服务器、配置密码),启动 Sentinel 后可模拟主服务器宕机测试,能看到从节点自动切换为主节点,原主节点恢复后成为从节点,体现其高可用性,但存在主从同步延迟问题。
  • RedisTemplate 连接 Sentinel:在 Spring Boot 项目中,创建项目并引入 Spring Data Redis 等依赖,配置 application.yml 连接 Sentinel 信息及日志。编写控制器类操作 Redis,创建 Redis 配置类设置读写策略(如 REPLICA_PREFERRED)。启动项目后可通过浏览器访问接口操作 Redis 数据,实现与 Sentinel 集成,确保在集群节点变化时客户端能自动感知与切换,保障业务正常运行。

http://www.ppmy.cn/embedded/154490.html

相关文章

yt-dlp脚本下载音频可选设置代理

import yt_dlp# 配置:是否使用代理 use_proxy = True # 设置为 False 可关闭代理# 代理地址 proxy_url = socks5://127.0.0.1:1089URLS = [https://www.bilibili.com/video/BV1WTktYcEcQ/?spm_id_from=333.1007.tianma.6-2-20.click&vd_source=dcb58f8fe1faf749f438620b…

python 爬虫自动获取 GB/T 7714 引用格式

python 自动获取 GB/T 7714 引用格式 参考&#xff1a;python爬虫实现自动获取论文GB 7714引用 介绍&#xff1a;从 Google Scholar 网站&#xff08;具体为 https://xueshu.aigrogu.com/&#xff09;收集文章信息&#xff0c;包括文章标题、链接和 GB/T 7714 引用格式。该代码…

【2025 Rust学习 --- 17 文本和格式化 】

字符串与文本 Rust 的主要文本类型 String、str 和 char 内容概括&#xff1a; Unicode 背景知识&#xff1f;单个 Unicode 码点的 char&#xff1f;String 类型和 str 类型都是表示拥有和借用的 Unicode 字符序列。Rust 的字符串格式化工具&#xff0c;比如 println! 宏和 …

Qt/C++进程间通信:QSharedMemory 使用详解(附演示Demo)

在开发跨进程应用程序时&#xff0c;进程间通信&#xff08;IPC&#xff09;是一个关键问题。Qt 框架提供了多种 IPC 技术&#xff0c;其中 QSharedMemory 是一种高效的共享内存方式&#xff0c;可以实现多个进程之间快速交换数据。本文将详细讲解 QSharedMemory 的概念、用法及…

用 Python 自动化处理日常任务

&#x1f496; 欢迎来到我的博客&#xff01; 非常高兴能在这里与您相遇。在这里&#xff0c;您不仅能获得有趣的技术分享&#xff0c;还能感受到轻松愉快的氛围。无论您是编程新手&#xff0c;还是资深开发者&#xff0c;都能在这里找到属于您的知识宝藏&#xff0c;学习和成长…

使用 selenium-webdriver 开发 Web 自动 UI 测试程序

优缺点 优点 有时候有可能一个改动导致其他的地方的功能失去效果&#xff0c;这样使用 Web 自动 UI 测试程序可以快速的检查并定位问题&#xff0c;节省大量的人工验证时间 缺点 增加了维护成本&#xff0c;如果功能更新过快或者技术更新过快&#xff0c;维护成本也会随之提高…

【Linux】sed编辑器二

一、处理多行命令 sed编辑器有3种可用于处理多行文本的特殊命令。 N&#xff1a;加入数据流中的下一行&#xff0c;创建一个多行组进行处理&#xff1b;D&#xff1a;删除多行组中的一行&#xff1b;P&#xff1a;打印多行组中的一行。 1、next命令&#xff1a;N 单行next命…

【SpringSecurity】SpringSecurity安全框架授权

授权 权限系统要实现的效果&#xff1a;不同的用户可以使用不同的功能。 在后台进行用户权限的判断&#xff0c;判断当前用户是否有相应的权限&#xff0c;必须具有所需权限才能进行相应的操作。 在 SpringSecurity 中&#xff0c;默认使用 FilterSecurityInterceptor 进行权…