梅琴 發表於 2025-9-17 11:55:51

Redis 高可用与集群原理深度解析

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">Redis 高可用与集群原理</a></li><ul class="second_class_ul"><li><a href="#_lab2_0_0">1. 前言</a></li><li><a href="#_lab2_0_1">2. Redis 高可用架构演进</a></li><li><a href="#_lab2_0_2">3. Sentinel 哨兵机制</a></li><ul class="third_class_ul"><li><a href="#_label3_0_2_0">3.1 Sentinel 的作用</a></li><li><a href="#_label3_0_2_1">3.2 故障检测机制</a></li><li><a href="#_label3_0_2_2">3.3 Leader 选举</a></li><li><a href="#_label3_0_2_3">3.4 源码剖析(sentinel.c)</a></li></ul><li><a href="#_lab2_0_3">4. Redis Cluster 集群架构</a></li><ul class="third_class_ul"><li><a href="#_label3_0_3_4">4.1 核心特性</a></li><li><a href="#_label3_0_3_5">4.2 集群拓扑</a></li><li><a href="#_label3_0_3_6">4.3 请求路由</a></li></ul><li><a href="#_lab2_0_4">5. Gossip 协议</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_0_5">6. 故障转移源码剖析</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_0_6">7. 总结</a></li><ul class="third_class_ul"></ul></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>Redis 高可用与集群原理</h2>
<p class="maodian"><a name="_lab2_0_0"></a></p><h3>1. 前言</h3>
<p>Redis 单机虽然高性能,但一旦节点宕机,数据丢失或服务不可用问题会非常严重。为了解决这一问题,Redis 提供了<strong>主从复制、哨兵(Sentinel)、Cluster 集群</strong> 等高可用机制。</p>
<p>这一篇文章我们重点拆解:</p>
<ul><li><strong>Sentinel 哨兵机制</strong>:如何发现故障、如何自动主从切换。</li><li><strong>Cluster 集群架构</strong>:如何实现分片存储与高可用。</li><li><strong>Gossip 协议</strong>:节点间如何通信。</li><li><strong>故障转移源码剖析</strong>:Redis 内部实现流程。</li></ul>
<p class="maodian"><a name="_lab2_0_1"></a></p><h3>2. Redis 高可用架构演进</h3>
<ul><li><strong>主从复制(Replication)</strong>
<ul><li>提供读写分离,但主节点宕机会导致服务中断,需要人工干预。</li></ul></li><li><strong>哨兵(Sentinel)</strong><ul><li>自动监控主节点健康,支持 <strong>自动故障转移</strong>。</li></ul></li><li><strong>Cluster 集群</strong><ul><li>支持 <strong>数据分片</strong>(水平扩展),并内置高可用。</li></ul></li></ul>
<p>👉 可以理解为:<br /><strong>复制 = 数据冗余</strong><br /><strong>Sentinel = 自动运维</strong><br /><strong>Cluster = 扩展能力 + 内置高可用</strong></p>
<p class="maodian"><a name="_lab2_0_2"></a></p><h3>3. Sentinel 哨兵机制</h3>
<p class="maodian"><a name="_label3_0_2_0"></a></p><h4>3.1 Sentinel 的作用</h4>
<ul><li><strong>监控(Monitoring)</strong>:周期性检测 Master 和 Slave 是否可达。</li><li><strong>通知(Notification)</strong>:当节点异常时,向客户端/其他哨兵发送通知。</li><li><strong>故障转移(Failover)</strong>:自动将一个 Slave 提升为新的 Master,并让其他 Slave 复制它。</li></ul>
<p class="maodian"><a name="_label3_0_2_1"></a></p><h4>3.2 故障检测机制</h4>
<ul><li><strong>主观下线(SDOWN)</strong>:某个 Sentinel 认为 Master 不可达。</li><li><strong>客观下线(ODOWN)</strong>:多数 Sentinel 达成共识,确认 Master 宕机。</li></ul>
<p class="maodian"><a name="_label3_0_2_2"></a></p><h4>3.3 Leader 选举</h4>
<p>在多个 Sentinel 中,需要选出一个 <strong>Leader</strong> 来执行故障转移,算法基于 <strong>Raft 的选举思想</strong>:</p>
<ul><li>每个 Sentinel 给候选者投票。</li><li>超过半数票数的 Sentinel 当选 Leader。</li></ul>
<p class="maodian"><a name="_label3_0_2_3"></a></p><h4>3.4 源码剖析(sentinel.c)</h4>
<p>哨兵检测主观下线:</p>
<div class="jb51code"><pre class="brush:java;">// sentinel.c
if (mst-&gt;flags &amp; SRI_MASTER) {
    if ((mst-&gt;flags &amp; SRI_S_DOWN) == 0 &amp;&amp; mst-&gt;link-&gt;disconnected) {
      mst-&gt;flags |= SRI_S_DOWN; // 标记主观下线
      sentinelEvent(LL_WARNING, "+sdown", mst, "%@");
    }
}</pre></div>
<p>这段代码表明,当哨兵发现主节点无法连接时,会标记为 <strong>S_DOWN</strong>。</p>
<p class="maodian"><a name="_lab2_0_3"></a></p><h3>4. Redis Cluster 集群架构</h3>
<p class="maodian"><a name="_label3_0_3_4"></a></p><h4>4.1 核心特性</h4>
<ul><li><strong>分布式存储</strong>:采用 <strong>16384 个哈希槽</strong>(hash slots),每个节点负责一部分槽位。</li><li><strong>高可用</strong>:每个分片至少有 1 个 Master 和若干 Slave。</li><li><strong>自动故障转移</strong>:某个 Master 挂掉时,其 Slave 自动升级为新的 Master。</li></ul>
<p class="maodian"><a name="_label3_0_3_5"></a></p><h4>4.2 集群拓扑</h4>
<div class="jb51code"><pre class="brush:java;">         ┌───────────┐
         │   Client│
         └─────┬─────┘
               │
