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

Redis高可用架构深度解析:主从、哨兵、集群架构选型与实践指南

文章目录

  • 前言
  • 一、Redis主从复制架构
    • 1.1 架构原理
    • 1.2 核心机制详解
      • 1.2.1 复制过程
      • 1.2.2 断线续传机制
    • 1.3 生产环境痛点
      • 痛点1:主从延迟导致的数据不一致
      • 痛点2:复制缓冲区溢出
  • 二、哨兵模式深度剖析
    • 2.1 架构演进
    • 2.2 核心功能实现
      • 2.2.1 监控机制
      • 2.2.2 故障转移流程
    • 2.3 生产环境脑裂实战案例
  • 三、Redis Cluster集群架构
    • 3.1 架构设计
    • 3.2 核心机制详解
      • 3.2.1 槽位计算原理
      • 3.2.2 批量操作优化实战
        • 场景1:用户维度的批量查询
      • 场景2:多维度数据关联
    • 3.3 集群故障转移实战
      • 3.3.1 故障检测机制
      • 3.3.2 故障转移源码级分析
  • 四、生产环境选型实战指南
    • 4.1 业务场景1:中小型电商系统
    • 4.2 业务场景2:大型社交平台
    • 4.3 业务场景3:金融支付系统
  • 五、架构选型决策树
  • 六、总结与最佳实践
    • 6.1 各架构适用场景速查表
    • 6.2 生产环境避坑指南
    • 6.3 性能调优清单

前言

作为一名Java后端工程师,我在8年的职业生涯中经历了多次Redis架构演进。从最初的单机版,到主从复制,再到哨兵模式,最后演进到Cluster集群,每一次升级都伴随着业务的指数级增长。本文将结合实战经验,深入剖析这三种架构的核心原理、生产问题及选型策略。


一、Redis主从复制架构

1.1 架构原理

主从复制是实现Redis高可用的基础架构。一个Master节点负责写操作,多个Slave节点负责读操作,数据通过异步复制从Master同步到Slave。

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

复制原理

ReplicationID复制ID

Offset复制偏移量

环形缓冲区积压队列

客户端

主节点读写操作

全量/增量同步

从节点2只读

从节点3只读

1.2 核心机制详解

1.2.1 复制过程

# 从节点执行命令
SLAVEOF 192.168.1.100 6379

# 复制过程三个阶段:
1. 连接建立:从节点保存主节点信息
2. 全量复制:主节点生成RDB发送给从节点
3. 增量复制:主节点持续发送写命令

1.2.2 断线续传机制

Master

Slave

Master

Slave

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

正常复制中

网络断开

重新连接

alt

[offset在积压队列内]

[offset已过期]

REPLCONF ACK {offset}

PSYNC {replid} {offset}

检查offset是否在积压队列

CONTINUE

发送积压数据

FULLRESYNC {new_replid}

全量同步RDB

1.3 生产环境痛点

痛点1:主从延迟导致的数据不一致

// 场景:用户下单后立即查询订单
public Order createOrder(Order order) {
redisTemplate.opsForValue().set("order:" + order.getId(), order);

// 立即查询,可能路由到从库
Order queryOrder = redisTemplate.opsForValue().get("order:" + order.getId());
if (queryOrder == null) {
// 数据还没同步到从库
throw new BusinessException("订单创建失败,请重试");
}
return queryOrder;
}

// 解决方案:强制读主库
@RedisRoute(master = true)
public Order getOrder(String orderId) {
return redisTemplate.opsForValue().get("order:" + orderId);
}

痛点2:复制缓冲区溢出

# 配置优化
# redis.conf
repl-backlog-size 256mb # 默认1MB,建议增大
client-output-buffer-limit slave 256mb 64mb 60 # 从节点缓冲区限制

二、哨兵模式深度剖析

2.1 架构演进

为了解决主从架构无法自动故障转移的问题,Redis 2.8引入了哨兵机制。哨兵本身也是一个集群,通常部署3个或5个奇数节点。

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

Redis节点

哨兵集群

Sentinel-1192.168.1.10:26379

Sentinel-2192.168.1.11:26379

Sentinel-3192.168.1.12:26379

Master192.168.1.100:6379

Slave-1192.168.1.101:6379

Slave-2192.168.1.102:6379

客户端通过哨兵发现主节点

2.2 核心功能实现

2.2.1 监控机制

