在这里插入图片描述

👋 大家好,欢迎来到我的技术博客!
💻 作为一名热爱 Java 与软件开发的程序员,我始终相信:清晰的逻辑 + 持续的积累 = 稳健的成长
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕Redis这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!


Redis100篇 - Redis Sentinel怎么用 高可用集群部署指南 🚀

在当今这个数据驱动的时代,Redis 作为一款高性能的内存数据库,已经成为了无数互联网应用的核心组件。无论是缓存、会话存储、消息队列还是实时排行榜,Redis 都能以惊人的速度处理海量数据请求。然而,任何系统都可能面临故障风险,单点故障(SPOF)是传统主从架构中的一大隐患。一旦主节点宕机,整个服务就可能陷入停滞,这对于追求高可用性的现代应用来说是不可接受的。

为了解决这一问题,Redis 提供了 Sentinel 系统,一个用于监控和自动故障转移的分布式系统。它就像一支全天候待命的“哨兵”部队 🛡️,时刻守护着你的 Redis 实例,一旦发现主节点失联,便能迅速选举出新的主节点,并通知所有客户端进行连接切换,从而实现真正的高可用(High Availability, HA)。

本篇文章将带你深入探索 Redis Sentinel 的世界,从零开始搭建一个具备自动故障转移能力的高可用集群。我们将详细讲解其核心原理、部署步骤、配置文件详解、Java 客户端集成、运维管理以及最佳实践。无论你是刚接触 Redis 的新手,还是希望提升系统稳定性的资深开发者,都能从中获得宝贵的实战经验。

准备好了吗?让我们一起踏上这场构建坚如磐石的 Redis 高可用集群之旅吧!🚗💨


🌐 什么是 Redis Sentinel?

Redis Sentinel 是 Redis 官方提供的高可用性解决方案。它不是一个独立的服务,而是一组运行在特殊模式下的 Redis 进程,专门用于监控 Redis 主从实例的健康状况,并在主节点发生故障时自动执行故障转移(failover),确保服务的持续可用。

🤔 为什么需要 Sentinel?

在传统的 Redis 主从复制架构中,虽然数据可以从主节点同步到一个或多个从节点,但当主节点崩溃时,系统无法自动恢复。此时,管理员必须手动介入,将某个从节点提升为新的主节点,并更新所有客户端的连接配置。这个过程不仅耗时,而且容易出错,尤其是在生产环境中,每一秒的停机都可能导致巨大的经济损失和用户体验下降。

Sentinel 的出现,正是为了自动化这一过程。它通过以下三个主要功能来保障系统的高可用性:

  1. 监控(Monitoring): Sentinel 会持续不断地检查你的主节点和从节点是否正常工作。
  2. 通知(Notification): 当被监控的某个 Redis 实例出现问题时,Sentinel 可以通过 API 向管理员或其他应用程序发送通知。
  3. 自动故障转移(Automatic Failover): 当主节点不可用时,Sentinel 会启动一个故障转移操作,将其中一个从节点提升为新的主节点,并让其他从节点开始复制这个新主节点。
  4. 配置提供者(Configuration Provider): Sentinel 充当客户端服务发现的角色。客户端在初始化连接时,会向 Sentinel 查询当前的主节点地址。如果发生了故障转移,Sentinel 会返回新的主节点地址,客户端据此更新连接。

🔗 相关链接


🧠 Sentinel 的核心原理与工作机制

理解 Sentinel 的内部工作机制是成功部署和维护高可用集群的关键。Sentinel 并非魔法,它的每一个决策背后都有严谨的算法和流程支撑。

🔄 故障检测与仲裁

Sentinel 系统通常由 三个或更多 的 Sentinel 实例组成,这些实例之间相互监控,形成一个去中心化的网络。这种设计避免了 Sentinel 自身成为单点故障。

📌 主观下线(Subjective Down, SDOWN)

每个 Sentinel 实例都会定期(默认每秒一次)向它所监控的主节点、从节点以及其他 Sentinel 实例发送 PING 命令。如果在指定的时间内(down-after-milliseconds 配置项)没有收到有效的回复,该 Sentinel 实例就会将目标节点标记为“主观下线”。这仅仅是单个 Sentinel 的判断,还不能触发故障转移。

PING
No Response
PING
Response
Sentinel 1
Redis Master
Mark as SDOWN
Sentinel 2
Still UP
🤝 客观下线(Objective Down, ODOWN)

