云计算百科
云计算领域专业知识百科平台

Redis:Redis高可用——副本、哨兵和集群

文章目录

  • Redis高可用:副本、哨兵和集群
    • Redis 复制:高可用的基石
      • 数据同步机制
      • 复制 ID 与 偏移量
      • 完全重同步 的内部流程
      • 关键配置与安全注意事项
        • 禁用主节点持久化时的风险
        • 只读从节点
        • 最小写入副本数
        • 键的过期处理
      • 常用命令
    • Redis Sentinel:非集群模式下的高可用守护者
      • Sentinel 的核心职责
      • Sentinel 的分布式架构
        • 故障检测与转移流程
        • 主观下线 vs 客观下线
        • 法定人数 vs 多数派
        • 配置纪元
      • 部署最佳实践
        • 布局拓扑
        • 避免“脑裂”与数据丢失
      • 基本配置
    • Redis 集群:实现数据的水平扩展与高可用
      • 核心概念:数据分片与哈希槽
        • 数据流转示意图
        • 多键操作与 Hash Tags
      • 网络架构:双端口设计
      • 高可用与故障转移机制
        • 主从模型与自动切换
        • 一致性保证
      • 关键配置参数
      • 集群运维实战指南
        • 创建集群
        • 重分片
        • 增加与删除节点
      • 集群与复制、哨兵的关系
        • 集群中的主从节点是指 Redis 副本中的主从节点吗?
        • 故障自动恢复是否使用了哨兵?
        • 副本、哨兵、集群这三个是否可以同时使用?
      • 从其他模式迁移到集群

Redis高可用:副本、哨兵和集群

在构建 Redis 服务时,我们通常面临三个不同层级的需求:数据备份、故障自动恢复、以及海量数据存储。Redis 提供了三种核心模式来应对这些需求:主从复制、哨兵 和 集群。

  • 主从复制:这是最基础的数据冗余机制。数据单向流动,从主节点复制到一个或多个从节点。它主要用于数据备份和读写分离。它的特点是简单,但主节点宕机后需要人工介入或脚本处理故障转移,无法自动恢复。

#mermaid-svg-ASXHF7ih0k7SLjSv{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ASXHF7ih0k7SLjSv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ASXHF7ih0k7SLjSv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ASXHF7ih0k7SLjSv .error-icon{fill:#552222;}#mermaid-svg-ASXHF7ih0k7SLjSv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ASXHF7ih0k7SLjSv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ASXHF7ih0k7SLjSv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ASXHF7ih0k7SLjSv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ASXHF7ih0k7SLjSv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ASXHF7ih0k7SLjSv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ASXHF7ih0k7SLjSv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ASXHF7ih0k7SLjSv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ASXHF7ih0k7SLjSv .marker.cross{stroke:#333333;}#mermaid-svg-ASXHF7ih0k7SLjSv svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ASXHF7ih0k7SLjSv p{margin:0;}#mermaid-svg-ASXHF7ih0k7SLjSv .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ASXHF7ih0k7SLjSv .cluster-label text{fill:#333;}#mermaid-svg-ASXHF7ih0k7SLjSv .cluster-label span{color:#333;}#mermaid-svg-ASXHF7ih0k7SLjSv .cluster-label span p{background-color:transparent;}#mermaid-svg-ASXHF7ih0k7SLjSv .label text,#mermaid-svg-ASXHF7ih0k7SLjSv span{fill:#333;color:#333;}#mermaid-svg-ASXHF7ih0k7SLjSv .node rect,#mermaid-svg-ASXHF7ih0k7SLjSv .node circle,#mermaid-svg-ASXHF7ih0k7SLjSv .node ellipse,#mermaid-svg-ASXHF7ih0k7SLjSv .node polygon,#mermaid-svg-ASXHF7ih0k7SLjSv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ASXHF7ih0k7SLjSv .rough-node .label text,#mermaid-svg-ASXHF7ih0k7SLjSv .node .label text,#mermaid-svg-ASXHF7ih0k7SLjSv .image-shape .label,#mermaid-svg-ASXHF7ih0k7SLjSv .icon-shape .label{text-anchor:middle;}#mermaid-svg-ASXHF7ih0k7SLjSv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ASXHF7ih0k7SLjSv .rough-node .label,#mermaid-svg-ASXHF7ih0k7SLjSv .node .label,#mermaid-svg-ASXHF7ih0k7SLjSv .image-shape .label,#mermaid-svg-ASXHF7ih0k7SLjSv .icon-shape .label{text-align:center;}#mermaid-svg-ASXHF7ih0k7SLjSv .node.clickable{cursor:pointer;}#mermaid-svg-ASXHF7ih0k7SLjSv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ASXHF7ih0k7SLjSv .arrowheadPath{fill:#333333;}#mermaid-svg-ASXHF7ih0k7SLjSv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ASXHF7ih0k7SLjSv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ASXHF7ih0k7SLjSv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ASXHF7ih0k7SLjSv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ASXHF7ih0k7SLjSv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ASXHF7ih0k7SLjSv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ASXHF7ih0k7SLjSv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ASXHF7ih0k7SLjSv .cluster text{fill:#333;}#mermaid-svg-ASXHF7ih0k7SLjSv .cluster span{color:#333;}#mermaid-svg-ASXHF7ih0k7SLjSv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ASXHF7ih0k7SLjSv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ASXHF7ih0k7SLjSv rect.text{fill:none;stroke-width:0;}#mermaid-svg-ASXHF7ih0k7SLjSv .icon-shape,#mermaid-svg-ASXHF7ih0k7SLjSv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ASXHF7ih0k7SLjSv .icon-shape p,#mermaid-svg-ASXHF7ih0k7SLjSv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ASXHF7ih0k7SLjSv .icon-shape rect,#mermaid-svg-ASXHF7ih0k7SLjSv .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ASXHF7ih0k7SLjSv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ASXHF7ih0k7SLjSv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ASXHF7ih0k7SLjSv :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

主从复制架构

写请求

读请求

读请求

读请求

异步复制

异步复制

客户端

主节点 Master负责写

从节点 Replica 1

从节点 Replica 2

  • 哨兵:哨兵是运行在特殊模式下的 Redis 进程,它监控主从复制架构。当主节点故障时,哨兵会自动投票选举从节点升级为主节点,实现高可用。它的特点是自动故障转移,系统更健壮。但数据仍在单个主节点上,内存容量受限于单机。