# 哨兵配置
sentinel monitor mymaster 192.168.1.100 6379 2 # 2表示需要2个哨兵同意
sentinel down-after-milliseconds mymaster 30000 # 30秒无响应判定为下线
sentinel failover-timeout mymaster 180000 # 故障转移超时时间
sentinel parallel-syncs mymaster 1 # 同时同步的从节点数量

2.2.2 故障转移流程

Client

其他Slave

Slave节点

Master(故障)

Sentinel-3

Sentinel-2

Sentinel-1

Client

其他Slave

Slave节点

Master(故障)

Sentinel-3

Sentinel-2

Sentinel-1

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

阶段1:主观下线

网络分区

sdown

阶段2:客观下线

odown(达到quorum=2)

阶段3:选举Leader

成为Leader

阶段4:选举新Master

过滤掉不健康的节点

优先级最高的成为新Master

阶段5:重新配置

PING

超时

SENTINEL is-master-down-by-addr

SENTINEL is-master-down-by-addr

同意下线

同意下线

请求投票

投票给S1

投票给S1

获取从节点列表

slaveof no one

成为新Master

slaveof 新Master

发布配置变更通知

2.3 生产环境脑裂实战案例

案例背景 某电商公司使用Redis哨兵架构,双11大促期间发生网络抖动,导致主节点与哨兵集群网络分区。

问题复现

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

交换机B区域

交换机A区域

原Master仍在运行

客户端1继续写入

Sentinel-1

Sentinel-2

Sentinel-3

新选举的Master

客户端2写入新主

网络中断10分钟

数据丢失分析

// 原Master上10分钟的写入量
// 假设QPS=5000,10分钟=300万条数据全部丢失

// 大促期间用户投诉:订单状态不一致、优惠券使用记录丢失
// 业务损失:约50万订单数据异常

解决方案

# 哨兵配置优化
sentinel down-after-milliseconds mymaster 10000 # 缩短检测时间,从30s改为10s

# Redis配置优化
min-slaves-to-write 2 # 至少2个从节点在线才能写入
min-slaves-max-lag 5 # 从节点延迟不超过5秒

# 应用层优化
@Component
public class RedisWriteGuard {
@Value("${redis.master.count}")
private int expectedMasterCount = 1;

public void writeWithGuard(String key, Object value) {
// 检查当前Redis实例是否是真正的Master
String role = redisTemplate.opsForValue().get("redis:role:check");
if (role == null) {
// 可能是脑裂产生的Master,拒绝写入
throw new RedisBrainSplitException("检测到脑裂风险,拒绝写入");
}
// 正常写入
redisTemplate.opsForValue().set(key, value);
}
}

三、Redis Cluster集群架构

3.1 架构设计

Redis 3.0推出的分布式解决方案,通过数据分片解决单机容量和写压力问题。

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

Cluster节点

Node1192.168.1.1:6379槽位:0-2730

Node2192.168.1.2:6379槽位:2731-5460

Node3192.168.1.3:6379槽位:5461-8190

Node4192.168.1.4:6379槽位:8191-10920

Node5192.168.1.5:6379槽位:10921-13650

Node6192.168.1.6:6379槽位:13651-16383

Node7Slave

Node8Slave

Node9Slave

Smart ClientJedisCluster/lettuce

3.2 核心机制详解

3.2.1 槽位计算原理

public class RedisClusterSlotCalculator {
// 16384个槽位
private static final int SLOT_COUNT = 16384;

/**
* 计算key的槽位
* CRC16(key) & 16383
*/

public static int calculateSlot(String key) {
// 处理Hash Tag
String hashKey = getHashKey(key);

// CRC16算法实现
int crc = CRC16.crc16(hashKey.getBytes());
return crc & (SLOT_COUNT 1);
}

/**
* 提取Hash Tag
* 规则:只计算第一个{和}之间的内容
*/

private static String getHashKey(String key) {
int s = key.indexOf("{");
if (s >= 0) {
int e = key.indexOf("}", s + 1);
if (e >= 0 && e != s + 1) {
return key.substring(s + 1, e);
}
}
return key;
}
}

3.2.2 批量操作优化实战

场景1:用户维度的批量查询