为了做出更可靠的决策,Sentinel 引入了“客观下线”的概念。当一个 Sentinel 实例认为主节点主观下线后,它会向其他 Sentinel 实例发送命令询问:“你认为主节点也下线了吗?” 如果有足够数量(quorum)的 Sentinel 实例也报告主节点主观下线,那么主节点就会被标记为“客观下线”。只有达到客观下线状态,才会触发故障转移流程。

Master is SDOWN
Master is SDOWN
Yes, SDOWN too
Yes, SDOWN too
Quorum Reached!
Sentinel 1
Sentinel 2
Sentinel 3
Start Failover

🏆 故障转移流程(Failover Process)

一旦主节点被标记为客观下线,Sentinel 系统将启动故障转移流程。这个过程由一个被选中的 Sentinel 领导者(Leader)来协调完成。

  1. 领导者选举(Leader Election): 所有 Sentinel 实例会通过 Raft 算法的一个简化版本进行投票,选出一个领导者。只有领导者有权发起故障转移。
  2. 选择新的主节点: 领导者会根据一系列规则从现有的从节点中挑选一个作为新的主节点。选择标准包括:
    • 从节点与旧主节点的断开时间。
    • 从节点的优先级(slave-priority 配置)。
    • 复制偏移量(越接近主节点越好)。
    • 运行 ID(字典序最小)。
  3. 提升从节点: 领导者向选定的从节点发送 SLAVEOF NO ONE 命令,将其提升为新的主节点。
  4. 重新配置其他从节点: 领导者通知其他从节点,让它们开始复制新的主节点。
  5. 更新配置: 领导者更新内部配置,记录新的主从关系。
  6. 通知客户端: Sentinel 会发布事件,客户端可以订阅这些事件来获取主节点变更的通知。
Sentinel 1 (Leader) Sentinel 2 Sentinel 3 Old Master Replica 1 Replica 2 Clients PING (No Response) "Is Master down?" Yes "Is Master down?" Yes Quorum Reached, Start Election Vote for Leader Vote Vote I am Leader! SELECT new master (based on rules) SLAVEOF NO ONE Promoted to Master SLAVEOF New_Master_IP New_Master_Port Start Replicating PUBLISH +switch-master event Sentinel 1 (Leader) Sentinel 2 Sentinel 3 Old Master Replica 1 Replica 2 Clients

🛠️ 搭建 Redis Sentinel 高可用集群

现在,让我们动手实践,从零开始搭建一个包含 1 个主节点、2 个从节点和 3 个 Sentinel 节点的高可用集群。我们将在一台机器上通过不同的端口来模拟多台服务器的环境,这在测试和学习阶段非常实用。

🖥️ 环境准备

假设我们的服务器 IP 地址为 192.168.1.100

  • Redis 主节点: 端口 6379
  • Redis 从节点 1: 端口 6380
  • Redis 从节点 2: 端口 6381
  • Sentinel 1: 端口 26379
  • Sentinel 2: 端口 26380
  • Sentinel 3: 端口 26381

首先,确保你的服务器上已经安装了 Redis。你可以通过包管理器安装,或者从源码编译。以下是 Ubuntu 系统下的安装命令:

sudo apt update
sudo apt install redis-server

📄 创建配置文件

我们需要为每个 Redis 和 Sentinel 实例创建独立的配置文件。

主节点配置 (redis-master.conf)
# 基本配置
port 6379
daemonize yes
pidfile /var/run/redis_6379.pid
logfile /var/log/redis/redis_6379.log
dir /var/lib/redis/6379

# 安全配置(可选)
# requirepass yourpassword

# 持久化配置
save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump.rdb
从节点配置 (redis-replica1.conf)
port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
logfile /var/log/redis/redis_6380.log
dir /var/lib/redis/6380

# 指向主节点
replicaof 192.168.1.100 6379

# 如果主节点有密码,需要配置
# masterauth yourpassword

save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump.rdb
从节点配置 (redis-replica2.conf)
port 6381
daemonize yes
pidfile /var/run/redis_6381.pid
logfile /var/log/redis/redis_6381.log
dir /var/lib/redis/6381

replicaof 192.168.1.100 6379
# masterauth yourpassword

save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump.rdb
Sentinel 配置 (sentinel1.conf)
# 监控名为 mymaster 的主节点,IP 和端口,quorum 设为 2
sentinel monitor mymaster 192.168.1.100 6379 2