#mermaid-svg-MCI0Ak6GLorELYmr{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MCI0Ak6GLorELYmr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MCI0Ak6GLorELYmr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MCI0Ak6GLorELYmr .error-icon{fill:#552222;}#mermaid-svg-MCI0Ak6GLorELYmr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MCI0Ak6GLorELYmr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MCI0Ak6GLorELYmr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MCI0Ak6GLorELYmr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MCI0Ak6GLorELYmr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MCI0Ak6GLorELYmr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MCI0Ak6GLorELYmr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MCI0Ak6GLorELYmr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MCI0Ak6GLorELYmr .marker.cross{stroke:#333333;}#mermaid-svg-MCI0Ak6GLorELYmr svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MCI0Ak6GLorELYmr p{margin:0;}#mermaid-svg-MCI0Ak6GLorELYmr .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-MCI0Ak6GLorELYmr .cluster-label text{fill:#333;}#mermaid-svg-MCI0Ak6GLorELYmr .cluster-label span{color:#333;}#mermaid-svg-MCI0Ak6GLorELYmr .cluster-label span p{background-color:transparent;}#mermaid-svg-MCI0Ak6GLorELYmr .label text,#mermaid-svg-MCI0Ak6GLorELYmr span{fill:#333;color:#333;}#mermaid-svg-MCI0Ak6GLorELYmr .node rect,#mermaid-svg-MCI0Ak6GLorELYmr .node circle,#mermaid-svg-MCI0Ak6GLorELYmr .node ellipse,#mermaid-svg-MCI0Ak6GLorELYmr .node polygon,#mermaid-svg-MCI0Ak6GLorELYmr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MCI0Ak6GLorELYmr .rough-node .label text,#mermaid-svg-MCI0Ak6GLorELYmr .node .label text,#mermaid-svg-MCI0Ak6GLorELYmr .image-shape .label,#mermaid-svg-MCI0Ak6GLorELYmr .icon-shape .label{text-anchor:middle;}#mermaid-svg-MCI0Ak6GLorELYmr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MCI0Ak6GLorELYmr .rough-node .label,#mermaid-svg-MCI0Ak6GLorELYmr .node .label,#mermaid-svg-MCI0Ak6GLorELYmr .image-shape .label,#mermaid-svg-MCI0Ak6GLorELYmr .icon-shape .label{text-align:center;}#mermaid-svg-MCI0Ak6GLorELYmr .node.clickable{cursor:pointer;}#mermaid-svg-MCI0Ak6GLorELYmr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MCI0Ak6GLorELYmr .arrowheadPath{fill:#333333;}#mermaid-svg-MCI0Ak6GLorELYmr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MCI0Ak6GLorELYmr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MCI0Ak6GLorELYmr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MCI0Ak6GLorELYmr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MCI0Ak6GLorELYmr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MCI0Ak6GLorELYmr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MCI0Ak6GLorELYmr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MCI0Ak6GLorELYmr .cluster text{fill:#333;}#mermaid-svg-MCI0Ak6GLorELYmr .cluster span{color:#333;}#mermaid-svg-MCI0Ak6GLorELYmr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MCI0Ak6GLorELYmr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MCI0Ak6GLorELYmr rect.text{fill:none;stroke-width:0;}#mermaid-svg-MCI0Ak6GLorELYmr .icon-shape,#mermaid-svg-MCI0Ak6GLorELYmr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MCI0Ak6GLorELYmr .icon-shape p,#mermaid-svg-MCI0Ak6GLorELYmr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MCI0Ak6GLorELYmr .icon-shape rect,#mermaid-svg-MCI0Ak6GLorELYmr .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MCI0Ak6GLorELYmr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MCI0Ak6GLorELYmr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MCI0Ak6GLorELYmr :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

数据层 主从

哨兵监控层

监控

监控

监控

哨兵节点 1

哨兵节点 2

哨兵节点 3

主节点 Master

升为新主

从节点 Replica

故障时: 哨兵协商

  • 集群:集群是 Redis 的分布式解决方案。它将数据自动分片存储在多个主节点中,每个主节点都有从节点。它解决了单机内存限制和网络瓶颈问题。它的特点是自动分片、高可用、水平扩展。适用于海量数据和高并发场景,但客户端逻辑较复杂,且不支持跨节点的多键操作(如 Multi-key)。

#mermaid-svg-cym1hXhfY2q0foAS{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cym1hXhfY2q0foAS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cym1hXhfY2q0foAS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cym1hXhfY2q0foAS .error-icon{fill:#552222;}#mermaid-svg-cym1hXhfY2q0foAS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cym1hXhfY2q0foAS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cym1hXhfY2q0foAS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cym1hXhfY2q0foAS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cym1hXhfY2q0foAS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cym1hXhfY2q0foAS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cym1hXhfY2q0foAS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cym1hXhfY2q0foAS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cym1hXhfY2q0foAS .marker.cross{stroke:#333333;}#mermaid-svg-cym1hXhfY2q0foAS svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cym1hXhfY2q0foAS p{margin:0;}#mermaid-svg-cym1hXhfY2q0foAS .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-cym1hXhfY2q0foAS .cluster-label text{fill:#333;}#mermaid-svg-cym1hXhfY2q0foAS .cluster-label span{color:#333;}#mermaid-svg-cym1hXhfY2q0foAS .cluster-label span p{background-color:transparent;}#mermaid-svg-cym1hXhfY2q0foAS .label text,#mermaid-svg-cym1hXhfY2q0foAS span{fill:#333;color:#333;}#mermaid-svg-cym1hXhfY2q0foAS .node rect,#mermaid-svg-cym1hXhfY2q0foAS .node circle,#mermaid-svg-cym1hXhfY2q0foAS .node ellipse,#mermaid-svg-cym1hXhfY2q0foAS .node polygon,#mermaid-svg-cym1hXhfY2q0foAS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cym1hXhfY2q0foAS .rough-node .label text,#mermaid-svg-cym1hXhfY2q0foAS .node .label text,#mermaid-svg-cym1hXhfY2q0foAS .image-shape .label,#mermaid-svg-cym1hXhfY2q0foAS .icon-shape .label{text-anchor:middle;}#mermaid-svg-cym1hXhfY2q0foAS .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cym1hXhfY2q0foAS .rough-node .label,#mermaid-svg-cym1hXhfY2q0foAS .node .label,#mermaid-svg-cym1hXhfY2q0foAS .image-shape .label,#mermaid-svg-cym1hXhfY2q0foAS .icon-shape .label{text-align:center;}#mermaid-svg-cym1hXhfY2q0foAS .node.clickable{cursor:pointer;}#mermaid-svg-cym1hXhfY2q0foAS .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cym1hXhfY2q0foAS .arrowheadPath{fill:#333333;}#mermaid-svg-cym1hXhfY2q0foAS .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cym1hXhfY2q0foAS .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cym1hXhfY2q0foAS .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cym1hXhfY2q0foAS .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cym1hXhfY2q0foAS .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cym1hXhfY2q0foAS .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cym1hXhfY2q0foAS .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cym1hXhfY2q0foAS .cluster text{fill:#333;}#mermaid-svg-cym1hXhfY2q0foAS .cluster span{color:#333;}#mermaid-svg-cym1hXhfY2q0foAS div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cym1hXhfY2q0foAS .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cym1hXhfY2q0foAS rect.text{fill:none;stroke-width:0;}#mermaid-svg-cym1hXhfY2q0foAS .icon-shape,#mermaid-svg-cym1hXhfY2q0foAS .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cym1hXhfY2q0foAS .icon-shape p,#mermaid-svg-cym1hXhfY2q0foAS .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cym1hXhfY2q0foAS .icon-shape rect,#mermaid-svg-cym1hXhfY2q0foAS .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cym1hXhfY2q0foAS .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cym1hXhfY2q0foAS .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cym1hXhfY2q0foAS :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

