当前位置:首页 > 文章列表 > 数据库 > Redis > Redis 客户端缓存如何用广播模式减少失效消息

Redis 客户端缓存如何用广播模式减少失效消息

来源:17golang原创 2026-10-08 22:51:53 0浏览 收藏

Redis 的 BCAST 广播模式不会天然减少失效消息:它用“按前缀广播”替代服务端逐键记录,通常会让客户端收到更多通知。真正能减少无关消息的是把键空间设计成稳定、互不重叠的业务前缀,并让每类客户端只订阅自己确实缓存的前缀,绝不能省略 PREFIX 或使用过宽的公共前缀。

如果一个商品服务只缓存 product:,就不要让它同时接收 user:、order: 的失效通知。这个迁移的目标不是追求“零消息”,而是让收到的每条失效通知都尽量与本地缓存有关,同时把 Redis 服务端的逐键跟踪内存换成一个更小、更稳定的前缀表。

Redis 官方参考:https://redis.io/docs/latest/develop/reference/client-side-caching/

先确认这次迁移解决什么问题

Redis 客户端缓存有两种跟踪方式。普通模式会记住某个客户端读过哪些键,键被修改、过期或因内存策略被淘汰时,只通知可能缓存了该键的客户端。它的消息比较精准,但服务端要维护失效表,内存开销与被跟踪的键和客户端有关。

BCAST 模式不保存逐键访问记录,而是保存“前缀对应哪些客户端”。只要某个键匹配已注册前缀,订阅该前缀的所有客户端都会收到失效消息。它降低了服务端跟踪内存,却把筛选责任交给前缀设计和客户端。

Redis 普通客户端跟踪与 BCAST 广播模式的静态结构对照图
图1:普通跟踪与 BCAST 的静态结构对照。广播模式减少的是服务端逐键记录,不是天然减少客户端通知。
对比项普通跟踪模式BCAST 广播模式
服务端记录键与可能缓存它的客户端前缀与订阅它的客户端
失效消息更接近实际读取过的键前缀内所有被修改的键
主要成本失效表内存与维护成本客户端消息量和前缀匹配 CPU
适合场景键分散、客户端读取集合差异大键空间可按少量稳定业务域划分

旧配置为什么会制造大量无关通知

最危险的旧写法是只启用 BCAST,却没有配置任何 PREFIX。Redis 会把前缀视为空字符串,也就是所有被修改的键都匹配。另一个常见问题是使用 app: 这类覆盖整个系统的前缀,导致只缓存商品的进程也接收用户、订单和库存的失效消息。

# 不推荐:没有 PREFIX 时等价于订阅整个键空间
redis-cli CLIENT TRACKING ON BCAST

# 不推荐:app: 覆盖范围过大,业务客户端会收到大量无关失效
redis-cli CLIENT TRACKING ON BCAST PREFIX app:

这类配置在功能上可能没有报错,但会增加网络流量、失效回调次数和本地缓存锁竞争。迁移前应先统计客户端真正缓存的键族,而不是从现有键名里随便截取一个共同前缀。

用不重叠的业务前缀收窄广播范围

把键设计为 user:42、product:9、order:20261008:1001 这类稳定业务域,随后按进程职责注册前缀。Redis 官方文档要求同一跟踪配置中的前缀不能覆盖重叠键空间,例如 foo 与 foob 不能同时使用,因为键 foobar 会同时匹配两者。

# 用户服务只接收 user: 键的失效消息
redis-cli CLIENT TRACKING ON BCAST PREFIX user:

# 商品服务只接收 product: 键的失效消息
redis-cli CLIENT TRACKING ON BCAST PREFIX product:

# 同一客户端确实缓存两个业务域时,可以注册多个不重叠前缀
redis-cli CLIENT TRACKING ON BCAST PREFIX user: PREFIX product:

配置后可用 CLIENT TRACKINGINFO 查看当前连接的跟踪状态和前缀集合。核对重点不是命令是否返回 OK,而是前缀是否只覆盖这个客户端的本地缓存域。

# 在启用跟踪的同一连接上检查 flags 与 prefixes
redis-cli CLIENT TRACKINGINFO
Redis 键前缀、失效连接、数据连接与本地缓存的静态关系图
图2:按业务域拆分 PREFIX 后的失效消息结构图。客户端只订阅自己缓存的键空间,并在失效连接丢失时清空本地缓存。

失效连接要和数据连接一起设计

RESP3 可以在同一连接上接收普通回复和 push 类型的失效消息。如果客户端库使用两条连接,数据连接可通过 REDIRECT 把消息送到专用失效连接;RESP2 也依赖这种模式,并通过特殊的 __redis__:invalidate 通道承载定向消息。这里不是普通意义上的全体 Pub/Sub 广播,只有指定的重定向连接会收到消息。

# 第一步:在专用失效连接上获取连接 ID,例如返回 42
redis-cli CLIENT ID

# RESP2 失效连接订阅 Redis 专用失效通道
redis-cli SUBSCRIBE __redis__:invalidate

# 第二步:数据连接把 BCAST 失效消息定向到连接 42
redis-cli CLIENT TRACKING ON REDIRECT 42 BCAST PREFIX product:

