Redis 7 实战:缓存/消息队列/分布式锁生产级实现

前言

💡 痛点 :Redis 只会 SET/GET?缓存穿透、击穿、雪崩怎么处理?消息队列用 Redis 靠谱吗?分布式锁怎么实现才安全?

🎯 解决方案 :从基础到生产级,系统讲解 Redis 7 在缓存、消息队列、分布式锁三大场景的实战方案。

Redis 7 是当前最稳定的 Redis 版本,引入了 Function、ACL 改进等新特性。本文将覆盖:
#mermaid-svg-v5lQpsxLxHGbB2at{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-v5lQpsxLxHGbB2at .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-v5lQpsxLxHGbB2at .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-v5lQpsxLxHGbB2at .error-icon{fill:#552222;}#mermaid-svg-v5lQpsxLxHGbB2at .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-v5lQpsxLxHGbB2at .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-v5lQpsxLxHGbB2at .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-v5lQpsxLxHGbB2at .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-v5lQpsxLxHGbB2at .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-v5lQpsxLxHGbB2at .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-v5lQpsxLxHGbB2at .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-v5lQpsxLxHGbB2at .marker{fill:#333333;stroke:#333333;}#mermaid-svg-v5lQpsxLxHGbB2at .marker.cross{stroke:#333333;}#mermaid-svg-v5lQpsxLxHGbB2at svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-v5lQpsxLxHGbB2at p{margin:0;}#mermaid-svg-v5lQpsxLxHGbB2at .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-v5lQpsxLxHGbB2at .cluster-label text{fill:#333;}#mermaid-svg-v5lQpsxLxHGbB2at .cluster-label span{color:#333;}#mermaid-svg-v5lQpsxLxHGbB2at .cluster-label span p{background-color:transparent;}#mermaid-svg-v5lQpsxLxHGbB2at .label text,#mermaid-svg-v5lQpsxLxHGbB2at span{fill:#333;color:#333;}#mermaid-svg-v5lQpsxLxHGbB2at .node rect,#mermaid-svg-v5lQpsxLxHGbB2at .node circle,#mermaid-svg-v5lQpsxLxHGbB2at .node ellipse,#mermaid-svg-v5lQpsxLxHGbB2at .node polygon,#mermaid-svg-v5lQpsxLxHGbB2at .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-v5lQpsxLxHGbB2at .rough-node .label text,#mermaid-svg-v5lQpsxLxHGbB2at .node .label text,#mermaid-svg-v5lQpsxLxHGbB2at .image-shape .label,#mermaid-svg-v5lQpsxLxHGbB2at .icon-shape .label{text-anchor:middle;}#mermaid-svg-v5lQpsxLxHGbB2at .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-v5lQpsxLxHGbB2at .rough-node .label,#mermaid-svg-v5lQpsxLxHGbB2at .node .label,#mermaid-svg-v5lQpsxLxHGbB2at .image-shape .label,#mermaid-svg-v5lQpsxLxHGbB2at .icon-shape .label{text-align:center;}#mermaid-svg-v5lQpsxLxHGbB2at .node.clickable{cursor:pointer;}#mermaid-svg-v5lQpsxLxHGbB2at .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-v5lQpsxLxHGbB2at .arrowheadPath{fill:#333333;}#mermaid-svg-v5lQpsxLxHGbB2at .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-v5lQpsxLxHGbB2at .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-v5lQpsxLxHGbB2at .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-v5lQpsxLxHGbB2at .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-v5lQpsxLxHGbB2at .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-v5lQpsxLxHGbB2at .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-v5lQpsxLxHGbB2at .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-v5lQpsxLxHGbB2at .cluster text{fill:#333;}#mermaid-svg-v5lQpsxLxHGbB2at .cluster span{color:#333;}#mermaid-svg-v5lQpsxLxHGbB2at 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-v5lQpsxLxHGbB2at .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-v5lQpsxLxHGbB2at rect.text{fill:none;stroke-width:0;}#mermaid-svg-v5lQpsxLxHGbB2at .icon-shape,#mermaid-svg-v5lQpsxLxHGbB2at .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-v5lQpsxLxHGbB2at .icon-shape p,#mermaid-svg-v5lQpsxLxHGbB2at .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-v5lQpsxLxHGbB2at .icon-shape .label rect,#mermaid-svg-v5lQpsxLxHGbB2at .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-v5lQpsxLxHGbB2at .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-v5lQpsxLxHGbB2at .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-v5lQpsxLxHGbB2at :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 🚀 Redis 7 实战
📦 缓存实战
📨 消息队列实战
🔒 分布式锁实战
⚙️ 生产级配置
基础缓存
三大问题解决
多级缓存
Pub/Sub
Stream
延迟队列
基础锁
Redisson
红锁算法
内存优化
持久化
集群方案


一、Redis 7 核心特性回顾

1.1 数据结构速查

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

字符串
Hash

哈希
List

列表
Set

集合
ZSet

有序集合
Stream

数据结构选型指南:

数据结构 时间复杂度 典型场景
String O(1) 缓存、计数器、分布式锁
Hash O(1) 对象存储、购物车
List O(n) 消息队列、最新列表
Set O(1) 去重、标签、共同好友
ZSet O(log n) 排行榜、延迟队列
Stream O(1) 消息队列、事件溯源

1.2 Redis 7 新特性

特性 说明 影响
Functions 替代 Lua 脚本,更好管理 复杂逻辑
ACL v2 细粒度权限控制 安全性
Sharded Pub/Sub 分片 Pub/Sub 扩展性
Multi-part AOF AOF 优化 性能 + 可靠性
CIDR ACL 支持 IP 段权限 运维