@Service
public class UserDataService {

/**
* 错误示例:key分散在不同节点
* 导致网络开销:3次网络请求
*/

public Map<String, Object> getUserDataBad(String userId) {
Map<String, Object> result = new HashMap<>();
// 这三个key可能分布在3个不同节点
result.put("profile", redisTemplate.opsForValue().get("user:" + userId + ":profile"));
result.put("orders", redisTemplate.opsForValue().get("user:" + userId + ":orders"));
result.put("points", redisTemplate.opsForValue().get("user:" + userId + ":points"));
return result;
}

/**
* 正确示例:使用Hash Tag
* 所有key在同一个节点,1次网络请求
*/

public List<Object> getUserDataGood(String userId) {
String hashTag = "{user:" + userId + "}";
List<String> keys = Arrays.asList(
hashTag + ":profile",
hashTag + ":orders",
hashTag + ":points"
);
// mget保证在一个节点执行
return redisTemplate.opsForValue().multiGet(keys);
}

/**
* 批量写入优化
*/

public void batchUpdateUserData(String userId, UserData data) {
String hashTag = "{user:" + userId + "}";
Map<String, Object> dataMap = new HashMap<>();
dataMap.put(hashTag + ":profile", data.getProfile());
dataMap.put(hashTag + ":orders", data.getOrders());
dataMap.put(hashTag + ":points", data.getPoints());

// 使用pipeline批量写入
redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
dataMap.forEach((key, value) -> {
connection.set(key.getBytes(),
SerializationUtils.serialize(value));
});
return null;
});
}
}

场景2:多维度数据关联

/**
* 电商订单维度查询优化
*/

@Component
public class OrderOptimizer {

/**
* 订单相关的多个维度
* 使用复合Hash Tag设计key
*/

public void storeOrderData(Order order) {
String orderTag = "{order:" + order.getOrderId() + "}";

// 所有相关key都在同一槽位
String orderKey = orderTag + ":basic";
String itemsKey = orderTag + ":items";
String logisKey = orderTag + ":logistics";
String paymentKey = orderTag + ":payment";

// pipeline批量写入
redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
connection.set(orderKey.getBytes(), order.toString().getBytes());
connection.set(itemsKey.getBytes(), order.getItems().toString().getBytes());
connection.set(logisKey.getBytes(), order.getLogistics().toString().getBytes());
connection.set(paymentKey.getBytes(), order.getPayment().toString().getBytes());
return null;
});
}

/**
* 批量查询订单数据
*/

public OrderVO getOrderDetail(String orderId) {
String orderTag = "{order:" + orderId + "}";
List<String> keys = Arrays.asList(
orderTag + ":basic",
orderTag + ":items",
orderTag + ":logistics",
orderTag + ":payment"
);

List<Object> values = redisTemplate.opsForValue().multiGet(keys);
// 组装数据
return assembleOrderVO(values);
}
}

3.3 集群故障转移实战

3.3.1 故障检测机制

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

故障检测流程

PING

PONG

PING超时

Gossip广播

Gossip广播

确认故障

确认故障

节点A

节点B

节点C

节点D

PFAIL状态

节点E

节点F

FAIL状态达成开始故障转移

3.3.2 故障转移源码级分析

// 模拟集群故障转移过程
public class ClusterFailoverSimulator {

/**
* 故障转移触发条件
*/

class FailoverCondition {
// 节点超时时间,默认15000ms
int clusterNodeTimeout = 15000;

// 主观下线阈值
int pfailCount = 1;

// 客观下线所需确认数
int failReportCount = clusterSize / 2 + 1;
}

/**
* 从节点选举算法
*/

class SlaveElection {
/**
* 优先级计算:
* 1. 复制偏移量越大优先级越高
* 2. 节点ID按字母排序
*/

public Slave selectNewMaster(List<Slave> slaves) {
return slaves.stream()
.filter(Slave::isHealthy)
.max(Comparator.comparing(Slave::getReplicationOffset)
.thenComparing(Slave::getNodeId))
.orElseThrow(() -> new NoMasterElectedException());
}

/**
* 投票机制
* 每个Master节点只有一票
* 获得半数以上票数的Slave成为新Master
*/

public boolean election(Slave candidate, int masterCount) {
int votes = candidate.requestVotes();
return votes > masterCount / 2;
}
}
}

四、生产环境选型实战指南

4.1 业务场景1:中小型电商系统

业务特征:

  • 数据量:50GB以内
  • QPS:读写混合5-10万
  • 可用性要求:99.95%
  • 预算:有限

架构方案:

部署架构:
1主2从 + 3哨兵哨兵

资源配置:
主节点:8核32G内存
从节点:8核32G内存
哨兵节点:2核4G (3台)

配置优化:
# redis.conf
maxmemory 24gb
maxmemorypolicy allkeyslru
save 900 1
save 300 10
save 60 10000