集群分片架构

Slot 10001-16383

Slot 5001-10000

Slot 0-5000

路由请求

路由请求

路由请求

主节点 A

从节点 A'

主节点 B

从节点 B'

主节点 C

从节点 C'

客户端

特性维度主从复制哨兵集群
核心目标 数据冗余、读写分离 自动故障转移 (高可用) 数据分片、水平扩展 (高并发+大容量)
数据分片 否,所有数据都在主节点 否,所有数据都在主节点 是,数据分散在多个主节点
在线扩容 手动添加从节点,不增加容量 手动添加节点,不增加容量 支持动态添加节点并重新分片
故障转移 需要人工介入或脚本 自动化 (Sentinel 选举) 自动化 (节点间通信投票)
运维复杂度 较高
客户端支持 所有客户端均支持 大多数客户端支持 需支持 Cluster 协议的客户端
网络分区容忍 主节点宕机不可写 少数 Sentinel 存活即可工作 多数 Master 存活即可工作 (需注意脑裂)
多键操作 支持 支持 仅当 key 在同一 slot 时支持 (使用 Hash Tag 解决)

Redis 复制:高可用的基石

Redis 的复制机制是实现数据备份、读取扩展和高可用性的基础。在最底层,它采用的是主从复制 模式。这种模式简单易用,允许一个或多个从节点成为主节点的精确副本。 无论主节点发生什么情况,从节点都会尝试自动重连并与其保持一致。

数据同步机制