二、缓存实战

2.1 基础缓存模式

🗄️ 数据库 📦 Redis 🖥️ 应用 🖥️ 客户端 🗄️ 数据库 📦 Redis 🖥️ 应用 🖥️ 客户端 #mermaid-svg-du2EUI3gypgjnNqQ{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-du2EUI3gypgjnNqQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-du2EUI3gypgjnNqQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-du2EUI3gypgjnNqQ .error-icon{fill:#552222;}#mermaid-svg-du2EUI3gypgjnNqQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-du2EUI3gypgjnNqQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-du2EUI3gypgjnNqQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-du2EUI3gypgjnNqQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-du2EUI3gypgjnNqQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-du2EUI3gypgjnNqQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-du2EUI3gypgjnNqQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-du2EUI3gypgjnNqQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-du2EUI3gypgjnNqQ .marker.cross{stroke:#333333;}#mermaid-svg-du2EUI3gypgjnNqQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-du2EUI3gypgjnNqQ p{margin:0;}#mermaid-svg-du2EUI3gypgjnNqQ .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-du2EUI3gypgjnNqQ text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-du2EUI3gypgjnNqQ .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-du2EUI3gypgjnNqQ .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-du2EUI3gypgjnNqQ .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-du2EUI3gypgjnNqQ .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-du2EUI3gypgjnNqQ #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-du2EUI3gypgjnNqQ .sequenceNumber{fill:white;}#mermaid-svg-du2EUI3gypgjnNqQ #sequencenumber{fill:#333;}#mermaid-svg-du2EUI3gypgjnNqQ #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-du2EUI3gypgjnNqQ .messageText{fill:#333;stroke:none;}#mermaid-svg-du2EUI3gypgjnNqQ .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-du2EUI3gypgjnNqQ .labelText,#mermaid-svg-du2EUI3gypgjnNqQ .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-du2EUI3gypgjnNqQ .loopText,#mermaid-svg-du2EUI3gypgjnNqQ .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-du2EUI3gypgjnNqQ .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-du2EUI3gypgjnNqQ .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-du2EUI3gypgjnNqQ .noteText,#mermaid-svg-du2EUI3gypgjnNqQ .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-du2EUI3gypgjnNqQ .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-du2EUI3gypgjnNqQ .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-du2EUI3gypgjnNqQ .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-du2EUI3gypgjnNqQ .actorPopupMenu{position:absolute;}#mermaid-svg-du2EUI3gypgjnNqQ .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-du2EUI3gypgjnNqQ .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-du2EUI3gypgjnNqQ .actor-man circle,#mermaid-svg-du2EUI3gypgjnNqQ line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-du2EUI3gypgjnNqQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt 缓存命中 缓存未命中 GET cache_key 返回缓存值 响应 NULL SELECT * FROM ... 返回数据 SET cache_key value EX 3600 响应

Python 实现
python 复制代码
"""
基础缓存读写
"""
import redis
import json
from typing import Optional, Any
from functools import wraps

# 连接 Redis
r = redis.Redis(
    host='localhost',
    port=6379,
    db=0,
    decode_responses=True,
    socket_timeout=5,
    retry_on_timeout=True,
    health_check_interval=30
)

def cache_get(key: str) -> Optional[Any]:
    """获取缓存"""
    value = r.get(key)
    if value is None:
        return None
    try:
        return json.loads(value)
    except (json.JSONDecodeError, TypeError):
        return value

def cache_set(key: str, value: Any, ttl: int = 3600):
    """设置缓存"""
    serialized = json.dumps(value, ensure_ascii=False) if not isinstance(value, str) else value
    r.setex(key, ttl, serialized)