连接池场景可以让多条数据连接重定向到同一条失效连接,但应用必须把“失效连接是否健康”纳入缓存有效性。如果失效连接断开,继续读取本地缓存可能产生陈旧数据。官方建议在连接丢失或心跳无响应时清空本地缓存,再重建连接和跟踪配置。

旧实现迁移时要补上的三个边界

写后立刻收到自己的失效消息

默认情况下,修改键的客户端也会收到失效通知。如果应用在写入成功后已经把新值放进本地缓存,可以使用 NOLOOP 避免马上清掉自己刚写入的值。只有明确实现了写后更新缓存,才应开启这个选项。

# 写路径会同步更新本地缓存时,用 NOLOOP 抑制自身写入的失效回环
redis-cli CLIENT TRACKING ON BCAST NOLOOP PREFIX product:

双连接的读写竞态

数据回复和失效消息走不同连接时,失效消息可能先到,而较旧的数据回复后到。如果客户端直接把后到的回复写入缓存,就会重新放入陈旧值。更稳妥的做法是在发起读取时放一个“缓存中”占位;若期间收到失效消息就删除占位,数据回复回来时发现占位已不存在,便不再写入本地缓存。

// 发出 GET 前先占位,用于识别读取期间到达的失效消息
localCache.set(key, { state: "loading" });

const value = await redis.get(key);

// 只有占位仍存在才写入;失效回调删除占位后,这里会跳过旧值
if (localCache.get(key)?.state === "loading") {
  localCache.set(key, { state: "ready", value });
}

TTL 和客户端内存没有上限

广播只解决失效通知,不替代本地淘汰策略。客户端仍应限制内存,并为缓存项设置最大 TTL;即使 Redis 键没有 TTL,本地最大存活时间也能降低连接故障或实现缺陷导致长期陈旧数据的风险。频繁变化或很少访问的键通常不值得进入客户端缓存。

回归检查不要只看 Redis 内存

迁移完成后,至少比较三个指标:Redis 跟踪相关内存是否下降、客户端收到的失效消息中有多少真正命中本地缓存、业务请求的本地缓存命中率是否保持稳定。BCAST 前缀数量过多时,Redis 的 CPU 成本会随注册前缀数量增长,因此前缀不是越细越好。

检查项理想变化异常时怎么处理
服务端逐键跟踪内存BCAST 后不再维护普通失效表中的逐键记录确认连接确实启用了 BCAST
无关失效消息比例细分 PREFIX 后明显下降继续拆分过宽前缀或调整服务职责
本地缓存命中率不因过度失效而明显下跌检查高频写键是否不适合缓存
Redis CPU保持在容量阈值内减少前缀数量,避免过细划分
失效连接健康断线时清空缓存并成功重连优先停用本地缓存,不能继续读旧值

可执行的迁移清单

  1. 列出每类应用实际缓存的 Redis 键族,剔除高频变化和低频读取的键。
  2. 把键名整理为少量稳定、不重叠的业务前缀,不使用空前缀和全局公共前缀。
  3. 先在单个实例启用 CLIENT TRACKING ON BCAST PREFIX ...,核对 TRACKINGINFO。
  4. 确认失效回调只删除本地对应键,并实现连接断开后清空本地缓存。
  5. 双连接实现加入读取占位,避免失效消息与数据回复乱序造成陈旧值回填。
  6. 只有写后会更新本地缓存的连接才开启 NOLOOP。
  7. 灰度比较消息命中率、缓存命中率、Redis CPU 与网络流量,再逐步扩大范围。
  8. 若无关通知仍然过多,回退到普通跟踪模式,或重新划分键前缀,而不是无限增加前缀。

相关问题

BCAST 一定比普通跟踪模式省资源吗?

不一定。它节省逐键跟踪内存,却可能增加客户端消息、网络流量和前缀匹配 CPU。是否合适取决于键空间能否被少量稳定前缀划分。

为什么不能同时使用 user: 和 user:profile:?

两者覆盖重叠键空间,某些键会同时匹配。应保留能覆盖需求的一个前缀,或改成互不重叠的命名。

失效连接断开后可以继续使用本地缓存吗?

不建议。客户端可能已经漏掉修改通知,应先清空本地缓存并恢复失效连接,再重新积累缓存。

什么时候应该放弃 BCAST?

当客户端读取集合高度离散、键前缀无法稳定划分,或无关失效消息与 CPU 成本高于普通跟踪模式时,普通逐键跟踪通常更合适。

广播模式的核心取舍很清楚:Redis 不再记住每个客户端读过哪些键,客户端则要接受前缀内的广播。把前缀设计成业务边界,并补齐断线清理、竞态保护和容量指标,才能真正减少无关失效消息,而不是把服务端内存压力转化成客户端消息风暴。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
MySQL 不可见索引适合怎样做上线前回归验证MySQL 不可见索引适合怎样做上线前回归验证
上一篇
MySQL 不可见索引适合怎样做上线前回归验证
用泛型方法封装类型安全的分页结果映射
下一篇
用泛型方法封装类型安全的分页结果映射
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    382次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    453次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    466次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    405次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    235次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码