《互联网产品的服务端架构·内容、社交与实时互动》8.2 单聊、群聊与系统消息
从系统通知被用户回复、产生没有接收方的会话写起,对照单聊、群聊、系统会话的成员与发送权限,说明群成员上限如何影响写扩散,给出会话校验与 CanSend 的 Go 实现、边界测试和真实运行输出,并列出会话模型设计、服务端发送权限与客户端展示的常见错误。
tag
从系统通知被用户回复、产生没有接收方的会话写起,对照单聊、群聊、系统会话的成员与发送权限,说明群成员上限如何影响写扩散,给出会话校验与 CanSend 的 Go 实现、边界测试和真实运行输出,并列出会话模型设计、服务端发送权限与客户端展示的常见错误。
从两个客户端同时发消息却看到不同顺序的事故写起,说明单聊会话 ID 如何由双方 ID 排序后哈希生成,比较会话内序号与全局序号两种方案,给出消息校验、按发送时间与 ID 分配序号的 Go 实现、连续序号测试和真实运行输出,并列出消息模型设计的常见错误。
四个品牌共用一套组件库,一次全量合并后,A 品牌的结算主色出现在 B 品牌的收银台,排查发现是品牌包被当成全局配置加载。多品牌复用的难点不是覆盖,而是边界与隔离。本节用 TypeScript 模块演示覆盖顺序、业务包与品牌包的权限边界、同层冲突检测和复用度计算,并给出多品牌接入前的验收判据。
从「回声」用户被二十条连赞推送逼到关闭通知权限的事故写起,拆解自己操作、被屏蔽者、短时间刷屏和聚合窗口四类触发边界,说明逐条通知与聚合通知的取舍,给出 ShouldNotify 的 Go 实现、时间窗口与维度隔离测试,以及真实运行输出和常见错误清单。
从「回声」一条违规评论在正文审核通过后存活四十分钟的事故写起,拆解正文、根评论、回复和昵称各自的审核时机,说明折叠为什么不能等于删除、根评论为什么不应被折叠,给出 Fold 规则的 Go 实现、拉黑子树与阈值测试,以及真实运行输出和常见错误清单。
从「回声」评论区「查看更多回复」翻页出现重复评论的事故写起,对比平铺、两层与多级评论树的代价,解释根评论按时间还是按热度分页、回复偏移量为什么会漂移,给出 Build、Page 的 Go 实现、坏输入与分页边界测试,以及一次真实运行输出和常见错误清单。
从「回声」一次点赞活动被代理池刷穿的事故写起:说明「同一用户对同一目标」「同一 IP 多账号」「同一设备批量注册」三种频控维度分别拦什么、漏什么,给出 Rule、Throttle、Allow 与 AllowE 的滑动窗口 Go 实现、表驱动测试和真实运行输出,并整理频控键设计的常见错误与边界。
从「回声」大 V 取消点赞后计数仍上涨的事故写起:对比精确计数、近似去重计数与对账重建三档方案,说明缓存计数何时可以滞后、何时必须回源,给出 Drift、Evaluate 与 NeedsRebuild 的 Go 实现、表驱动测试和真实运行输出,并整理对账的常见错误与边界。
从「回声」上线点赞后计数不动的投诉写起:拆解点赞、评论、收藏三种互动对一致性的不同要求,说明关系表与物化计数为何必须分开写入,给出 Counter、Key、Delta 与 Apply 的 Go 实现、表驱动测试和真实运行输出,并列出互动计数的常见错误与边界。
从「回声」共同好友查询在 1 万好友时耗时 12 秒的事故写起,拆解我关注谁、谁关注我、共同好友三类关系查询的代价,说明大 V 粉丝列表为什么不能全量拉,给出 Graph、Followers、Following 与 Common 的 Go 实现、去重排序测试和真实运行输出,并列出关系链存储与查询的常见错误。
从「回声」一次拉黑只在前端生效的事故写起:用户拉黑骚扰者后,换个客户端仍能看到对方内容。文章把拉黑、屏蔽与可见性拆成不同层次,给出 CanView 的判定顺序、可读原因、拉黑压过好友的实现、边界测试与真实输出,并说明为什么可见性必须在服务端最终响应处统一生效。
从「回声」上线好友功能后的一次投诉写起:一方删除好友,另一方仍能看到仅好友可见的动态。文章拆解关注、好友与拉黑三种边的方向语义,说明关注后对方是否知情、好友请求被拒后关系如何落库,给出 Validate 与 Mutual 的 Go 实现、表驱动测试和真实运行输出,并列出关系建模的常见错误与边界。
按钮组件从 1.4 升到 1.5,发布说明写着「只加了可选属性」,四十多个业务包却在编译期报错。问题不在版本号,而在没人把组件契约当成可比较的对象。本节用 TypeScript 模块演示属性、事件、插槽与可访问性语义的变更分类、兼容判定、版本递增和契约快照比较。
从实验组点击率涨了 8%、次留却跌了 2% 的事故写起,说明分桶必须稳定、指标必须先定、实验期间不能混入其他改动;给出基于 FNV 的 0 到 99 分桶、rollout 判定与相对提升计算的可测试 Go 实现,并讨论点击与留存的取舍,附真实运行输出。
从用户点过一条内容、刷新后它就消失的投诉写起,区分按内容 ID 去重与按事件去重,讨论已读是否应该影响排序,以及同作者相邻内容从哪里开始折叠;给出保持顺序、容忍 nil 入参的 Go 实现与边界测试,避免误删与重复曝光,并附上真实运行输出。
从三天前爆款占满首页的事故写起,拆解时间衰减、点赞热度与作者亲和度三种信号各自的偏差,说明多样性其实是限制同作者与同话题占比,而不是随机打散;给出带权重校验和稳定排序的可测试 Go 实现,以及新内容起不来的排查与修正路径,并附真实测试输出。
从普通用户关注 800 人的首页出发,拆解混合时间线为什么必须按作者分层而不是按用户分层:活跃作者推、长尾作者拉,合并顺序与名额分配怎样决定大 V 内容能否出现在第一屏,并用可测试的 Go 混合函数固定比例、去重与上限的边界,最后给出覆盖率监控与灰度顺序。
从一条粉丝 500 万的明星动态出发,拆解推模式为什么把成本放在写时:一条内容要扩散多少行、写队列如何被大 V 堵死、普通用户为什么跟着延迟,并用可测试的 Go 策略选择与成本函数固定粉丝门槛、写读成本与负数校验的边界,最后给出队列隔离与幂等重试的取舍。
从关注 500 人与 5000 人的首页刷新出发,拆解拉模式为什么把成本放在读时:一次刷新究竟要合并多少来源、并发查收件箱怎样拖垮 p99、关注 3000 人如何把首页延迟推到 3 秒,并用可测试的 Go 合并函数固定去重、排序与截断的边界,最后给出容量估算与降级顺序。
「回声」的缓存命中率升到 92%,端到端延迟却变差了。本节把命中率拆成请求、token 与成本三个口径,说明为什么必须按能力与租户分层、精确命中与语义命中要分开、缓存污染与语义误命中要单独计数,并给出可运行的 TypeScript 分层指标实现。