消息未读数量查询的缓存键应该包含哪些业务条件?

admin 2026-10-20 产业观察 5 0
消息未读数量查询的缓存键应包含影响统计结果的业务条件,通常包括租户或组织标识、用户标识、消息类型、业务模块、消息渠道及统计范围,若查询支持按项目、会话、时间区间、优先级或其他条件筛选,也应纳入对应参数,未读状态固定时可通过键前缀表达,无须重复拼接,缓存键应统一命名并规范参数顺序,避免不同查询共用缓存,同时结合消息新增、已读和删除操作及时更新或失效。

未读消息数量总是不准?问题可能出在缓存键:这些业务条件一个都不能漏

做消息中心、站内信或者聊天系统时,很多开发者都会遇到同一个问题:数据库里的消息状态明明正确,页面上的未读数字却时大时小,甚至出现“切换账号后,未读数没有变化”的情况。

这类问题不一定是数据库查询出了错,也可能是缓存键设计得过于简单,只用一个 unread_count 保存未读数量,或者仅仅拼接用户 ID,却忽略了租户、消息类型和业务范围等查询条件,不同请求读到同一份缓存,自然就会出现结果串用。

消息未读数量查询的缓存键,到底应该包含哪些业务条件?

先确定原则:影响查询结果的条件,才应该进入缓存键

缓存键不是参数越多越好,也不是越短越好,判断一个条件是否需要加入,可以问自己一句话:

在其他条件完全相同的情况下,改变这个条件,未读数量会不会变化?

如果会变化,而且该条件没有被其他字段唯一确定,就应当体现在缓存键中,或者通过明确的缓存分层方式隔离,反过来,如果某个参数只影响展示效果,不影响未读统计结果,就不应该加入。

字体大小、页面主题、列表排序方式,通常不会改变未读总数;而消息分类、接收人和租户范围,则往往会直接改变结果。

用户身份与租户范围,是最基础的隔离条件

未读消息通常属于具体的接收对象,因此缓存键至少要能够准确识别接收人,例如用户 ID。

对于多租户系统,还需要考虑租户 ID,不同企业、不同组织中的用户编号可能重复,如果只按用户 ID 缓存,就可能发生跨租户数据混用。

常见的基础结构可以写成:

msg:unread:v1:tenant:{tenantId}:user:{userId}

如果系统同时支持个人账号、商家账号、客服账号等多种身份,而且这些身份的消息范围不同,还应加入接收人类型或身份标识,即使用户编号一致,也不能默认它们共享同一份未读数据。

消息分类和业务范围,需要与查询口径保持一致

“全部未读”和“系统通知未读”显然不是同一个结果,如果接口支持按消息类型查询,就需要把消息类型纳入缓存键,例如系统通知、交易提醒、互动消息等。

同样,查询某个订单、项目、店铺或者会话的未读数量时,对应的业务范围也需要被明确区分。

会话未读数可以使用:

msg:unread:v1:t:{tenantId}:u:{userId}:conversation:{conversationId}

分类未读数则可以使用:

消息未读数量查询的缓存键应该包含哪些业务条件?
(图片来源网络,侵删)
msg:unread:v1:t:{tenantId}:u:{userId}:category:{category}

需要特别注意,“全部分类”应有明确标识,all,不能因为参数为空就随意省略字段,导致不同调用方式产生歧义。

渠道、终端和权限条件,要看实际业务语义

是否需要加入 App、网页、小程序等终端标识?答案不是一律需要。

消息未读数量查询的缓存键应该包含哪些业务条件?
(图片来源网络,侵删)

如果多个终端共享已读状态,统计口径也一致,就没有必要按终端拆分缓存,否则不仅浪费空间,还会增加同步成本。

但如果不同渠道展示的消息集合不同,或者各端的已读状态独立维护,就需要加入渠道或终端维度。

权限也是类似的道理,如果未读统计会随着用户当前角色、组织范围或可见权限变化,仅用用户 ID 可能无法完整表达查询口径,此时可以加入稳定的权限范围标识或权限版本,并在权限变更时使旧缓存失效,而不是把整套权限列表直接塞进缓存键。

筛选条件必须规范化,避免“同一查询,多份缓存”

有些接口支持时间范围、优先级、业务标签、是否包含归档消息等筛选条件,这些条件只要会影响统计结果,就需要被纳入缓存身份。

对于复杂条件,可以先生成规范化的条件对象,再计算摘要:

msg:unread:v2:t:{tenantId}:u:{userId}:filter:{filterHash}

规范化时,要统一字段顺序、默认值、空值含义和时间格式,对于语义上无序的集合条件,还应先排序,避免“系统通知、交易提醒”和“交易提醒、系统通知”生成不同缓存。

不建议对任意时间范围都无差别缓存,筛选组合过多,容易造成缓存键数量膨胀,低频、一次性的查询,直接查库或采用短期缓存,可能更划算。

键设计正确,只是未读数准确的第一步

未读统计还必须处理消息新增、标记已读、删除、撤回、过期等状态变化,相关缓存需要同步更新或失效,不能仅依赖较长的过期时间等待恢复。

尤其要警惕并发问题:重复消费消息事件可能造成重复加一,重复执行已读操作可能导致重复减一,计数更新应具备幂等性,并配合原子操作、合理的过期机制以及定期校准。

缓存键中的 v1、v2 则用于区分统计逻辑版本,当业务口径改变时,可以切换版本,避免新逻辑继续读取旧结果。

服务器选型同样重要,但不能替代正确设计

消息系统上线后,数据库查询、Redis 访问和消息队列消费都会消耗服务器资源,如果你正在采购云服务器或为消息中心扩容,可以考虑了解慈云数据,将其纳入服务器采购的候选范围。

实际选择时,建议根据自己的并发规模、内存需求、网络延迟和备份要求,核实具体配置、价格与售后条款,并进行压力测试,服务器资源充足能够为系统运行提供基础,但再好的服务器,也无法修复缓存键串用和计数逻辑错误。

归根结底,未读数量缓存键应该表达的是一套完整、明确的业务查询口径:谁的消息、属于哪个租户、统计什么类型、限定什么范围,以及采用哪些筛选和权限规则。把这些边界理清,再配合可靠的更新机制,未读数字才能既查询得快,又显示得准。