# 缓存装饰器
def cached(key_prefix: str, ttl: int = 3600):
    """缓存装饰器"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 生成缓存 key
            cache_key = f"{key_prefix}:{hash(str(args) + str(kwargs))}"
            
            # 尝试读取缓存
            cached_value = cache_get(cache_key)
            if cached_value is not None:
                return cached_value
            
            # 执行函数
            result = func(*args, **kwargs)
            
            # 写入缓存
            if result is not None:
                cache_set(cache_key, result, ttl)
            
            return result
        return wrapper
    return decorator

# 使用示例
@cached("user:info", ttl=1800)
def get_user_info(user_id: int) -> dict:
    """获取用户信息(自动缓存)"""
    # 模拟数据库查询
    db_result = {"id": user_id, "name": "张三", "age": 25}
    return db_result

2.2 三大缓存问题与解决

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

Cache Penetration
击穿

Cache Breakdown
雪崩

Cache Avalanche
查询不存在的数据
方案:布隆过滤器

空值缓存
热点 key 过期
方案:互斥锁

永不过期 + 逻辑过期
大量 key 同时过期
方案:随机 TTL

多级缓存

问题 1:缓存穿透

场景:查询不存在的数据,每次都打到数据库。

python 复制代码
"""
缓存穿透解决方案
"""
from pybloom_live import ScalableBloomFilter

# 方案 1:布隆过滤器
bloom = ScalableBloomFilter(initial_capacity=100000, error_rate=0.001)

def init_bloom_filter():
    """初始化布隆过滤器(加载所有存在的 key)"""
    for user_id in db.query("SELECT id FROM users"):
        bloom.add(f"user:{user_id}")

def get_user_with_bloom(user_id: int) -> Optional[dict]:
    """布隆过滤器 + 缓存"""
    cache_key = f"user:{user_id}"
    
    # 1. 布隆过滤器判断
    if cache_key not in bloom:
        return None  # 一定不存在,直接返回
    
    # 2. 查缓存
    cached = cache_get(cache_key)
    if cached is not None:
        return cached
    
    # 3. 查数据库
    user = db.query("SELECT * FROM users WHERE id = ?", user_id)
    if user:
        cache_set(cache_key, user)
        return user
    
    return None

# 方案 2:空值缓存
def get_user_with_null_cache(user_id: int) -> Optional[dict]:
    """空值缓存防止穿透"""
    cache_key = f"user:{user_id}"
    
    cached = cache_get(cache_key)
    if cached is not None:
        if cached == "__NULL__":
            return None  # 空值缓存,说明不存在
        return cached
    
    user = db.query("SELECT * FROM users WHERE id = ?", user_id)
    if user:
        cache_set(cache_key, user, ttl=3600)
    else:
        # 缓存空值,短过期时间
        cache_set(cache_key, "__NULL__", ttl=60)
    
    return user
问题 2:缓存击穿

场景:热点 key 过期瞬间,大量并发打到数据库。

python 复制代码
"""
缓存击穿解决方案
"""
import threading

lock_cache = {}  # 简单锁缓存

def get_user_with_mutex(user_id: int) -> Optional[dict]:
    """互斥锁方案:只允许一个线程重建缓存"""
    cache_key = f"user:{user_id}"
    
    # 1. 查缓存
    cached = cache_get(cache_key)
    if cached is not None:
        return cached
    
    # 2. 获取分布式锁
    lock_key = f"lock:{cache_key}"
    
    # 使用 SET NX EX 实现简单分布式锁
    acquired = r.set(lock_key, "1", nx=True, ex=10)
    
    if acquired:
        try:
            # 双重检查:可能其他线程已经重建了缓存
            cached = cache_get(cache_key)
            if cached is not None:
                return cached
            
            # 查数据库
            user = db.query("SELECT * FROM users WHERE id = ?", user_id)
            if user:
                cache_set(cache_key, user, ttl=3600)
                return user
        finally:
            # 释放锁
            r.delete(lock_key)
    else:
        # 获取锁失败,短暂等待后重试
        import time
        time.sleep(0.1)
        return get_user_with_mutex(user_id)  # 递归重试
    
    return None


def get_user_with_logical_expire(user_id: int) -> dict:
    """逻辑过期方案:热点 key 永不过期"""
    cache_key = f"user:{user_id}"
    
    cached = cache_get(cache_key)
    if cached is not None:
        # 检查逻辑过期时间
        if cached.get("_expire_at", 0) > time.time():
            return cached["data"]  # 未过期
        
        # 逻辑过期,异步更新(不阻塞请求)
        import threading
        threading.Thread(
            target=refresh_cache,
            args=(user_id,)
        ).start()
        
        return cached["data"]  # 返回旧数据
    
    # 首次加载
    user = db.query("SELECT * FROM users WHERE id = ?", user_id)
    cache_data = {
        "data": user,
        "_expire_at": time.time() + 3600
    }
    cache_set(cache_key, cache_data, ttl=86400 * 7)  # 物理过期 7 天
    return user

def refresh_cache(user_id: int):
    """异步刷新缓存"""
    user = db.query("SELECT * FROM users WHERE id = ?", user_id)
    cache_key = f"user:{user_id}"
    cache_data = {
        "data": user,
        "_expire_at": time.time() + 3600
    }
    cache_set(cache_key, cache_data, ttl=86400 * 7)
问题 3:缓存雪崩

场景:大量 key 同时过期,数据库压力暴增。

python 复制代码
"""
缓存雪崩解决方案
"""
import random

def cache_set_with_jitter(key: str, value: Any, base_ttl: int = 3600):
    """随机 TTL 防止同时过期"""
    jitter = random.randint(-base_ttl // 10, base_ttl // 10)
    actual_ttl = base_ttl + jitter
    cache_set(key, value, actual_ttl)

# 方案对比
solutions = {
    "随机TTL": "在基础 TTL 上加随机抖动,避免同时过期",
    "多级缓存": "本地缓存 + Redis 缓存,即使 Redis 全挂,本地还能撑住",
    "缓存预热": "系统启动时主动加载热点数据到缓存",
    "熔断降级": "数据库压力过大时,暂时返回默认值",
}

2.3 多级缓存架构

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

Caffeine/本地Dict
L2: Redis

分布式缓存
L3: 数据库

python 复制代码
"""
多级缓存实现
"""
from cachetools import TTLCache

# L1: 本地缓存
local_cache = TTLCache(maxsize=1000, ttl=60)

class MultiLevelCache:
    """多级缓存"""
    
    def __init__(self, redis_client):
        self.redis = redis_client
        self.local = local_cache
    
    def get(self, key: str) -> Optional[Any]:
        """逐级查询"""
        
        # L1: 本地缓存
        value = self.local.get(key)
        if value is not None:
            return value
        
        # L2: Redis
        value = self.redis.get(key)
        if value is not None:
            try:
                parsed = json.loads(value)
            except:
                parsed = value
            # 回填本地缓存
            self.local[key] = parsed
            return parsed
        
        return None
    
    def set(self, key: str, value: Any, redis_ttl: int = 3600):
        """写入多级缓存"""
        self.local[key] = value  # 本地缓存
        serialized = json.dumps(value, ensure_ascii=False) if not isinstance(value, str) else value
        self.redis.setex(key, redis_ttl, serialized)  # Redis
    
    def invalidate(self, key: str):
        """失效多级缓存"""
        self.local.pop(key, None)
        self.redis.delete(key)

# 使用
ml_cache = MultiLevelCache(r)
ml_cache.set("product:1001", {"name": "iPhone", "price": 7999})
product = ml_cache.get("product:1001")

三、消息队列实战

3.1 三种方案对比

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

实时广播
List

简单队列
Stream

生产级队列
✅ 实时

❌ 不持久化

❌ 不可靠
✅ 简单

⚠️ 功能有限

❌ 无消费者组
✅ 持久化

✅ 消费者组

✅ 消息确认

✅ 阻塞读取

特性 Pub/Sub List Stream
持久化
消费者组
消息确认
阻塞读取
消息回溯
适用场景 实时通知 简单队列 生产级 MQ

3.2 Stream 详解

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

基础操作
python 复制代码
"""
Redis Stream 基础操作
"""

# ===== 生产者 =====
def produce_message(stream_name: str, data: dict):
    """发送消息到 Stream"""
    message_id = r.xadd(
        stream_name,
        data,
        maxlen=100000,  # 最大消息数(裁剪)
        approximate=True  # 近似裁剪(性能更好)
    )
    return message_id

# 发送消息
msg_id = produce_message("orders", {
    "order_id": "10086",
    "user_id": "1001",
    "amount": "299.00",
    "status": "created"
})
print(f"消息 ID: {msg_id}")

# ===== 消费者组 =====
def create_consumer_group(stream_name: str, group_name: str):
    """创建消费者组"""
    try:
        r.xgroup_create(stream_name, group_name, id="0", mkstream=True)
    except redis.ResponseError as e:
        if "BUSYGROUP" in str(e):
            pass  # 组已存在
        else:
            raise

def consume_messages(
    stream_name: str,
    group_name: str,
    consumer_name: str,
    count: int = 10,
    block_ms: int = 5000
):
    """消费消息(阻塞读取)"""
    
    while True:
        messages = r.xreadgroup(
            groupname=group_name,
            consumername=consumer_name,
            streams={stream_name: ">"},  # 未读消息
            count=count,
            block=block_ms
        )
        
        if messages:
            for stream, stream_messages in messages:
                for msg_id, data in stream_messages:
                    # 处理消息
                    try:
                        process_message(data)
                        # 确认消息
                        r.xack(stream_name, group_name, msg_id)
                    except Exception as e:
                        print(f"处理消息失败: {e}")
                        # 消息未确认,会被重新投递
        else:
            print("等待消息...")

def process_message(data: dict):
    """处理消息(业务逻辑)"""
    print(f"处理订单: {data}")
    # 模拟业务处理
    order_id = data.get("order_id")
    amount = data.get("amount")
    print(f"  订单 {order_id} 金额 {amount} 处理完成")

# 使用
create_consumer_group("orders", "order_processor")

import threading
threading.Thread(
    target=consume_messages,
    args=("orders", "order_processor", "worker-1"),
    daemon=True
).start()

3.3 延迟队列

python 复制代码
"""
Redis 实现延迟队列(基于 ZSet)
"""
import time
import threading

class RedisDelayQueue:
    """延迟队列(基于 ZSet)"""
    
    def __init__(self, redis_client, queue_name: str = "delay_queue"):
        self.redis = redis_client
        self.queue_name = queue_name
        self.handlers = {}
    
    def publish(self, task_data: str, delay_seconds: int, task_id: str = None):
        """发布延迟任务"""
        if task_id is None:
            task_id = f"{int(time.time()*1000)}-{id(task_data)}"
        
        # 计算执行时间戳
        execute_at = time.time() + delay_seconds
        
        self.redis.zadd(self.queue_name, {task_id: execute_at})
        self.redis.hset(f"task:{task_id}", mapping={
            "data": task_data,
            "execute_at": str(execute_at),
            "created_at": str(time.time())
        })
        
        return task_id
    
    def consume(self):
        """消费延迟任务(轮询)"""
        while True:
            now = time.time()
            
            # 查询到期的任务
            tasks = self.redis.zrangebyscore(
                self.queue_name, 0, now
            )
            
            for task_id in tasks:
                # 获取任务数据
                task_data = self.redis.hget(f"task:{task_id}", "data")
                
                if task_data:
                    # 从队列移除
                    self.redis.zrem(self.queue_name, task_id)
                    
                    # 调用处理函数
                    handler = self.handlers.get("default")
                    if handler:
                        handler(task_data)
                
                # 清理任务数据
                self.redis.delete(f"task:{task_id}")
            
            time.sleep(0.5)  # 500ms 轮询
    
    def register_handler(self, name: str = "default", handler: callable = None):
        """注册处理函数"""
        self.handlers[name] = handler
    
    def start(self):
        """启动消费者"""
        thread = threading.Thread(target=self.consume, daemon=True)
        thread.start()
        return thread

# 使用示例
delay_queue = RedisDelayQueue(r)

# 注册处理函数
delay_queue.register_handler(
    handler=lambda data: print(f"执行延迟任务: {data}")
)

# 启动消费者
delay_queue.start()

# 发布延迟任务
delay_queue.publish("30分钟后发送提醒邮件", delay_seconds=1800)
delay_queue.publish("1小时后检查订单状态", delay_seconds=3600)
delay_queue.publish("明天凌晨生成报表", delay_seconds=86400)

print("延迟队列已启动")

四、分布式锁实战

4.1 基础实现

python 复制代码
"""
Redis 分布式锁基础实现
"""
import uuid
import time

class RedisLock:
    """简单分布式锁(基础版)"""
    
    def __init__(self, redis_client, lock_name: str, ttl: int = 10):
        self.redis = redis_client
        self.lock_name = f"lock:{lock_name}"
        self.ttl = ttl
        self.identifier = str(uuid.uuid4())
    
    def acquire(self, timeout: int = 10) -> bool:
        """获取锁"""
        end_time = time.time() + timeout
        
        while time.time() < end_time:
            # SET key value NX EX
            if self.redis.set(self.lock_name, self.identifier, nx=True, ex=self.ttl):
                return True
            time.sleep(0.1)
        
        return False
    
    def release(self):
        """释放锁(使用 Lua 脚本保证原子性)"""
        lua_script = """
        if redis.call("get", KEYS[1]) == ARGV[1] then
            return redis.call("del", KEYS[1])
        else
            return 0
        end
        """
        result = self.redis.eval(lua_script, 1, self.lock_name, self.identifier)
        return result == 1

# 使用示例(上下文管理器)
class RedisLockContext:
    """锁上下文管理器"""
    
    def __init__(self, redis_client, lock_name: str, ttl: int = 10, timeout: int = 10):
        self.lock = RedisLock(redis_client, lock_name, ttl)
        self.timeout = timeout
        self.acquired = False
    
    def __enter__(self):
        self.acquired = self.lock.acquire(timeout=self.timeout)
        if not self.acquired:
            raise TimeoutError(f"获取锁超时: {self.lock.lock_name}")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.acquired:
            self.lock.release()

# 使用
with RedisLockContext(r, "order:10086", ttl=30):
    # 安全地处理订单
    process_order(10086)
    print("订单处理完成,锁已释放")

4.2 可重入锁

python 复制代码
"""
可重入分布式锁
"""
import threading

class ReentrantRedisLock:
    """可重入分布式锁"""
    
    def __init__(self, redis_client, lock_name: str, ttl: int = 30):
        self.redis = redis_client
        self.lock_name = f"rlock:{lock_name}"
        self.ttl = ttl
        self.identifier = str(uuid.uuid4())
        self._local_lock = threading.Lock()
        self._lock_count = 0
    
    def acquire(self, timeout: int = 10) -> bool:
        """获取锁(可重入)"""
        with self._local_lock:
            if self._lock_count > 0:
                self._lock_count += 1
                return True  # 同一线程可重入
        
        end_time = time.time() + timeout
        
        while time.time() < end_time:
            # 使用 Hash 存储锁信息(支持重入计数)
            lua_script = """
            if redis.call("exists", KEYS[1]) == 0 then
                redis.call("hset", KEYS[1], "owner", ARGV[1])
                redis.call("hset", KEYS[1], "count", 1)
                redis.call("pexpire", KEYS[1], ARGV[2])
                return 1
            elseif redis.call("hget", KEYS[1], "owner") == ARGV[1] then
                redis.call("hincrby", KEYS[1], "count", 1)
                redis.call("pexpire", KEYS[1], ARGV[2])
                return 1
            else
                return 0
            end
            """
            
            result = self.redis.eval(
                lua_script, 1,
                self.lock_name, self.identifier, self.ttl * 1000
            )
            
            if result == 1:
                with self._local_lock:
                    self._lock_count = 1
                return True
            
            time.sleep(0.1)
        
        return False
    
    def release(self):
        """释放锁"""
        with self._local_lock:
            if self._lock_count > 1:
                self._lock_count -= 1
                return True
        
        lua_script = """
        if redis.call("hget", KEYS[1], "owner") == ARGV[1] then
            local count = redis.call("hincrby", KEYS[1], "count", -1)
            if count == 0 then
                return redis.call("del", KEYS[1])
            else
                return count
            end
        else
            return 0
        end
        """
        
        result = self.redis.eval(lua_script, 1, self.lock_name, self.identifier)
        return result > 0

4.3 Redisson(推荐生产使用)

python 复制代码
"""
使用 Redisson 实现分布式锁
(Python 对应库:redis-py + 自行实现,或 redlock-py)
"""
from redlock import RedLock

# 使用 Redlock(红锁算法)
lock = RedLock(
    "order:10086",
    connection_details=[
        {"host": "redis1", "port": 6379},
        {"host": "redis2", "port": 6379},
        {"host": "redis3", "port": 6379},
    ],
    ttl=10000,  # 锁 TTL(毫秒)
    retry_delay=200,  # 重试间隔(毫秒)
    retry_count=3
)

if lock.acquire():
    try:
        process_order(10086)
    finally:
        lock.release()

4.4 锁方案对比

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

SET NX EX
可重入锁

Lua + Hash
红锁

Redlock
✅ 简单

⚠️ 不可重入
✅ 可重入

✅ 原子性
✅ 高可用

⚠️ 复杂度高

方案 可重入 高可用 复杂度 适用场景
SET NX EX 简单场景
Lua + Hash 需要重入
Redlock ⚠️ 生产环境

五、生产级配置

5.1 内存优化

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

ZSet 代替 List+Score
合理设置 TTL

TTL 抖动防雪崩
Hash field 压缩

紧凑编码

redis.conf 关键配置:

conf 复制代码
# 内存限制
maxmemory 4gb

# 淘汰策略
# allkeys-lru: 所有 key,最近最少使用
# volatile-lru: 有过期的 key,最近最少使用
# allkeys-random: 所有 key,随机淘汰
# volatile-ttl: 有过期的 key,即将过期的优先淘汰
maxmemory-policy allkeys-lru

# 内存淘汰采样数(越大越精确,但越慢)
maxmemory-samples 10

# 是否开启 lazyfree
lazyfree-lazy-eviction yes
lazyfree-lazy-expire yes

淘汰策略选择:

策略 适用场景 说明
allkeys-lru 通用推荐 淘汰最久未使用的
volatile-lru 需要永久 key 的场景 只淘汰有 TTL 的
volatile-ttl 优先淘汰快过期的 TTL 短的先淘汰
allkeys-lfu Redis 4.0+ 淘汰使用频率最低的

5.2 持久化方案

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

快照
AOF

日志
✅ 文件紧凑

✅ 恢复快

⚠️ 可能丢失数据
✅ 数据安全

⚠️ 文件大

⚠️ 恢复慢

推荐配置(Redis 7):

conf 复制代码
# RDB 配置(默认开启)
save 900 1        # 15 分钟内至少 1 次变更
save 300 10       # 5 分钟内至少 10 次变更
save 60 10000     # 1 分钟内至少 10000 次变更

# AOF 配置
appendonly yes
appendfilename "appendonly.aof"

# Redis 7 多部分 AOF
aof-use-rdb-preamble yes  # AOF 文件开头用 RDB 格式(加载更快)

# AOF 重写触发条件
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# AOF 刷盘策略
# always: 每次写入都刷盘(最安全,最慢)
# everysec: 每秒刷盘(推荐)
# no: 由 OS 决定
appendfsync everysec
方案 数据安全 性能 恢复速度 适用
RDB ⚠️ 可能丢数据 ✅ 高 ✅ 快 备份、容忍少量丢失
AOF ✅ 最多丢 1 秒 ⚠️ 中等 ⚠️ 较慢 数据安全要求高
RDB + AOF ✅ 最佳 ⚠️ 中等 ✅ 快 生产环境推荐

5.3 集群方案

#mermaid-svg-npw75yYwOW6amcxX{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-npw75yYwOW6amcxX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-npw75yYwOW6amcxX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-npw75yYwOW6amcxX .error-icon{fill:#552222;}#mermaid-svg-npw75yYwOW6amcxX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-npw75yYwOW6amcxX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-npw75yYwOW6amcxX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-npw75yYwOW6amcxX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-npw75yYwOW6amcxX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-npw75yYwOW6amcxX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-npw75yYwOW6amcxX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-npw75yYwOW6amcxX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-npw75yYwOW6amcxX .marker.cross{stroke:#333333;}#mermaid-svg-npw75yYwOW6amcxX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-npw75yYwOW6amcxX p{margin:0;}#mermaid-svg-npw75yYwOW6amcxX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-npw75yYwOW6amcxX .cluster-label text{fill:#333;}#mermaid-svg-npw75yYwOW6amcxX .cluster-label span{color:#333;}#mermaid-svg-npw75yYwOW6amcxX .cluster-label span p{background-color:transparent;}#mermaid-svg-npw75yYwOW6amcxX .label text,#mermaid-svg-npw75yYwOW6amcxX span{fill:#333;color:#333;}#mermaid-svg-npw75yYwOW6amcxX .node rect,#mermaid-svg-npw75yYwOW6amcxX .node circle,#mermaid-svg-npw75yYwOW6amcxX .node ellipse,#mermaid-svg-npw75yYwOW6amcxX .node polygon,#mermaid-svg-npw75yYwOW6amcxX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-npw75yYwOW6amcxX .rough-node .label text,#mermaid-svg-npw75yYwOW6amcxX .node .label text,#mermaid-svg-npw75yYwOW6amcxX .image-shape .label,#mermaid-svg-npw75yYwOW6amcxX .icon-shape .label{text-anchor:middle;}#mermaid-svg-npw75yYwOW6amcxX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-npw75yYwOW6amcxX .rough-node .label,#mermaid-svg-npw75yYwOW6amcxX .node .label,#mermaid-svg-npw75yYwOW6amcxX .image-shape .label,#mermaid-svg-npw75yYwOW6amcxX .icon-shape .label{text-align:center;}#mermaid-svg-npw75yYwOW6amcxX .node.clickable{cursor:pointer;}#mermaid-svg-npw75yYwOW6amcxX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-npw75yYwOW6amcxX .arrowheadPath{fill:#333333;}#mermaid-svg-npw75yYwOW6amcxX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-npw75yYwOW6amcxX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-npw75yYwOW6amcxX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-npw75yYwOW6amcxX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-npw75yYwOW6amcxX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-npw75yYwOW6amcxX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-npw75yYwOW6amcxX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-npw75yYwOW6amcxX .cluster text{fill:#333;}#mermaid-svg-npw75yYwOW6amcxX .cluster span{color:#333;}#mermaid-svg-npw75yYwOW6amcxX 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-npw75yYwOW6amcxX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-npw75yYwOW6amcxX rect.text{fill:none;stroke-width:0;}#mermaid-svg-npw75yYwOW6amcxX .icon-shape,#mermaid-svg-npw75yYwOW6amcxX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-npw75yYwOW6amcxX .icon-shape p,#mermaid-svg-npw75yYwOW6amcxX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-npw75yYwOW6amcxX .icon-shape .label rect,#mermaid-svg-npw75yYwOW6amcxX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-npw75yYwOW6amcxX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-npw75yYwOW6amcxX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-npw75yYwOW6amcxX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 部署方案
单机
主从复制
哨兵
Cluster
开发/测试
读扩展
自动故障转移
数据分片

高可用

大规模

方案 可用性 扩展性 复杂度 适用场景
单机 ❌ 低 开发测试
主从 ⚠️ 中 ⚠️ 读扩展 读多写少
Sentinel ✅ 高 ⚠️ 读扩展 中小规模
Cluster ✅ 高 ✅ 读写扩展 大规模生产

六、性能优化

6.1 Pipeline 批量操作

python 复制代码
"""
Pipeline 批量操作
"""
def batch_get(keys: list) -> list:
    """批量 GET"""
    pipe = r.pipeline(transaction=False)  # 非事务 Pipeline
    for key in keys:
        pipe.get(key)
    return pipe.execute()

def batch_set(items: dict, ttl: int = 3600):
    """批量 SET"""
    pipe = r.pipeline(transaction=False)
    for key, value in items.items():
        serialized = json.dumps(value, ensure_ascii=False) if not isinstance(value, str) else value
        pipe.setex(key, ttl, serialized)
    pipe.execute()

# 性能对比
import time

keys = [f"key:{i}" for i in range(10000)]

# 逐个 GET
start = time.time()
for key in keys:
    r.get(key)
print(f"逐个 GET: {time.time() - start:.3f}s")

# Pipeline GET
start = time.time()
batch_get(keys)
print(f"Pipeline GET: {time.time() - start:.3f}s")

# Pipeline 通常快 10-50 倍

6.2 BigKey 处理

python 复制代码
"""
BigKey 检测与处理
"""
def scan_big_keys(redis_client, threshold_bytes=1024*1024):
    """扫描 BigKey(> 1MB)"""
    
    cursor = 0
    big_keys = []
    
    while True:
        cursor, keys = redis_client.scan(cursor=cursor, count=100)
        
        for key in keys:
            key_type = redis_client.type(key)
            key_size = redis_client.strlen(key) if key_type == "string" \
                else redis_client.hlen(key) if key_type == "hash" \
                else redis_client.llen(key) if key_type == "list" \
                else redis_client.scard(key) if key_type == "set" \
                else redis_client.zcard(key) if key_type == "zset" else 0
            
            if key_size > threshold_bytes:
                big_keys.append({
                    "key": key,
                    "type": key_type,
                    "size": key_size
                })
        
        if cursor == 0:
            break
    
    return big_keys

BigKey 解决方案:

场景 方案
大 String 拆分为多个小 key(Hash)
大 Hash 使用 HSCAN 分批获取
大 List 使用 LRANGE 分页获取
大 Set 使用 SSCAN 分批获取

七、监控与运维

7.1 关键指标监控

python 复制代码
"""
Redis 监控指标采集
"""
def get_redis_info(redis_client) -> dict:
    """获取关键监控指标"""
    
    info = redis_client.info()
    
    return {
        # 内存
        "used_memory_mb": info["used_memory"] / 1024 / 1024,
        "used_memory_peak_mb": info["used_memory_peak"] / 1024 / 1024,
        "used_memory_rss_mb": info["used_memory_rss"] / 1024 / 1024,
        
        # 连接
        "connected_clients": info["connected_clients"],
        "blocked_clients": info["blocked_clients"],
        
        # 性能
        "ops_per_sec": info.get("instantaneous_ops_per_sec", 0),
        "hit_rate": info["keyspace_hits"] / max(info["keyspace_hits"] + info["keyspace_misses"], 1),
        
        # 持久化
        "rdb_last_bgsave": info.get("rdb_last_bgsave_status", "ok"),
        "aof_enabled": info.get("aof_enabled", 0) == 1,
        
        # 集群
        "cluster_enabled": info.get("cluster_enabled", 0) == 1,
    }

# 监控告警
def check_redis_health(redis_client):
    """健康检查"""
    
    info = get_redis_info(redis_client)
    alerts = []
    
    if info["used_memory_mb"] > info["used_memory_peak_mb"] * 0.8:
        alerts.append("⚠️ 内存使用接近峰值")
    
    if info["hit_rate"] < 0.9:
        alerts.append(f"⚠️ 缓存命中率过低: {info['hit_rate']:.2%}")
    
    if info["blocked_clients"] > 10:
        alerts.append(f"⚠️ 阻塞客户端数: {info['blocked_clients']}")
    
    return alerts

7.2 常用运维命令

命令 说明 使用场景
INFO memory 内存信息 内存排查
INFO stats 统计信息 性能分析
INFO replication 主从信息 主从状态
SLOWLOG GET 10 慢查询日志 性能优化
CLIENT LIST 客户端连接 连接管理
DBSIZE key 总数 容量监控
SCAN 安全遍历 大数据量操作
OBJECT ENCODING key 编码方式 内存优化

八、最佳实践总结

8.1 开发规范

markdown 复制代码
✅ Redis 开发规范

📋 Key 命名
  □ 使用冒号分隔的命名空间:`project:module:entity:id`
  □ 例:`order:detail:10086`、`user:token:1001`
  □ 避免过长(< 100 字节)

⏰ TTL 设置
  □ 所有 key 都应设置 TTL
  □ 热点数据:1-6 小时
  □ 冷数据:1-7 天
  □ 添加随机抖动(±10%)防雪崩

📦 数据大小
  □ 单个 value < 10KB(推荐 < 1KB)
  □ 避免 BigKey(> 1MB 严格禁止)

⚡ 性能
  □ 批量操作使用 Pipeline
  □ 避免使用 KEYS *(用 SCAN)
  □ 使用连接池

🔒 安全
  □ 生产环境必须设置密码
  □ 禁用危险命令(FLUSHALL、CONFIG)
  □ 使用 ACL 限制权限

8.2 常见错误

错误 后果 解决方案
❌ 不设 TTL 内存泄漏 所有 key 都设置 TTL
❌ 用 KEYS * 阻塞 Redis 使用 SCAN
❌ BigKey 延迟飙升 拆分数据
❌ 热点 key 单节点 单点压力 本地缓存 + 分布式
❌ 大量 Pipeline 阻塞网络 控制批次大小

九、总结

#mermaid-svg-uSgsgA0CejxQ1FMH{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-uSgsgA0CejxQ1FMH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uSgsgA0CejxQ1FMH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uSgsgA0CejxQ1FMH .error-icon{fill:#552222;}#mermaid-svg-uSgsgA0CejxQ1FMH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uSgsgA0CejxQ1FMH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uSgsgA0CejxQ1FMH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uSgsgA0CejxQ1FMH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uSgsgA0CejxQ1FMH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uSgsgA0CejxQ1FMH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uSgsgA0CejxQ1FMH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uSgsgA0CejxQ1FMH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uSgsgA0CejxQ1FMH .marker.cross{stroke:#333333;}#mermaid-svg-uSgsgA0CejxQ1FMH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uSgsgA0CejxQ1FMH p{margin:0;}#mermaid-svg-uSgsgA0CejxQ1FMH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-uSgsgA0CejxQ1FMH .cluster-label text{fill:#333;}#mermaid-svg-uSgsgA0CejxQ1FMH .cluster-label span{color:#333;}#mermaid-svg-uSgsgA0CejxQ1FMH .cluster-label span p{background-color:transparent;}#mermaid-svg-uSgsgA0CejxQ1FMH .label text,#mermaid-svg-uSgsgA0CejxQ1FMH span{fill:#333;color:#333;}#mermaid-svg-uSgsgA0CejxQ1FMH .node rect,#mermaid-svg-uSgsgA0CejxQ1FMH .node circle,#mermaid-svg-uSgsgA0CejxQ1FMH .node ellipse,#mermaid-svg-uSgsgA0CejxQ1FMH .node polygon,#mermaid-svg-uSgsgA0CejxQ1FMH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-uSgsgA0CejxQ1FMH .rough-node .label text,#mermaid-svg-uSgsgA0CejxQ1FMH .node .label text,#mermaid-svg-uSgsgA0CejxQ1FMH .image-shape .label,#mermaid-svg-uSgsgA0CejxQ1FMH .icon-shape .label{text-anchor:middle;}#mermaid-svg-uSgsgA0CejxQ1FMH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-uSgsgA0CejxQ1FMH .rough-node .label,#mermaid-svg-uSgsgA0CejxQ1FMH .node .label,#mermaid-svg-uSgsgA0CejxQ1FMH .image-shape .label,#mermaid-svg-uSgsgA0CejxQ1FMH .icon-shape .label{text-align:center;}#mermaid-svg-uSgsgA0CejxQ1FMH .node.clickable{cursor:pointer;}#mermaid-svg-uSgsgA0CejxQ1FMH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-uSgsgA0CejxQ1FMH .arrowheadPath{fill:#333333;}#mermaid-svg-uSgsgA0CejxQ1FMH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-uSgsgA0CejxQ1FMH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-uSgsgA0CejxQ1FMH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uSgsgA0CejxQ1FMH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-uSgsgA0CejxQ1FMH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uSgsgA0CejxQ1FMH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-uSgsgA0CejxQ1FMH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-uSgsgA0CejxQ1FMH .cluster text{fill:#333;}#mermaid-svg-uSgsgA0CejxQ1FMH .cluster span{color:#333;}#mermaid-svg-uSgsgA0CejxQ1FMH 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-uSgsgA0CejxQ1FMH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-uSgsgA0CejxQ1FMH rect.text{fill:none;stroke-width:0;}#mermaid-svg-uSgsgA0CejxQ1FMH .icon-shape,#mermaid-svg-uSgsgA0CejxQ1FMH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uSgsgA0CejxQ1FMH .icon-shape p,#mermaid-svg-uSgsgA0CejxQ1FMH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-uSgsgA0CejxQ1FMH .icon-shape .label rect,#mermaid-svg-uSgsgA0CejxQ1FMH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uSgsgA0CejxQ1FMH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-uSgsgA0CejxQ1FMH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-uSgsgA0CejxQ1FMH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 🎓 Redis 7 实战总结
📦 缓存
📨 消息队列
🔒 分布式锁
穿透:布隆过滤器
击穿:互斥锁
雪崩:随机 TTL
多级缓存
Stream: 生产级
延迟队列: ZSet
基础锁: SET NX
可重入锁: Lua
高可用: Redlock

场景方案选择

场景 推荐方案
简单缓存 String + TTL
对象缓存 Hash
排行榜 ZSet
实时通知 Pub/Sub
可靠消息 Stream + 消费者组
延迟任务 ZSet + 轮询
简单锁 SET NX EX
生产锁 Lua + Hash / Redlock

本文基于 Redis 7.x 编写,代码示例使用 Python (redis-py)。实际生产环境建议结合业务需求调整参数和方案。如有问题欢迎评论区讨论!

相关推荐
小程故事多_801 小时前
从初代架构到大模型时代,英伟达GPU底层架构演进与核心逻辑深度解析
java·人工智能·分布式·架构
海市公约1 小时前
Redis 哨兵模式底层原理与自动故障转移全流程
redis·sentinel·redis哨兵·高可用架构·主观下线·客观下线·leader选举
abigale031 小时前
LangChain 实践4: 7个人AI助手全栈项目:完整拆解+分阶段开发指南
缓存·langchain·prompt·token·rag·lcel
map1e_zjc1 小时前
Redis入门笔记
数据库·redis·缓存
辞忧九千七1 小时前
Redis高可用基石:从发布订阅到主从复制再到哨兵模式
redis
步十人1 小时前
【Redis】高可用集群架构
数据库·redis·架构
霸道流氓气质1 小时前
批量异步处理 + MQ + Redis 进度追踪实战指南
数据库·redis·状态模式
我是一颗柠檬2 小时前
【Java后端技术亮点】Feed流三级缓存设计,从10秒到100毫秒的优化实战
java·开发语言·后端·缓存
Java 码思客2 小时前
【Redis分布式缓存实战】第3章 Redis核心机制深度解析
redis·分布式·缓存