# 主节点响应超时时间(毫秒)
sentinel down-after-milliseconds mymaster 5000

# 故障转移超时时间
sentinel failover-timeout mymaster 10000

# 故障转移期间,可以同时从新主节点同步数据的从节点数量
sentinel parallel-syncs mymaster 1

# 通知脚本(可选)
# sentinel notification-script mymaster /path/to/notify.sh

# 客户端重连延迟
sentinel client-reconfig-script mymaster /path/to/reconfig.sh

# Sentinel 专用配置
port 26379
daemonize yes
pidfile /var/run/redis-sentinel-26379.pid
logfile /var/log/redis/sentinel_26379.log
dir /var/lib/redis/sentinel/26379
Sentinel 配置 (sentinel2.conf)
sentinel monitor mymaster 192.168.1.100 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel parallel-syncs mymaster 1

port 26380
daemonize yes
pidfile /var/run/redis-sentinel-26380.pid
logfile /var/log/redis/sentinel_26380.log
dir /var/lib/redis/sentinel/26380
Sentinel 配置 (sentinel3.conf)
sentinel monitor mymaster 192.168.1.100 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel parallel-syncs mymaster 1

port 26381
daemonize yes
pidfile /var/run/redis-sentinel-26381.pid
logfile /var/log/redis/sentinel_26381.log
dir /var/lib/redis/sentinel/26381

▶️ 启动服务

按照以下顺序启动服务:

  1. 启动主节点

    redis-server redis-master.conf
    
  2. 启动从节点

    redis-server redis-replica1.conf
    redis-server redis-replica2.conf
    
  3. 启动 Sentinel 节点

    redis-sentinel sentinel1.conf
    redis-sentinel sentinel2.conf
    redis-sentinel sentinel3.conf
    

✅ 验证集群状态

使用 redis-cli 连接到任意一个 Sentinel 实例,检查集群状态。

redis-cli -p 26379

在 Redis CLI 中执行以下命令:

# 查看 Sentinel 监控的所有主节点
SENTINEL masters

# 查看名为 mymaster 的主节点详细信息
SENTINEL master mymaster

# 查看所有从节点
SENTINEL replicas mymaster

# 查看其他 Sentinel 节点
SENTINEL sentinels mymaster

如果一切正常,你应该能看到主节点和两个从节点都处于 online 状态,Sentinel 节点之间也互相发现了彼此。


💻 Java 客户端集成:Jedis 与 Lettuce

在 Java 应用中,我们通常使用 Jedis 或 Lettuce 作为 Redis 客户端。两者都原生支持 Redis Sentinel,能够自动发现主节点并处理故障转移。

🧩 使用 Jedis 连接 Sentinel

Jedis 是一个简单而强大的 Redis Java 客户端。以下是使用 Jedis 连接 Sentinel 集群的代码示例。

添加 Maven 依赖
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>5.0.2</version>
</dependency>
Java 代码示例
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.exceptions.JedisConnectionException;

import java.util.HashSet;
import java.util.Set;

public class JedisSentinelExample {

    private static JedisSentinelPool pool;

    public static void init() {
        // 定义 Sentinel 节点地址
        Set<String> sentinels = new HashSet<>();
        sentinels.add("192.168.1.100:26379");
        sentinels.add("192.168.1.100:26380");
        sentinels.add("192.168.1.100:26381");

        // 初始化连接池
        // mymaster 是我们在 sentinel.conf 中配置的主节点名称
        pool = new JedisSentinelPool("mymaster", sentinels);

        System.out.println("Jedis Sentinel Pool initialized successfully! 🎉");
    }

    public static void main(String[] args) {
        init();

        try (Jedis jedis = pool.getResource()) {
            // 测试连接
            String response = jedis.ping();
            System.out.println("Ping response: " + response); // Should print "PONG"

            // 写入数据
            jedis.set("hello", "Hello from Jedis with Sentinel! 🚀");
            String value = jedis.get("hello");
            System.out.println("Value of 'hello': " + value);

        } catch (JedisConnectionException e) {
            System.err.println("Failed to connect to Redis via Sentinel: " + e.getMessage());
            e.printStackTrace();
        } finally {
            if (pool != null) {
                pool.close();
            }
        }
    }
}
⚠️ 注意事项
  • JedisSentinelPool 会自动从 Sentinel 获取当前主节点的地址。
  • 当发生故障转移时,JedisSentinelPool 会监听 Sentinel 发布的 +switch-master 事件,并自动更新内部的主节点地址,后续的 getResource() 调用将返回连接到新主节点的 Jedis 实例。
  • 建议将 JedisSentinelPool 作为单例在整个应用中共享,避免频繁创建和销毁连接池带来的性能开销。