# sentinel.conf
sentinel monitor mymaster 192.168.1.10 6379 2
sentinel downaftermilliseconds mymaster 10000
sentinel failovertimeout mymaster 60000
sentinel parallelsyncs mymaster 1

监控告警:

@Component
public class SentinelMonitor {

@Scheduled(fixedDelay = 5000)
public void checkSentinelHealth() {
// 监控主从延迟
Long masterOffset = getMasterOffset();
List<Long> slaveOffsets = getSlaveOffsets();

for (Long slaveOffset : slaveOffsets) {
long delay = masterOffset slaveOffset;
if (delay > 10000) { // 延迟超过10000条命令
alert("从节点同步延迟过高:" + delay);
}
}

// 监控哨兵状态
int activeSentinels = getActiveSentinels();
if (activeSentinels < 3) {
alert("哨兵节点异常,当前存活:" + activeSentinels);
}
}
}

4.2 业务场景2:大型社交平台

业务特征:

  • 数据量:500GB+
  • QPS:写入10万+,读取50万+
  • 可用性要求:99.99%
  • 业务模块:用户关系、Feed流、消息队列

架构方案:

部署架构:
9节点集群(6主3从)

节点分布:
可用区A:主节点x2 + 从节点x1
可用区B:主节点x2 + 从节点x1
可用区C:主节点x2 + 从节点x1

资源配置:
主节点:16核64G内存
从节点:16核64G内存

配置优化:
# redis.conf
clusterenabled yes
clusterconfigfile nodes.conf
clusternodetimeout 5000
clusterrequirefullcoverage no
clustermigrationbarrier 1

# 网络优化
tcpbacklog 511
timeout 0
tcpkeepalive 300

分片策略设计:

@Component
public class ShardingStrategy {

/**
* 用户关系数据分片
* 按用户ID哈希分布
*/

public String getUserRelationKey(long userId) {
return "{relation:" + (userId % 1000) + "}:user:" + userId;
}

/**
* Feed流数据分片
* 按时间维度分片,避免热点
*/

public String getFeedKey(long timestamp) {
// 按小时分片
String hourTag = "feed:" + (timestamp / 3600000);
return "{" + hourTag + "}:data";
}

/**
* 热点key处理
* 使用本地缓存+分布式锁
*/

@Cacheable(value = "hot:user", key = "#userId")
public User getUserWithLocalCache(long userId) {
String lockKey = "{lock:user:" + userId + "}";
RLock lock = redissonClient.getLock(lockKey);

try {
if (lock.tryLock(1, 5, TimeUnit.SECONDS)) {
// 查Redis集群
return queryFromCluster(userId);
}
} finally {
lock.unlock();
}
return null;
}
}

4.3 业务场景3:金融支付系统

业务特征:

  • 数据强一致性要求
  • 不能容忍数据丢失
  • 严格的审计要求
  • 秒级故障恢复要求

架构方案:

部署架构:
3主3从集群 + 跨机房容灾

双机房部署:
主中心:3主 + 2从
备中心:1从 + 实时同步

数据一致性配置:
# redis.conf
minreplicastowrite 2
minreplicasmaxlag 2
wait 2 1000 # 等待至少2个从节点确认

clusterrequirefullcoverage yes
clusternodetimeout 3000

强一致性实现:

@Service
public class PaymentService {

@Autowired
private RedisTemplate<String, String> redisTemplate;

/**
* 支付事务:要求强一致性
*/

public boolean processPayment(Payment payment) {
String key = "payment:" + payment.getOrderId();
String lockKey = "{lock:" + key + "}";

// 分布式锁
RLock lock = redissonClient.getLock(lockKey);
try {
lock.lock(5, TimeUnit.SECONDS);

// 开启Redis事务
redisTemplate.setEnableTransactionSupport(true);
SessionCallback<Object> callback = new SessionCallback<Object>() {
@Override
public Object execute(RedisOperations operations) throws DataAccessException {
operations.multi();
try {
// 扣减余额
operations.opsForValue().decrement("balance:" + payment.getUserId(),
payment.getAmount());
// 记录支付流水
operations.opsForValue().set(key, payment.toString());
// 更新订单状态
operations.opsForValue().set("order:" + payment.getOrderId(),
"PAID");

// 执行事务并等待从节点确认
List<Object> results = operations.exec();
// WAIT命令确保数据同步到从节点
redisTemplate.execute((RedisCallback<Long>) connection ->
connection.waitReplicas(2, 1000));

return results;
} catch (Exception e) {
operations.discard();
throw e;
}
}
};

List<Object> results = redisTemplate.execute(callback);
return !results.contains(null);

} finally {
lock.unlock();
}
}

/**
* 数据核对机制
*/

@Scheduled(cron = "0 0/5 * * * ?")
public void verifyDataConsistency() {
// 对比主从数据
Long masterCount = getMasterDataCount();
Long slaveCount = getSlaveDataCount();

if (!masterCount.equals(slaveCount)) {
// 触发数据修复流程
triggerDataRepair();
// 发送告警
alert("Redis主从数据不一致!");
}
}
}

