这份清单用于方案评审、上线前自查和事故复盘。它不是「最佳实践大全」,而是卷二各章判断的压缩版:每一项都对应一个具体的失败场景。
怎么用这份清单
先看三个使用原则:
- 按场景选段,不要从头勾到尾。 发布功能查第一、二、三段;IM 功能查第六段;推送改动查第七段。全勾一遍通常需要两小时,没人会认真做。
- 每项都要能指出代码位置。 勾选「已检查」但没有对应函数或测试,等于没检查。
- 不通过项要写清影响。 「未做」和「做了但有风险」是两回事,后者需要记录触发条件。
清单分三档优先级:
- P0:不做会直接导致数据错误或用户可见的越权。
- P1:不做会在流量上涨或依赖故障时暴露。
- P2:不做会影响体验或运维效率,但不会立刻出事。
上线前 P0 必须全过,P1 允许有明确的豁免记录,P2 可以排期。
一、发布与审核
P0 发布链路有明确的状态机,且状态迁移由单一服务校验。
检查什么:草稿、审核中、已发布、已拒绝、已删除之间的迁移是否集中在一处;接口是否直接改 state 字段。
不通过会怎样:不同接口对同一状态的理解不一致,出现「已拒绝的内容还能被编辑成已发布」。
P0 审核结论与内容状态在同一个事务或同一条消息里落库。
检查什么:审核服务返回结论后,内容状态更新是否可能丢失;消息消费失败是否有重试与告警。
不通过会怎样:审核通过了,但内容一直停在「审核中」,用户以为没发出去。
P1 发布链路的同步步骤有明确预算。
检查什么:用户点发布到接口返回,中间同步执行了哪些步骤;每一步的 p99 是否在预算内。
不通过会怎样:加一个同步步骤就超时,用户重试产生重复内容。
P1 机审超时有人审兜底,不直接拒绝。
检查什么:机审超时、机审服务不可用时的分支;是否返回「审核中」而不是「发布失败」。
不通过会怎样:机审服务抖动时,大量正常内容被判失败,用户投诉。
P1 申诉有时限、有状态、有通知。
检查什么:申诉入口是否对「已拒绝」内容可见;申诉结果是否通知用户;超过时限后入口是否关闭。
不通过会怎样:用户不知道可以申诉,或者申诉后永远等不到结果。
P2 审核记录只追加,不覆盖。
检查什么:修正审核结论时是新增记录还是改旧记录;能否回答「当时为什么这么判」。
不通过会怎样:复核时无法还原历史,责任无法界定。
二、可见性
P0 可见性判定在服务端读路径上,不依赖前端隐藏。
检查什么:详情、列表、搜索、推荐每个入口是否都调用同一个判定函数;是否存在「前端不展示但接口返回」的字段。
不通过会怎样:抓包或改客户端即可看到本不该看的内容。
P0 拉黑优先级高于关注与好友。
检查什么:判定链的顺序;A 拉黑 B 后,B 通过关注关系、共同群、搜索结果是否还能看到 A 的内容。
不通过会怎样:用户拉黑后仍被骚扰,这是最容易被截图传播的事故。
P0 删除是软删除,且所有读路径都过滤。
检查什么:详情、Feed、评论、搜索、推荐是否都检查 deleted_at;缓存是否有失效。
不通过会怎样:删除的内容在某个入口继续存在,用户认为删除无效。
P1 可见性规则有真值表或等价测试。
检查什么:内容状态 × 读者关系 × 入口场景的组合是否有测试覆盖;新增关系类型时是否补测试。
不通过会怎样:规则只存在于开发者脑中,改动时靠记忆,迟早漏一条。
P1 好友关系解除后,依赖它的派生数据会失效。
检查什么:好友动态、共同好友、推荐亲和度是否在关系解除后更新;缓存 TTL 是否合理。
不通过会怎样:解除好友后仍能看到对方的好友可见内容。
P2 可见性判定有审计日志。
检查什么:拒绝访问时是否记录 owner、viewer、关系、场景、结论;能否用于事后排查。
不通过会怎样:用户投诉「为什么看不到」时,无法复现判定过程。
三、Feed
P0 推模式下,收件箱写入有去重键。
检查什么:同一内容写入同一用户收件箱是否可能发生两次;去重键是内容 ID 还是「内容 ID + 用户 ID」。
不通过会怎样:用户首页出现重复内容。
P0 拉模式下,多源合并有稳定的排序与截断。
检查什么:多个来源的时间线如何合并;同分如何排序;截断是否会让某些来源永远不出现。
不通过会怎样:某些作者的内容永远排不进来,或者每次刷新顺序抖动。
P1 推拉选择有明确判据,不是拍脑袋。
检查什么:粉丝数分布、刷新频率、写成本、读成本是否算过;门槛值是否写进配置或文档。
不通过会怎样:头部作者一次发布打满收件箱写入,接口超时。
P1 发布后作者自己的可见性与粉丝一致。
检查什么:作者刷新首页能否立刻看到自己的内容;如果不能,是否有「发布成功」的明确反馈。
不通过会怎样:作者以为发布失败,重复发布。
P1 Feed 读取有超时与降级。
检查什么:合并多个来源时,单个来源超时是否会拖垮整个请求;是否有缓存兜底。
不通过会怎样:一个慢来源导致首页整体超时。
P2 Feed 有已读、去重、折叠的产品规则。
检查什么:已读内容是否重复出现;同一事件的多条内容是否折叠;规则是否对用户可见。
不通过会怎样:用户觉得「首页总是那几条」,或者「同样的事刷了十遍」。
四、互动与计数
P0 点赞、收藏等互动是幂等的。
检查什么:同一用户对同一目标重复操作是否只产生一条关系;重复请求是否返回成功而不是报错。
不通过会怎样:网络抖动导致重复点击,计数翻倍。
P0 计数有真相来源,缓存计数可对账。
检查什么:计数是从关系表聚合,还是只存在于缓存;对账任务是否存在、是否跑过。
不通过会怎样:缓存丢失后计数无法恢复,或者长期漂移无人发现。
P1 计数更新与互动写入的顺序明确。
检查什么:先写关系还是先更计数;失败时哪一步会丢;是否有补偿。
不通过会怎样:关系写成功、计数没更新,用户看到「赞了但数字没变」。
P1 频控覆盖用户、目标、IP、设备维度。
检查什么:只按用户频控是否足够;刷子换账号后是否能绕过;是否误伤正常用户。
不通过会怎样:刷量或恶意互动无法拦截,或者正常用户被误拦。
P1 热点计数有本地聚合或分片。
检查什么:单条内容的计数更新是否打到一个 key;是否有批量合并。
不通过会怎样:爆款内容把单个缓存分片打满,影响其他内容。
P2 计数展示有「约」「万」等口径说明。
检查什么:大数展示是否四舍五入;是否与详情页数字一致。
不通过会怎样:用户发现列表显示 1.2 万、详情显示 11999,质疑数据造假。
五、评论
P0 评论树有深度上限,且不会因深回复导致栈溢出或超时。
检查什么:maxDepth 是否配置;超过上限的回复挂到哪里;构建树是否递归无界。
不通过会怎样:恶意用户回复几千层,拖垮评论接口。
P0 折叠不删除节点,被折叠内容可展开。
检查什么:折叠是标记还是删除;被折叠评论的回复是否还在;作者能否申诉。
不通过会怎样:用户认为评论被无故删除,且无法找回。
P1 评论分页稳定,不因新评论插入而重复或遗漏。
检查什么:分页游标是偏移量还是「时间 + ID」;新评论插入时是否会导致下一页重复。
不通过会怎样:用户翻页时看到重复评论,或者漏掉评论。
P1 评论通知有聚合与自触发过滤。
检查什么:自己评论自己的内容是否通知;短时间内多条评论是否合并;被拉黑用户是否还能触发通知。
不通过会怎样:用户被自己的操作通知刷屏,或者被拉黑者持续骚扰。
P1 评论审核与内容审核共用状态语义。
检查什么:评论的「审核中」「已拒绝」是否与内容一致;已发布内容下的新评论是否也走审核。
不通过会怎样:内容审核严格、评论审核宽松,评论区成为违规内容入口。
P2 评论计数与实际可见评论数口径一致。
检查什么:计数是否包含已折叠、已删除评论;前端展示「XX 条评论」与列表实际条数是否对得上。
不通过会怎样:用户点开发现「100 条评论」只有 20 条可见。
六、IM 与投递
P0 会话内消息序号单调,且由服务端分配。
检查什么:seq 是客户端生成还是服务端生成;并发发送时是否可能重复或跳号。
不通过会怎样:客户端无法判断消息是否连续,离线补偿出错。
P0 消息去重有服务端窗口,不只依赖客户端 ID。
检查什么:客户端重发、网关重试、消费重试是否都会经过同一个去重逻辑;窗口 TTL 是否覆盖最大重试跨度。
不通过会怎样:用户看到重复消息。
P0 多端已读取最大值,不求和不覆盖。
检查什么:手机读了、电脑没读时,未读数是多少;已读上报是否按设备存。
不通过会怎样:未读数出现负数或翻倍。
P1 在线投递是尽力而为,离线补偿是可靠性来源。
检查什么:投递失败时消息是否落库;客户端重连后能否按 seq 拉取缺失消息。
不通过会怎样:连接断开期间的消息永久丢失。
P1 离线判定有心跳 TTL,且 TTL 大于心跳间隔。
检查什么:半开连接是否会被判在线;TTL 与客户端心跳间隔的关系。
不通过会怎样:消息投给已断开的连接,用户收不到也收不到补偿。
P1 群成员变更与消息投递的顺序明确。
检查什么:退群、踢人、拉黑的生效时刻;生效前的消息是否补投;生效后的消息是否拦截。
不通过会怎样:被踢出群的人还能收到后续消息。
P2 消息保留期与漫游分页有上限。
检查什么:历史消息保留多久;单次拉取条数;超过保留期后客户端如何提示。
不通过会怎样:新设备登录拉取全量历史,拖垮服务。
七、推送与通知
P0 推送失败有降级链,不静默丢弃。
检查什么:APNs/FCM 失败后走站内信还是短信;降级是否有优先级;是否有告警。
不通过会怎样:证书过期导致所有 iOS 推送失败,三天后才发现。
P0 模板按渠道裁剪,不超包体上限。
检查什么:同一模板在各渠道渲染后的长度;小程序订阅消息字段是否匹配。
不通过会怎样:推送被渠道拒收,或被截断成半句话。
P1 通知有聚合与频控,区分营销与事务。
检查什么:同一事件的多条通知是否合并;营销推送是否有每日上限;事务通知是否被误限。
不通过会怎样:用户一天收到十几条推送,直接关闭通知权限。
P1 通知有用户可见的开关,且开关生效于发送前。
检查什么:用户关闭某类通知后,是发送前过滤还是发送后丢弃;是否会重复消耗推送配额。
不通过会怎样:用户关了通知仍然收到,认为开关无效。
P1 推送到达率、展示率、点击率分开统计。
检查什么:是否把「发送成功」当成「用户看到」;渠道回执是否接入。
不通过会怎样:指标虚高,实际触达很低。
P2 通知深链有兜底页面。
检查什么:内容删除、用户注销后,点击通知跳到哪;是否有友好的兜底。
不通过会怎样:用户点通知进入 404 或白屏。
八、搜索与推荐
P0 搜索结果的可见性在查询阶段过滤。
检查什么:索引里的可见性快照是否可信;用户关系变化后是否重新过滤;删除是否有墓碑。
不通过会怎样:用户搜到已删除或无权查看的内容,点进去 403。
P0 推荐服务不直接读业务库做过滤。
检查什么:推荐返回的候选是否由业务服务二次过滤;推荐服务是否依赖内容表结构。
不通过会怎样:内容表改字段,推荐服务跟着崩。
P1 索引同步有版本号或幂等键。
检查什么:旧消息晚到是否会覆盖新状态;删除后旧更新是否会把文档复活。
不通过会怎样:删除的内容在索引里反复出现。
P1 搜索/推荐有一致性窗口的产品说明。
检查什么:删除后多久从搜索消失;新内容多久能被搜到;是否写进帮助文档。
不通过会怎样:用户认为「删了还能搜到」是隐私事故。
P1 冷启动有明确兜底链。
检查什么:新用户、新内容、特征缺失时走哪条路径;兜底是否有独立监控。
不通过会怎样:新用户首页空白,或者推荐结果全是同一批内容。
P2 推荐结果有多样性约束与解释入口。
检查什么:是否限制同一作者占比;用户能否知道「为什么推荐这个」。
不通过会怎样:信息茧房,或者用户对推荐不信任。
九、上线与事故响应
P0 上线前有回滚方案,且回滚不需要数据修复。
检查什么:新功能能否通过开关关闭;关闭后旧数据是否兼容;是否有双写/双读过渡。
不通过会怎样:出问题时只能往前修,修复时间不可控。
P0 关键链路有 SLI 与告警,告警能指向行动。
检查什么:发布成功率、Feed 刷新 p99、消息到达率、未读准确率是否有监控;告警是否有处理手册。
不通过会怎样:故障发生了没人知道,或者知道了不知道做什么。
P1 灰度按用户或内容分桶,不按机器分桶。
检查什么:同一用户是否会看到新旧两种行为;分桶键是否稳定。
不通过会怎样:用户体验不一致,实验数据不可信。
P1 事故复盘区分触发因素与根本原因。
检查什么:复盘是否停在「某服务挂了」;是否追问「为什么挂了会影响这么大」。
不通过会怎样:同类事故反复发生。
P2 有容量与成本的定期回顾。
检查什么:Feed 写放大、消息存储增长、推送成本是否定期看;是否有预算。
不通过会怎样:成本悄悄上涨,直到财务报警。
清单之外的判断
这份清单能覆盖多数常见问题,但不能替代思考。使用时有三个提醒:
第一,清单是下限,不是上限。 全部勾选只说明没有明显遗漏,不说明方案是对的。方案对不对,要看它是否匹配当前产品阶段。
第二,不做某项不等于错。 早期产品可以没有推荐、没有多端、没有复杂审核。关键是知道「现在不做,代价是什么,什么时候必须做」。
第三,清单会过期。 产品变了、规模变了、依赖变了,检查项也要变。建议每半年回顾一次,删掉不再适用的项,补上新的失败场景。
最后,如果评审时只能问三个问题,问这三个:
- 这条内容在什么状态下、对谁、在哪个入口可见?
- 这次操作失败或重复时,用户看到什么?
- 这条链路故障时,影响一个用户、一个群,还是整个首页?
三个问题答不上来的方案,先不要上线。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。