🌿 使用 Lettuce 连接 Sentinel

Lettuce 是另一个流行的 Redis 客户端,基于 Netty 构建,支持异步、响应式编程模型,并且对 Sentinel 的支持更加现代化和灵活。

添加 Maven 依赖
<dependency>
    <groupId>io.lettuce.core</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>6.3.2.RELEASE</version>
</dependency>
Java 代码示例
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.pubsub.RedisPubSubAdapter;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.async.RedisPubSubAsyncCommands;

import java.time.Duration;
import java.util.Arrays;

public class LettuceSentinelExample {

    public static void main(String[] args) {
        // 构建 RedisURI,指向 Sentinel
        RedisURI redisURI = RedisURI.Builder
                .sentinel("192.168.1.100", 26379, "mymaster")
                .withSentinel("192.168.1.100", 26380)
                .withSentinel("192.168.1.100", 26381)
                // .withPassword("yourpassword") // 如果有密码
                .withTimeout(Duration.ofSeconds(10))
                .build();

        // 创建 RedisClient
        RedisClient client = RedisClient.create(redisURI);

        try {
            // 获取同步连接
            StatefulRedisConnection<String, String> connection = client.connect();
            RedisCommands<String, String> syncCommands = connection.sync();

            // 测试连接
            String pong = syncCommands.ping();
            System.out.println("Lettuce Ping: " + pong);

            // 写入和读取数据
            syncCommands.set("greeting", "Hello from Lettuce with Sentinel! 🌿");
            String value = syncCommands.get("greeting");
            System.out.println("Value: " + value);

            // 订阅 Sentinel 事件(可选,用于监控)
            StatefulRedisPubSubConnection<String, String> pubSubConn = client.connectPubSub();
            pubSubConn.addListener(new RedisPubSubAdapter<String, String>() {
                @Override
                public void message(String channel, String message) {
                    System.out.println("Received Sentinel Event [" + channel + "]: " + message);
                    // 在这里可以处理 +switch-master 事件等
                }
            });

            // 订阅 +switch-master 事件
            pubSubConn.async().subscribe("+switch-master");

            // 保持程序运行以接收事件
            Thread.sleep(60000); // Wait for 1 minute

            pubSubConn.close();
            connection.close();

        } catch (Exception e) {
            System.err.println("Lettuce Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            client.shutdown();
        }
    }
}
🌟 Lettuce 的优势
  • 自动重连与事件驱动: Lettuce 能够自动处理网络中断和故障转移,通过订阅 Sentinel 事件,应用可以实时感知主节点的变化。
  • 异步与响应式支持: 支持 CompletableFuture、Reactive Streams(Project Reactor),非常适合高并发场景。
  • 连接共享: 多个线程可以安全地共享同一个 StatefulRedisConnection,减少了资源消耗。

🛡️ 生产环境最佳实践

在生产环境中部署 Redis Sentinel 集群,需要考虑更多的因素来确保系统的稳定性、安全性和可维护性。

🧱 架构设计建议

  1. 至少部署 3 个 Sentinel 节点: 这是最小推荐数量,可以容忍一个 Sentinel 节点故障。理想情况下,将 Sentinel 节点分散在不同的物理服务器或可用区(Availability Zone)上,避免单点故障。
  2. 奇数个 Sentinel 节点: 推荐使用 3、5、7 个 Sentinel 节点。奇数个节点可以避免在投票时出现平局的情况,确保故障转移决策的顺利进行。
  3. 独立部署 vs 共存部署: Sentinel 进程可以与 Redis 实例部署在同一台服务器上,也可以独立部署。独立部署更安全,但成本更高。共存部署时,需确保服务器资源充足,避免相互影响。
  4. 跨机房/区域部署: 对于要求极高的系统,可以考虑跨机房部署 Sentinel 和 Redis 实例,实现异地多活。但这会增加网络延迟和复杂性,需要仔细权衡。

🔐 安全配置