五、架构选型决策树

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

开始选型

数据量超过100GB?

写QPS超过5万?

Cluster集群

可用性要求99.95%以上?

哨兵模式

读写比例读远大于写?

主从复制+读写分离

确定架构

六、总结与最佳实践

6.1 各架构适用场景速查表

Redis 多业务场景架构选型与配置指南:

业务场景数据量级推荐架构核心配置注意事项与关键运维
缓存加速 < 10G 主从 + 哨兵 (Master-Slave + Sentinel) maxmemory-policy allkeys-lru maxmemory 8GB • 监控:重点关注哨兵监控状态与主从复制延迟。 • 驱逐:确保 maxmemory 设置略低于物理内存,避免OOM。
会话存储 < 50G 哨兵模式 (Sentinel) maxmemory-policy volatile-lru maxmemory 45GB • 过期策略:应用层必须设置合理的过期时间(expire),防止内存泄露。 • 高可用:哨兵数量至少3个,部署在不同物理机。
计数统计 < 100G Cluster 集群 cluster-node-timeout 5000 cluster-enabled yes • 数据分片:使用 Hash Tag (例如 {user123}:count)确保相关key位于同一slot,支持多key操作。 • 扩缩容:规划好slot数量,预先分配节点。
支付交易 < 500G 强一致性集群 (Cluster + 强同步) min-replicas-to-write 2 min-replicas-max-lag 5 appendonly yes appendfsync always • 持久化:必须开启AOF且为always刷盘,配合appendfsync保证数据不丢。 • 一致性:至少同步写入2个从节点,牺牲部分性能换取强一致性。 • 备份:定期备份AOF文件到远程存储。
社交Feed > 500G 大规模集群 (Cluster + 异地多活) cluster-migration-barrier 1 repl-backlog-size 512MB • 动态扩容:采用预分片(预创建较多slot)或支持在线扩容的集群方案(如Redis Cluster或Codis)。 • 大Key处理:避免存储用户时间线大Key,建议拆分为多个小Key或使用其他组件。 • 网络:保证节点间网络低延迟,适当增大repl-backlog以应对网络抖动。

6.2 生产环境避坑指南

内存爆炸预防:

# 限制单个key大小
# redis.conf
proto-max-bulk-len 100mb

# 监控大key
redis-cli –bigkeys

网络分区防护:

// 应用层熔断
@HystrixCommand(fallbackMethod = "fallbackGetFromDB",
commandProperties = {
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000")
})
public Object getFromRedis(String key) {
return redisTemplate.opsForValue().get(key);
}

版本升级策略:

# 集群滚动升级
1. 先升级从节点
2. 手动触发故障转移
3. 升级原主节点
4. 验证集群状态

# 升级前必须测试
redis-benchmark -h 127.0.0.1 -p 6379 -c 50 -n 10000

容量规划公式:

// 内存计算公式
total_memory = (data_size * (1 + replication_factor) * 1.5) + buffer_size

// 数据量增长预测
growth_rate = 30% // 年增长率
capacity_plan = current_size * (1 + growth_rate) ^ years

// 连接数规划
max_clients = (max_connections_per_instance * node_count) * 0.8

6.3 性能调优清单

操作系统优化:
vm.overcommit_memory=1
net.core.somaxconn=1024
transparent_hugepage=disabled

Redis配置优化:
maxclients 20000
timeout 0
tcpkeepalive 300
lazyfreelazyeviction yes
lazyfreelazyexpire yes
lazyfreelazyserverdel yes

监控指标:
命中率 > 90%
内存碎片率 < 1.5
主从延迟 < 1s
拒绝连接数 = 0
OOM killer次数 = 0


赞(0)
未经允许不得转载:网硕互联帮助中心 » Redis高可用架构深度解析:主从、哨兵、集群架构选型与实践指南
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!