Redis主要依赖以下三种机制来维持数据同步:

  • 命令传播:当主从连接正常时,主节点将接收到的写操作(客户端写入、键过期驱逐等)以命令流的形式发送给从节点。
  • 部分重同步:如果连接断开(网络抖动或超时),从节点重连后会尝试获取断开期间缺失的命令流。
  • 完全重同步:如果无法进行部分同步(例如缺失的数据太旧),从节点会请求完整的数据集快照。主节点会生成 RDB 文件发送给从节点,并同步缓冲区中的新写命令。
  • #mermaid-svg-WCw9v4wO6lHYTRY3{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WCw9v4wO6lHYTRY3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WCw9v4wO6lHYTRY3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WCw9v4wO6lHYTRY3 .error-icon{fill:#552222;}#mermaid-svg-WCw9v4wO6lHYTRY3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WCw9v4wO6lHYTRY3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WCw9v4wO6lHYTRY3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WCw9v4wO6lHYTRY3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WCw9v4wO6lHYTRY3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WCw9v4wO6lHYTRY3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WCw9v4wO6lHYTRY3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WCw9v4wO6lHYTRY3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WCw9v4wO6lHYTRY3 .marker.cross{stroke:#333333;}#mermaid-svg-WCw9v4wO6lHYTRY3 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WCw9v4wO6lHYTRY3 p{margin:0;}#mermaid-svg-WCw9v4wO6lHYTRY3 defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-WCw9v4wO6lHYTRY3 g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-WCw9v4wO6lHYTRY3 g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-WCw9v4wO6lHYTRY3 g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-WCw9v4wO6lHYTRY3 g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-WCw9v4wO6lHYTRY3 g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-WCw9v4wO6lHYTRY3 .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-WCw9v4wO6lHYTRY3 .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-WCw9v4wO6lHYTRY3 .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-WCw9v4wO6lHYTRY3 .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-WCw9v4wO6lHYTRY3 .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-WCw9v4wO6lHYTRY3 .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-WCw9v4wO6lHYTRY3 .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-WCw9v4wO6lHYTRY3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WCw9v4wO6lHYTRY3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WCw9v4wO6lHYTRY3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WCw9v4wO6lHYTRY3 .edgeLabel .label text{fill:#333;}#mermaid-svg-WCw9v4wO6lHYTRY3 .label div .edgeLabel{color:#333;}#mermaid-svg-WCw9v4wO6lHYTRY3 .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-WCw9v4wO6lHYTRY3 .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-WCw9v4wO6lHYTRY3 .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-WCw9v4wO6lHYTRY3 .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-WCw9v4wO6lHYTRY3 .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-WCw9v4wO6lHYTRY3 .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WCw9v4wO6lHYTRY3 .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WCw9v4wO6lHYTRY3 #statediagram-barbEnd{fill:#333333;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WCw9v4wO6lHYTRY3 .cluster-label,#mermaid-svg-WCw9v4wO6lHYTRY3 .nodeLabel{color:#131300;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-WCw9v4wO6lHYTRY3 .note-edge{stroke-dasharray:5;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-note text{fill:black;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram-note .nodeLabel{color:black;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagram .edgeLabel{color:red;}#mermaid-svg-WCw9v4wO6lHYTRY3 #dependencyStart,#mermaid-svg-WCw9v4wO6lHYTRY3 #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-WCw9v4wO6lHYTRY3 .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WCw9v4wO6lHYTRY3 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    接收命令流

    网络故障/超时

    重连成功且增量在缓冲区

    增量丢失或 ID 不匹配

    补齐缺失数据

    加载 RDB 及缓冲数据

    连接建立

    命令传播

    链路断开

    部分重同步

    完全重同步

    主节点持续发送写命令给从节点保持数据一致

    复制 ID 与 偏移量

    为了判断两个实例的数据是否一致,Redis 使用了两个概念:

    • 复制 ID:一个标记数据集特定历史的大型伪随机字符串。
    • 偏移量:一个随着处理复制流而不断递增的数字。

    如果两个实例拥有相同的 复制 ID 和 偏移量,它们的数据就是完全一致的。此外, Redis 实例实际上维护两个 ID:主 ID 和辅助 ID。这是为了处理故障转移 场景:

    • 当一个从节点被提升为主节点时,它会生成一个新的主 ID(开启新的历史)。
    • 同时,它将旧的主 ID 记为辅助 ID。
    • 作用:其他旧的从节点重连时,可以凭借辅助 ID 和偏移量进行“部分重同步”,而不必进行昂贵的“完全重同步”。这避免了网络分区导致旧主节点恢复时的 ID 冲突。

    完全重同步 的内部流程

    当需要进行完全同步时,Redis 会执行以下步骤。这是一个巧妙的后台处理过程,旨在不阻塞主线程:

    从节点

    磁盘

    主节点 (子进程)

    主节点 (父进程)

    客户端

    从节点

    磁盘

    主节点 (子进程)

    主节点 (父进程)

    客户端

    #mermaid-svg-LYPW2hXRjCPVgAlf{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LYPW2hXRjCPVgAlf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LYPW2hXRjCPVgAlf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LYPW2hXRjCPVgAlf .error-icon{fill:#552222;}#mermaid-svg-LYPW2hXRjCPVgAlf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LYPW2hXRjCPVgAlf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LYPW2hXRjCPVgAlf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LYPW2hXRjCPVgAlf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LYPW2hXRjCPVgAlf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LYPW2hXRjCPVgAlf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LYPW2hXRjCPVgAlf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LYPW2hXRjCPVgAlf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LYPW2hXRjCPVgAlf .marker.cross{stroke:#333333;}#mermaid-svg-LYPW2hXRjCPVgAlf svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LYPW2hXRjCPVgAlf p{margin:0;}#mermaid-svg-LYPW2hXRjCPVgAlf .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-LYPW2hXRjCPVgAlf text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-LYPW2hXRjCPVgAlf .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-LYPW2hXRjCPVgAlf .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-LYPW2hXRjCPVgAlf .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-LYPW2hXRjCPVgAlf .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-LYPW2hXRjCPVgAlf #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-LYPW2hXRjCPVgAlf .sequenceNumber{fill:white;}#mermaid-svg-LYPW2hXRjCPVgAlf #sequencenumber{fill:#333;}#mermaid-svg-LYPW2hXRjCPVgAlf #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-LYPW2hXRjCPVgAlf .messageText{fill:#333;stroke:none;}#mermaid-svg-LYPW2hXRjCPVgAlf .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-LYPW2hXRjCPVgAlf .labelText,#mermaid-svg-LYPW2hXRjCPVgAlf .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-LYPW2hXRjCPVgAlf .loopText,#mermaid-svg-LYPW2hXRjCPVgAlf .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-LYPW2hXRjCPVgAlf .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-LYPW2hXRjCPVgAlf .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-LYPW2hXRjCPVgAlf .noteText,#mermaid-svg-LYPW2hXRjCPVgAlf .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-LYPW2hXRjCPVgAlf .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-LYPW2hXRjCPVgAlf .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-LYPW2hXRjCPVgAlf .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-LYPW2hXRjCPVgAlf .actorPopupMenu{position:absolute;}#mermaid-svg-LYPW2hXRjCPVgAlf .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-LYPW2hXRjCPVgAlf .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-LYPW2hXRjCPVgAlf .actor-man circle,#mermaid-svg-LYPW2hXRjCPVgAlf line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-LYPW2hXRjCPVgAlf :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    触发 BGSAVE

    此时从节点状态与主节点一致

    写入新数据

    缓存写命令到内存缓冲区

    Fork() 创建子进程

    生成 RDB 快照文件

    继续处理请求

    快照完成

    通知完成

    发送 RDB 文件

    保存 RDB 到本地

    加载 RDB 到内存

    发送缓冲区的增量命令

    • 无盘复制:如果磁盘 IO 是瓶颈,可以配置 repl-diskless-sync。子进程直接通过网络将 RDB 发送给从节点,跳过磁盘存储,提高同步速度。

    关键配置与安全注意事项

    禁用主节点持久化时的风险

    这是一个非常重要的安全警告。如果在复制配置中,主节点关闭了持久化(RDB/AOF),并且配置了自动重启,可能会导致数据彻底丢失。为了数据安全,强烈建议在主节点和从节点上都开启持久化。如果必须关闭主节点持久化,则绝不要配置自动重启。

    #mermaid-svg-NUjHuyGzgDJXT6mA{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NUjHuyGzgDJXT6mA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NUjHuyGzgDJXT6mA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NUjHuyGzgDJXT6mA .error-icon{fill:#552222;}#mermaid-svg-NUjHuyGzgDJXT6mA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NUjHuyGzgDJXT6mA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NUjHuyGzgDJXT6mA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NUjHuyGzgDJXT6mA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NUjHuyGzgDJXT6mA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NUjHuyGzgDJXT6mA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NUjHuyGzgDJXT6mA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NUjHuyGzgDJXT6mA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NUjHuyGzgDJXT6mA .marker.cross{stroke:#333333;}#mermaid-svg-NUjHuyGzgDJXT6mA svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NUjHuyGzgDJXT6mA p{margin:0;}#mermaid-svg-NUjHuyGzgDJXT6mA .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-NUjHuyGzgDJXT6mA .cluster-label text{fill:#333;}#mermaid-svg-NUjHuyGzgDJXT6mA .cluster-label span{color:#333;}#mermaid-svg-NUjHuyGzgDJXT6mA .cluster-label span p{background-color:transparent;}#mermaid-svg-NUjHuyGzgDJXT6mA .label text,#mermaid-svg-NUjHuyGzgDJXT6mA span{fill:#333;color:#333;}#mermaid-svg-NUjHuyGzgDJXT6mA .node rect,#mermaid-svg-NUjHuyGzgDJXT6mA .node circle,#mermaid-svg-NUjHuyGzgDJXT6mA .node ellipse,#mermaid-svg-NUjHuyGzgDJXT6mA .node polygon,#mermaid-svg-NUjHuyGzgDJXT6mA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NUjHuyGzgDJXT6mA .rough-node .label text,#mermaid-svg-NUjHuyGzgDJXT6mA .node .label text,#mermaid-svg-NUjHuyGzgDJXT6mA .image-shape .label,#mermaid-svg-NUjHuyGzgDJXT6mA .icon-shape .label{text-anchor:middle;}#mermaid-svg-NUjHuyGzgDJXT6mA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NUjHuyGzgDJXT6mA .rough-node .label,#mermaid-svg-NUjHuyGzgDJXT6mA .node .label,#mermaid-svg-NUjHuyGzgDJXT6mA .image-shape .label,#mermaid-svg-NUjHuyGzgDJXT6mA .icon-shape .label{text-align:center;}#mermaid-svg-NUjHuyGzgDJXT6mA .node.clickable{cursor:pointer;}#mermaid-svg-NUjHuyGzgDJXT6mA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NUjHuyGzgDJXT6mA .arrowheadPath{fill:#333333;}#mermaid-svg-NUjHuyGzgDJXT6mA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NUjHuyGzgDJXT6mA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NUjHuyGzgDJXT6mA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NUjHuyGzgDJXT6mA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NUjHuyGzgDJXT6mA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NUjHuyGzgDJXT6mA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NUjHuyGzgDJXT6mA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NUjHuyGzgDJXT6mA .cluster text{fill:#333;}#mermaid-svg-NUjHuyGzgDJXT6mA .cluster span{color:#333;}#mermaid-svg-NUjHuyGzgDJXT6mA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NUjHuyGzgDJXT6mA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NUjHuyGzgDJXT6mA rect.text{fill:none;stroke-width:0;}#mermaid-svg-NUjHuyGzgDJXT6mA .icon-shape,#mermaid-svg-NUjHuyGzgDJXT6mA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NUjHuyGzgDJXT6mA .icon-shape p,#mermaid-svg-NUjHuyGzgDJXT6mA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NUjHuyGzgDJXT6mA .icon-shape rect,#mermaid-svg-NUjHuyGzgDJXT6mA .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NUjHuyGzgDJXT6mA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NUjHuyGzgDJXT6mA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NUjHuyGzgDJXT6mA :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    灾难发生

    初始状态

    崩溃

    自动重启数据为空

    同步

    同步

    主 A无持久化

    从 B – 空

    从 C – 空

    X

    主 A – 空

    只读从节点

    默认情况下,从节点是只读的(replica-read-only yes)。这是为了防止误操作导致主从不一致。

    • 可写从节点:虽然 Redis 允许配置从节点可写,但这是不推荐的。
      • 写入的数据是临时的,同步后会被覆盖。
      • 写入不会被传播给下级的从节点(级联复制场景)。
      • 一旦从节点提升为主节点,这些临时数据可能会引发混乱。
    • 建议:如果需要在从节点上计算数据,使用 SORT_RO、EVAL_RO 等只读命令,而不是写入临时键。
    最小写入副本数

    为了增强数据安全性,您可以配置主节点:只有当至少 N 个从节点连接成功且延迟小于 M 秒时,才接受写操作。

    相关配置参数:

    • min-replicas-to-write <数量>
    • min-replicas-max-lag <秒数>

    这是一种“尽力而为”的数据安全机制,虽然不能保证强一致性(因为复制是异步的),但能将数据丢失的时间窗口限制在几秒钟内。

    键的过期处理

    Redis 复制中,键的过期是由主节点驱动的:

  • 主节点键过期 -> 生成 DEL 命令 -> 发送给从节点。
  • 从节点被动执行 DEL,不独立计算过期时间。
  • Lua 脚本:在脚本执行期间,主节点的逻辑时钟是“冻结”的,以保证主从执行脚本的结果一致。
  • 常用命令

    命令/配置用途
    INFO replication 查看复制状态、连接的从节点、偏移量等。
    ROLE 查看实例角色(master/replica)及其详细复制信息。
    replicaof <ip> <port> 将当前实例配置为指定地址的从节点。
    WAIT <replicas> <timeout> 阻塞当前客户端,直到写操作被指定数量的从节点确认(伪同步)。
    masterauth <password> 设置从节点连接主节点所需的密码。

    Redis Sentinel:非集群模式下的高可用守护者

    在上一节中,我们了解了 Redis 如何通过主从复制 来实现数据备份和读写分离。但是,单纯的主从复制有一个致命的弱点:主节点故障无法自动恢复。如果主节点宕机,从节点虽然拥有数据,但不会自动升级为主节点,除非有人工介入。 这就是 Redis Sentinel 登场的时刻。Sentinel 是 Redis 的高可用解决方案,它运行在特殊的模式下,负责监控、通知和自动故障转移。

    Sentinel 的核心职责

    Sentinel 不仅仅是一个简单的监控工具,它是一个完整的分布式系统,主要承担以下四个职责:

  • 监控:持续检查主节点和从节点是否正常运行。
  • 通知:当被监控的实例出现问题时,通过 API 通知系统管理员或其他程序。
  • 自动故障转移:这是核心功能。当主节点失效时,Sentinel 会发起故障转移流程:将一个从节点升级为新的主节点,重新配置其他从节点,并通知客户端新的地址。
  • 配置提供者:Sentinel 充当客户端的权威服务发现源。客户端连接 Sentinel 询问:“谁是当前的主节点?”,Sentinel 会返回最新的地址。如果发生故障转移,Sentinel 会自动更新这个地址。
  • Sentinel 的分布式架构

    Sentinel 本身被设计为一个分布式系统。这意味着您不能只运行一个 Sentinel 进程,否则 Sentinel 本身就成了单点故障。 为了实现高可用,您需要运行多个 Sentinel 进程协同工作。它们之间通过Gossip协议进行通信。

    故障检测与转移流程

    理解 Sentinel 的关键是区分主观下线 和 客观下线,以及法定人数 与 多数派 的概念。 下图展示了从主节点故障到完成故障转移的完整过程:

    客户端

    从节点 R

    Sentinel 3

    Sentinel 2

    Sentinel 1

    主节点 M

    客户端

    从节点 R

    Sentinel 3

    Sentinel 2

    Sentinel 1

    主节点 M

    #mermaid-svg-KWUm6Hho07hVws0V{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KWUm6Hho07hVws0V .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KWUm6Hho07hVws0V .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KWUm6Hho07hVws0V .error-icon{fill:#552222;}#mermaid-svg-KWUm6Hho07hVws0V .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KWUm6Hho07hVws0V .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KWUm6Hho07hVws0V .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KWUm6Hho07hVws0V .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KWUm6Hho07hVws0V .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KWUm6Hho07hVws0V .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KWUm6Hho07hVws0V .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KWUm6Hho07hVws0V .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KWUm6Hho07hVws0V .marker.cross{stroke:#333333;}#mermaid-svg-KWUm6Hho07hVws0V svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KWUm6Hho07hVws0V p{margin:0;}#mermaid-svg-KWUm6Hho07hVws0V .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-KWUm6Hho07hVws0V text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-KWUm6Hho07hVws0V .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-KWUm6Hho07hVws0V .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-KWUm6Hho07hVws0V .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-KWUm6Hho07hVws0V .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-KWUm6Hho07hVws0V #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-KWUm6Hho07hVws0V .sequenceNumber{fill:white;}#mermaid-svg-KWUm6Hho07hVws0V #sequencenumber{fill:#333;}#mermaid-svg-KWUm6Hho07hVws0V #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-KWUm6Hho07hVws0V .messageText{fill:#333;stroke:none;}#mermaid-svg-KWUm6Hho07hVws0V .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-KWUm6Hho07hVws0V .labelText,#mermaid-svg-KWUm6Hho07hVws0V .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-KWUm6Hho07hVws0V .loopText,#mermaid-svg-KWUm6Hho07hVws0V .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-KWUm6Hho07hVws0V .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-KWUm6Hho07hVws0V .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-KWUm6Hho07hVws0V .noteText,#mermaid-svg-KWUm6Hho07hVws0V .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-KWUm6Hho07hVws0V .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-KWUm6Hho07hVws0V .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-KWUm6Hho07hVws0V .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-KWUm6Hho07hVws0V .actorPopupMenu{position:absolute;}#mermaid-svg-KWUm6Hho07hVws0V .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-KWUm6Hho07hVws0V .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-KWUm6Hho07hVws0V .actor-man circle,#mermaid-svg-KWUm6Hho07hVws0V line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-KWUm6Hho07hVws0V :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    主节点宕机

    选举阶段

    连接断开

    1

    连接断开

    2

    超时未响应 (SDOWN)

    3

    超时未响应 (SDOWN)

    4

    确认主节点状态?

    5

    确认下线 (ODOWN

    达到法定人数)

    6

    投票请求 (我负责故障转移)

    7

    投票同意

    8

    投票请求

    9

    投票同意

    10

    SLAVEOF NO ONE

    (升级为主节点)

    11

    断开旧主连接

    12

    确认已升级

    13

    广播新配置 (Epoch +1)

    14

    广播新配置 (Epoch +1)

    15

    询问主节点地址?

    16

    返回新主节点地址

    17

    主观下线 vs 客观下线
    • SDOWN (Subjective Down):这是一个局部状态。单个 Sentinel 发现某个实例在 down-after-milliseconds 毫秒内没有回复 PING,就认为它主观下线了。
    • ODOWN (Objective Down):这是一个全局状态。当足够数量的 Sentinel(达到配置的 quorum)都认为主节点是 SDOWN 时,主节点被标记为 ODOWN。
    • 注意:只有主节点会被标记为 ODOWN。从节点或 Sentinel 故障通常不需要触发复杂的故障转移逻辑。
    法定人数 vs 多数派

    这两个参数决定了系统的敏感度和安全性,也是容易混淆的地方:

    • Quorum (法定人数):在 sentinel monitor <master-name> <ip> <port> <quorum> 中配置。
      • 作用:标记主节点为 ODOWN。
      • 例子:如果有 5 个 Sentinel,Quorum 设为 2。只要有 2 个 Sentinel 认为主节点挂了,主节点就会被标记为 ODOWN。
    • Majority (多数派):Sentinel 总数的一半 + 1。
      • 作用:授权执行故障转移。
      • 规则:即使主节点已经被标记为 ODOWN,Sentinel 依然必须获得多数派 的授权才能真正开始执行 slaveof no one 等操作。

    安全机制:这防止了“脑裂”。即使网络分区导致少数派 Sentinel 认为主节点挂了,它们无法获得多数派授权,因此不会启动故障转移。

    配置纪元

    这是 Sentinel 的版本号机制。每次成功进行故障转移,配置纪元 就会 +1。

    • 当 Sentinel 广播新的配置(主节点变更)时,会附带这个纪元号。
    • 纪元号大的配置被视为“更新”,会覆盖旧的配置。
    • 这保证了所有 Sentinel 最终会收敛到同一个配置(最终一致性)。

    部署最佳实践

    为了构建一个健壮的 Sentinel 部署,请遵循以下原则:

    布局拓扑

    推荐的拓扑(三节点部署): 将 Sentinel 和 Redis 进程分布在三个独立的物理机或虚拟机上。

    #mermaid-svg-HCdwRTxY5vJa8iN5{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HCdwRTxY5vJa8iN5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HCdwRTxY5vJa8iN5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HCdwRTxY5vJa8iN5 .error-icon{fill:#552222;}#mermaid-svg-HCdwRTxY5vJa8iN5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HCdwRTxY5vJa8iN5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HCdwRTxY5vJa8iN5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HCdwRTxY5vJa8iN5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HCdwRTxY5vJa8iN5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HCdwRTxY5vJa8iN5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HCdwRTxY5vJa8iN5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HCdwRTxY5vJa8iN5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HCdwRTxY5vJa8iN5 .marker.cross{stroke:#333333;}#mermaid-svg-HCdwRTxY5vJa8iN5 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HCdwRTxY5vJa8iN5 p{margin:0;}#mermaid-svg-HCdwRTxY5vJa8iN5 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-HCdwRTxY5vJa8iN5 .cluster-label text{fill:#333;}#mermaid-svg-HCdwRTxY5vJa8iN5 .cluster-label span{color:#333;}#mermaid-svg-HCdwRTxY5vJa8iN5 .cluster-label span p{background-color:transparent;}#mermaid-svg-HCdwRTxY5vJa8iN5 .label text,#mermaid-svg-HCdwRTxY5vJa8iN5 span{fill:#333;color:#333;}#mermaid-svg-HCdwRTxY5vJa8iN5 .node rect,#mermaid-svg-HCdwRTxY5vJa8iN5 .node circle,#mermaid-svg-HCdwRTxY5vJa8iN5 .node ellipse,#mermaid-svg-HCdwRTxY5vJa8iN5 .node polygon,#mermaid-svg-HCdwRTxY5vJa8iN5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HCdwRTxY5vJa8iN5 .rough-node .label text,#mermaid-svg-HCdwRTxY5vJa8iN5 .node .label text,#mermaid-svg-HCdwRTxY5vJa8iN5 .image-shape .label,#mermaid-svg-HCdwRTxY5vJa8iN5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-HCdwRTxY5vJa8iN5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HCdwRTxY5vJa8iN5 .rough-node .label,#mermaid-svg-HCdwRTxY5vJa8iN5 .node .label,#mermaid-svg-HCdwRTxY5vJa8iN5 .image-shape .label,#mermaid-svg-HCdwRTxY5vJa8iN5 .icon-shape .label{text-align:center;}#mermaid-svg-HCdwRTxY5vJa8iN5 .node.clickable{cursor:pointer;}#mermaid-svg-HCdwRTxY5vJa8iN5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HCdwRTxY5vJa8iN5 .arrowheadPath{fill:#333333;}#mermaid-svg-HCdwRTxY5vJa8iN5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HCdwRTxY5vJa8iN5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HCdwRTxY5vJa8iN5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HCdwRTxY5vJa8iN5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HCdwRTxY5vJa8iN5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HCdwRTxY5vJa8iN5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HCdwRTxY5vJa8iN5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HCdwRTxY5vJa8iN5 .cluster text{fill:#333;}#mermaid-svg-HCdwRTxY5vJa8iN5 .cluster span{color:#333;}#mermaid-svg-HCdwRTxY5vJa8iN5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HCdwRTxY5vJa8iN5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HCdwRTxY5vJa8iN5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-HCdwRTxY5vJa8iN5 .icon-shape,#mermaid-svg-HCdwRTxY5vJa8iN5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HCdwRTxY5vJa8iN5 .icon-shape p,#mermaid-svg-HCdwRTxY5vJa8iN5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HCdwRTxY5vJa8iN5 .icon-shape rect,#mermaid-svg-HCdwRTxY5vJa8iN5 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HCdwRTxY5vJa8iN5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HCdwRTxY5vJa8iN5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HCdwRTxY5vJa8iN5 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    物理机 3

    物理机 2

    物理机 1

    监控

    监控

    监控

    Redis Master

    Sentinel 1

    Redis Replica 1

    Sentinel 2

    Redis Replica 2

    Sentinel 3

    关键配置:

    • Quorum 设置为 2:这意味着需要至少 2 个 Sentinel 同意主节点挂了,才能触发 ODOWN。
    • 优势:
      • 如果物理机 1 宕机(M1 和 S1 挂了),剩下的 S2 和 S3 依然构成多数派(2/3),可以授权 S2 或 S3 进行故障转移。
      • 客户端连接到剩下的 S2/S3 依然可以获取新主节点信息。
    避免“脑裂”与数据丢失

    由于 Redis 复制是异步的,在网络分区发生时,旧的主节点可能仍然接受写入,而新的主节点已经产生。当分区恢复时,旧主节点会被重新配置为从节点,导致其上的写入数据丢失。

    缓解措施: 在 Redis 配置中启用 min-replicas-to-write:

    min-replicas-to-write 1
    min-replicas-max-lag 10

    这意味着:主节点必须至少能写入 1 个从节点,否则拒绝写请求。在网络分区发生时,旧主节点会迅速失去连接,从而停止接受写入,大大减少数据丢失窗口。

    基本配置

    一个最小的 sentinel.conf 示例:

    # 监控名为 mymaster 的主节点,IP 127.0.0.1,端口 6379,法定人数为 2
    sentinel monitor mymaster 127.0.0.1 6379 2

    # 30秒内无响应视为主观下线
    sentinel down-after-milliseconds mymaster 30000

    # 故障转移超时时间(3分钟)
    sentinel failover-timeout mymaster 180000

    # 故障转移时,同时有多少个从节点同步新主节点(数字越小对网络影响越小)
    sentinel parallel-syncs mymaster 1

    Redis 集群:实现数据的水平扩展与高可用

    在之前的章节中,我们探讨了“主从复制”(数据冗余)和“哨兵”(高可用监控)。虽然这两个功能组合在一起可以提供一个非常健壮的单节点 Redis 服务,但它们受限于单机的内存大小和 CPU 性能。当数据量达到几十 TB 或者单机吞吐量成为瓶颈时,我们需要 Redis Cluster。 Redis Cluster 是 Redis 的分布式解决方案,它提供了自动分片 和 高可用 的能力。它将数据自动分割到多个节点上,从而实现水平扩展,同时内置了故障恢复机制。

    核心概念:数据分片与哈希槽

    Redis Cluster 不使用传统的一致性哈希,而是使用一种称为 哈希槽 的概念。

    • 总槽位数:集群共有 16384 个哈希槽。
    • 计算方式:每个 Key 根据其名称计算哈希值:CRC16(key) % 16384。
    • 分配:这 16384 个槽位被分配给集群中的不同主节点。
    数据流转示意图

    下图展示了一个 Key 是如何被路由到特定节点的,以及 Key 如何在分片中工作:

    #mermaid-svg-oAzYDfWF94nHTWHU{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-oAzYDfWF94nHTWHU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-oAzYDfWF94nHTWHU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-oAzYDfWF94nHTWHU .error-icon{fill:#552222;}#mermaid-svg-oAzYDfWF94nHTWHU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-oAzYDfWF94nHTWHU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-oAzYDfWF94nHTWHU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-oAzYDfWF94nHTWHU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-oAzYDfWF94nHTWHU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-oAzYDfWF94nHTWHU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-oAzYDfWF94nHTWHU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-oAzYDfWF94nHTWHU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-oAzYDfWF94nHTWHU .marker.cross{stroke:#333333;}#mermaid-svg-oAzYDfWF94nHTWHU svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-oAzYDfWF94nHTWHU p{margin:0;}#mermaid-svg-oAzYDfWF94nHTWHU .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-oAzYDfWF94nHTWHU .cluster-label text{fill:#333;}#mermaid-svg-oAzYDfWF94nHTWHU .cluster-label span{color:#333;}#mermaid-svg-oAzYDfWF94nHTWHU .cluster-label span p{background-color:transparent;}#mermaid-svg-oAzYDfWF94nHTWHU .label text,#mermaid-svg-oAzYDfWF94nHTWHU span{fill:#333;color:#333;}#mermaid-svg-oAzYDfWF94nHTWHU .node rect,#mermaid-svg-oAzYDfWF94nHTWHU .node circle,#mermaid-svg-oAzYDfWF94nHTWHU .node ellipse,#mermaid-svg-oAzYDfWF94nHTWHU .node polygon,#mermaid-svg-oAzYDfWF94nHTWHU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-oAzYDfWF94nHTWHU .rough-node .label text,#mermaid-svg-oAzYDfWF94nHTWHU .node .label text,#mermaid-svg-oAzYDfWF94nHTWHU .image-shape .label,#mermaid-svg-oAzYDfWF94nHTWHU .icon-shape .label{text-anchor:middle;}#mermaid-svg-oAzYDfWF94nHTWHU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-oAzYDfWF94nHTWHU .rough-node .label,#mermaid-svg-oAzYDfWF94nHTWHU .node .label,#mermaid-svg-oAzYDfWF94nHTWHU .image-shape .label,#mermaid-svg-oAzYDfWF94nHTWHU .icon-shape .label{text-align:center;}#mermaid-svg-oAzYDfWF94nHTWHU .node.clickable{cursor:pointer;}#mermaid-svg-oAzYDfWF94nHTWHU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-oAzYDfWF94nHTWHU .arrowheadPath{fill:#333333;}#mermaid-svg-oAzYDfWF94nHTWHU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-oAzYDfWF94nHTWHU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-oAzYDfWF94nHTWHU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oAzYDfWF94nHTWHU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-oAzYDfWF94nHTWHU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oAzYDfWF94nHTWHU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-oAzYDfWF94nHTWHU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-oAzYDfWF94nHTWHU .cluster text{fill:#333;}#mermaid-svg-oAzYDfWF94nHTWHU .cluster span{color:#333;}#mermaid-svg-oAzYDfWF94nHTWHU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-oAzYDfWF94nHTWHU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-oAzYDfWF94nHTWHU rect.text{fill:none;stroke-width:0;}#mermaid-svg-oAzYDfWF94nHTWHU .icon-shape,#mermaid-svg-oAzYDfWF94nHTWHU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oAzYDfWF94nHTWHU .icon-shape p,#mermaid-svg-oAzYDfWF94nHTWHU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-oAzYDfWF94nHTWHU .icon-shape rect,#mermaid-svg-oAzYDfWF94nHTWHU .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oAzYDfWF94nHTWHU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-oAzYDfWF94nHTWHU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-oAzYDfWF94nHTWHU :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    Redis Cluster 架构

    节点与槽位映射

    取模 16384

    槽位 0-5000

    Master-Sentinel

    Master-Sentinel

    Master-Sentinel

    请求

    重定向

    返回数据

    客户端

    Key: user:1001

    计算 CRC16

    Hash Slot 1234

    Master A

    Slot 5001-10000

    Master B

    Slot 10001-16383

    Master C

    Replica A1

    Replica B1

    Replica C1

    优势:

    • 轻松扩容:添加新节点时,只需将一部分槽位从旧节点迁移到新节点。
    • 在线迁移:数据迁移过程不需要停止服务。
    多键操作与 Hash Tags

    Redis Cluster 限制:涉及多个 Key 的操作(如 MGET, SUNION)必须作用在同一个槽位上。 如果需要跨键操作,可以使用 Hash Tags:

    • 如果 Key 包含 {…} 这样的子字符串,只有 {} 内的内容参与哈希计算。
    • 例如:user:{123}:profile 和 user:{123}:orders 会被分配到同一个槽位,因此可以一起操作。

    网络架构:双端口设计

    为了保证集群内部通信的高效,每个 Redis Cluster 节点需要开放两个 TCP 端口:

  • 客户端端口:例如 6379。用于服务客户端请求,以及节点间的数据迁移。
  • 集群总线端口:默认为客户端端口 + 10000(例如 16379)。
    • 这是一个节点对节点的通信通道,使用二进制协议,带宽和处理开销更低。
    • 用于故障检测、配置更新、故障转移授权等。
    • 注意:客户端不应连接此端口,但防火墙必须开放此端口给其他集群节点。
  • 高可用与故障转移机制

    主从模型与自动切换

    为了保持高可用,集群中的每个主节点都可以有多个从节点。故障转移流程(内置机制):

  • 主节点 A 宕机。
  • 集群内其他主节点通过 Cluster Bus 感知 A 下线(Gossip协议)。
  • 主节点 A 的从节点(如 A1)发起投票。
  • 多数派主节点同意后,A1 被提升为新的主节点。
  • 集群更新路由表:A1 负责 A 原本的槽位。
  • 一致性保证

    Redis Cluster 不保证强一致性。它是最终一致的系统,这意味着在某些故障场景下,已经确认的写入可能会丢失。原因:

  • 异步复制:客户端向主节点 B 写入数据 -> B 返回 OK -> B 异步发送给从节点 B1。如果 B 在发送给 B1 之前崩溃,B1 提升为主节点,这条数据就丢失了。
  • 网络分区(脑裂):
    • 集群被分割为两部分。
    • 多数派(拥有大多数 Master)侧会继续工作,并选举新的主节点。
    • 少数派(被隔离的旧 Master)侧在超过 cluster-node-timeout 时间后,会停止接受写入。
    • 如果在超时之前,客户端继续向少数派的旧 Master 写入数据,这些数据在分区愈合后将丢失。
  • 关键配置参数

    在 redis.conf 中,Cluster 模式引入了以下关键参数:

    • cluster-enabled <yes/no>:是否启用集群模式。
    • cluster-config-file <filename>:节点状态自动保存的文件(非人工编辑)。
    • cluster-node-timeout <milliseconds>:
      • 节点被视为失效的超时时间。
      • 也是控制分区场景下少数派何时停止写入的关键参数。
    • cluster-slave-validity-factor <factor>:控制从节点在断开连接多久后不再尝试发起故障转移(0 表示总是尝试)。
    • cluster-require-full-coverage <yes/no>:
      • 默认为 yes:如果有一部分槽位没有被任何节点覆盖,集群停止接受写入。
      • 设置为 no:即使部分槽位不可用,集群仍处理其他请求。
    • cluster-allow-reads-when-down <yes/no>:是否允许在集群标记为失败(标记为 down)时,节点处理只读请求。

    集群运维实战指南

    创建集群

    最小推荐配置是 3 主 3 从(共 6 个节点)。 使用 redis-cli 工具快速创建:

    redis-cli –cluster create 127.0.0.1:7000 127.0.0.1:7001 \\
    127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 \\
    127.0.0.1:7005 –cluster-replicas 1

    • –cluster-replicas 1 表示每个主节点自动分配一个从节点。
    • 命令执行后,系统会自动分配 16384 个槽位。
    重分片

    用于平衡数据负载。

    redis-cli –cluster reshard 127.0.0.1:7000

    工具会引导您:

  • 要移动多少个槽位?
  • 接收槽位的目标节点 ID 是什么?
  • 从哪些源节点移动?
  • 增加与删除节点
  • 添加新主节点:
    • 启动一个配置好的空 Redis 实例(如端口 7006)。
    • 执行 redis-cli –cluster add-node 127.0.0.1:7006 127.0.0.1:7000。
    • 此时节点已加入,但没有槽位。需要通过 Resharding(重分片)分配槽位给它。
  • 添加新从节点:
    • 启动空实例。
    • 执行 redis-cli –cluster add-node … –cluster-slave。它会自动复制给某个副本较少的主节点。
  • 删除节点:
    • 如果是从节点,直接用 redis-cli –cluster del-node 删除。
    • 如果是主节点,必须先通过 Resharding 将其槽位全部移出,使其变空,然后才能删除。
  • 集群与复制、哨兵的关系

    集群中的主从节点是指 Redis 副本中的主从节点吗?

    是的,完全一致。

    Redis Cluster 中的“主节点”和“从节点”,本质就是我们在前面“主从复制”章节中介绍的同一个东西。

    • 集群主节点:就是一个开启了 cluster-enabled yes 的普通 Redis 主节点,只是它还负责管理一部分哈希槽。
    • 集群从节点:就是一个开启了 cluster-enabled yes 的普通 Redis 从节点。它通过标准的 PSYNC 命令从主节点同步数据。

    唯一的区别在于:

    • 普通复制:主节点通常只有 1 个,从节点负责备份或分担读压力。
    • 集群复制:主节点有多个,每个主节点负责不同的数据(槽位),从节点跟随它对应的主节点。您可以这样理解:Cluster 就像是一个由多个“主从复制小组”组成的大联盟。
    故障自动恢复是否使用了哨兵?

    没有,完全独立。

    Redis Cluster 不依赖 哨兵 来进行故障转移。它拥有一套完全独立的、内置的高可用机制。

    • 哨兵模式:Sentinel 是运行在 Redis 外部 的独立进程,作为“监察员”监控 Redis。它通过投票和决策来发起故障转移。
    • 集群模式:故障转移的逻辑集成在 Redis 节点内部。节点之间通过二进制的 Cluster Bus(集群总线)交换信息。当主节点 A 宕机,它的从节点 A1、A2 之间会通过 Gossip 协议感知,并进行内部投票,直接将 A1 提升为主节点。

    关键区别:

    • 如果您使用 Sentinel,您的架构里必须运行 Sentinel 进程。
    • 如果您使用 Cluster,您的架构里不需要 运行 Sentinel 进程,Cluster 自己就能搞定。
    副本、哨兵、集群这三个是否可以同时使用?

    这是一个关于架构选型的问题。答案是:机制上可以混合,但架构上通常是互斥的。

    我们要分清“机制”和“解决方案”两个层面:

    • Redis 复制:这是底层机制。Cluster 本身就是建立在复制之上的,所以集群肯定用了复制。
    • Sentinel vs Cluster:这是两个并列的高可用/扩展解决方案。不要混用。

    为什么不建议混用 Sentinel 和 Cluster?

    • 功能重复:Sentinel 管监控和故障转移,Cluster 也能管监控和故障转移。同时用就是画蛇添足。
    • 逻辑冲突:Sentinel 不理解“槽位”的概念。如果 Cluster 发生了主节点切换,Sentinel 可能无法正确感知 Cluster 的拓扑状态,反之亦然。

    正确的架构选择路径:

    需求场景推荐方案包含的技术关系说明
    简单缓存 单机 Redis 最基础模式。
    数据安全 + 读写分离 主从复制 副本机制 基础模式 + 冗余备份。
    自动故障恢复 (单机数据量) 哨兵 + 主从复制 副本机制 + Sentinel 哨兵作为外挂的大脑,监控主从。这是最经典的生产配置。
    海量数据 (单机存不下) + 高并发 Redis Cluster 副本机制 + 集群逻辑 集群自带高可用能力,不需要 Sentinel。

    从其他模式迁移到集群

    如果您目前在使用单机或 Sentinel 模式,想要迁移到 Cluster:

  • 停止客户端:目前不支持热迁移。
  • 生成 AOF 文件:对现有主节点执行 BGREWRITEAOF。
  • 创建空集群:启动 N 个新的 Cluster 节点,不分配数据。
  • 替换数据:停止新节点,将生成的 AOF 文件复制到对应的新节点目录中。
  • 启动并修复:启动新节点。它们会加载 AOF 数据。使用 redis-cli –cluster fix 命令将 Key 迁移到正确的槽位对应的节点上。
  • 切换客户端:更新客户端使用支持 Cluster 的库,并重新上线。
  • 赞(0)
    未经允许不得转载:网硕互联帮助中心 » Redis:Redis高可用——副本、哨兵和集群
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!