┌─────────────▼─────────────┐
│      Cluster            │
│ ┌────────┐   ┌────────┐   │
│ │ Master │   │ Master │   │ ...
│ │ Slot 0 │   │ Slot 5461│
│ └───▲────┘   └────▲───┘   │
│   │            │         │
│   ┌─┴─┐      ┌─┴─┐       │
│   │Slave│      │Slave│   │
│   └─────┘      └─────┘   │
└────────────────────────────┘</pre></div>
<p class="maodian"><a name="_label3_0_3_6"></a></p><h4>4.3 请求路由</h4>
<ul><li>Client 向某个节点发起请求。</li><li>如果 Key 不在本节点的槽位范围,返回 <code>MOVED</code> 重定向。</li><li>客户端更新槽位映射表,下次直连正确节点。</li></ul>
<p class="maodian"><a name="_lab2_0_4"></a></p><h3>5. Gossip 协议</h3>
<p>Redis Cluster 中节点通信依赖 <strong>Gossip 协议</strong>,类似于 <strong>流言传播</strong>:</p>
<ul><li>每个节点周期性地向随机节点发送 <strong>PING</strong>。</li><li>接收节点返回 <strong>PONG</strong>,附带自己已知的集群信息。</li><li>这样集群拓扑信息逐渐在所有节点中收敛。</li></ul>
<p>消息类型:</p>
<ul><li><strong>MEET</strong>:新节点加入。</li><li><strong>PING/PONG</strong>:心跳检测与状态同步。</li><li><strong>FAIL</strong>:节点失效信息。</li></ul>
<p>👉 Gossip 的特点是 <strong>去中心化、最终一致性</strong>。</p>
<p class="maodian"><a name="_lab2_0_5"></a></p><h3>6. 故障转移源码剖析</h3>
<p>当 Master 宕机时,Cluster 的转移逻辑如下:</p>
<ol><li><strong>检测故障</strong></li></ol>
<div class="jb51code"><pre class="brush:java;">// cluster.c
if (node-&gt;flags &amp; (CLUSTER_NODE_FAIL | CLUSTER_NODE_PFAIL)) {
    // 标记为下线
}</pre></div>
<ol start="2"><li><strong>Slave 竞选新 Master</strong></li></ol>
<ul><li>每个 Slave 会尝试升级为 Master。</li><li>使用投票机制,获得过半节点支持的 Slave 升级。</li></ul>
<ol start="3"><li><strong>重新分配槽位</strong></li></ol>
<div class="jb51code"><pre class="brush:java;">// cluster.c
clusterFailoverReplaceYourMaster();</pre></div>
<p>执行槽位迁移,客户端可继续访问。</p>
<ol start="4"><li><strong>客户端感知</strong></li></ol>
<ul><li>客户端收到 <code>MOVED</code> / <code>ASK</code>,刷新槽位映射。</li></ul>
<p class="maodian"><a name="_lab2_0_6"></a></p><h3>7. 总结</h3>
<p>本文深入分析了 Redis 高可用与集群原理:</p>
<ol><li><strong>Sentinel</strong>:实现了自动故障转移,基于 SDOWN/ODOWN 和选举机制。</li><li><strong>Cluster</strong>:通过哈希槽实现数据分片和自动转移。</li><li><strong>Gossip 协议</strong>:支撑集群中节点间的通信和状态同步。</li><li><strong>源码剖析</strong>:揭示了 Redis 在 <code>sentinel.c</code>、<code>cluster.c</code> 中的故障转移实现。</li></ol>
<p>📌 下一步可以写 <strong>Redis 持久化(RDB/AOF)与复制原理</strong>,这样整个高可用 + 数据可靠性体系就完整了。</p>
頁: [1]
查看完整版本: Redis 高可用与集群原理深度解析