  1. 启用认证: 为 Redis 主从节点和 Sentinel 节点设置强密码。在 redis.conf 中使用 requirepass,在 sentinel.conf 中使用 sentinel auth-pass
  2. 绑定私有网络: 将 Redis 和 Sentinel 服务绑定到内网 IP 地址,避免暴露在公网。
  3. 防火墙规则: 配置防火墙,只允许必要的端口(如 6379、26379)在受信任的 IP 范围内访问。
  4. 定期更新: 及时升级 Redis 到最新稳定版本,修复已知的安全漏洞。

📊 监控与告警

  • 监控 Sentinel 状态: 使用 Prometheus + Grafana 或 Zabbix 等工具监控 Sentinel 的 num-other-sentinelsnum-slavesdown-after-milliseconds 等关键指标。
  • 日志分析: 定期检查 Redis 和 Sentinel 的日志文件,及时发现异常。
  • 设置告警: 当 Sentinel 触发故障转移(+switch-master 事件)或节点下线(+sdown/-sdown)时,通过邮件、短信或钉钉等方式通知运维人员。

🧪 故障演练

定期进行故障演练是检验高可用系统有效性的最佳方式。

  1. 手动模拟主节点宕机: 使用 kill 命令终止主节点的进程。
  2. 观察 Sentinel 日志: 查看 Sentinel 是否正确检测到故障,并成功执行了故障转移。
  3. 验证数据一致性: 检查新主节点上的数据是否完整,从节点是否已正确切换到新的主节点。
  4. 测试客户端连接: 确认 Java 应用能够自动连接到新的主节点,业务不受影响。

🧰 常见问题与故障排查

在实际运维过程中,可能会遇到各种问题。以下是一些常见问题及其解决方案。

❌ 问题1:Sentinel 无法发现从节点

现象: SENTINEL replicas mymaster 命令返回空或不完整的列表。

原因: 从节点未正确配置 replicaof 指令,或网络不通。

解决方法:

  • 检查从节点的 redis.conf 文件,确认 replicaof 指向正确的主节点 IP 和端口。
  • 使用 pingtelnet 测试网络连通性。
  • 检查防火墙设置。

❌ 问题2:故障转移失败

现象: 主节点宕机后,长时间没有新的主节点被选举出来。

原因: Sentinel quorum 未达到,或领导者选举失败。

解决方法:

  • 检查 sentinel monitor 配置中的 quorum 值是否合理。例如,在 3 个 Sentinel 的集群中,quorum 应设为 2。
  • 确保大多数 Sentinel 节点在线且能相互通信。
  • 检查 down-after-milliseconds 设置是否过长。

❌ 问题3:客户端连接不上

现象: Java 应用抛出连接异常。

原因: 客户端配置错误,或 Sentinel 返回了错误的主节点地址。

解决方法:

  • 确认 JedisSentinelPoolRedisClient 配置的 master name 和 Sentinel 地址正确无误。
  • 使用 redis-cli 连接到 Sentinel,执行 SENTINEL get-master-addr-by-name mymaster 验证当前主节点地址。
  • 检查客户端网络是否能访问 Redis 和 Sentinel 端口。

📚 总结

通过本文的详细讲解,我们已经全面掌握了 Redis Sentinel 的核心原理、部署步骤、Java 客户端集成以及生产环境的最佳实践。Redis Sentinel 不仅仅是一个故障转移工具,它是一个完整的高可用性解决方案,为我们的 Redis 集群提供了强有力的保障。

回顾一下关键要点:

  • Sentinel 的三大功能:监控、通知、自动故障转移,缺一不可。
  • 合理的架构设计:至少 3 个 Sentinel 节点,分散部署,避免单点故障。
  • Java 客户端集成:Jedis 和 Lettuce 都能很好地支持 Sentinel,选择适合你项目需求的客户端。
  • 安全与监控:生产环境必须重视安全配置和实时监控,防患于未然。
  • 定期演练:通过故障演练验证系统的可靠性,确保在真实故障发生时能够从容应对。

高可用性不是一蹴而就的,它需要我们在架构设计、部署实施、运维管理等各个环节都精益求精。希望这篇指南能成为你构建稳定、可靠 Redis 集群的得力助手。

最后,别忘了访问以下资源,进一步深化你的 Redis 技能:

祝你在 Redis 的世界里探索愉快,构建出坚不可摧的数据基石!🏰✨


🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