今天给大家分享 B 站的评论系统的 组件化、平台化建设
通过持续演进架构设计,管理不断上升的系统复杂度,从而更好地满足各类用户的需求。
基础功能模块
评论的基础功能模块是相对稳定的。
1. 发布评论:支持无限盖楼回复。
2. 读取评论:按照时间、热度排序;显示评论数、楼中楼等。
3. 删除评论:用户删除、UP 主删除等。
4. 评论互动:点赞、点踩、举报等。
5. 管理评论:置顶、精选、后台运营管理(搜索、删除、审核等)。
结合 B 站以及其他互联网平台的评论产品特点,评论一般还包括一些更高阶的基础功能:
1. 评论富文本展示:例如表情、@、分享链接、广告等。
2. 评论标签:例如 UP 主点赞、UP 主回复、好友点赞等。
3. 评论装扮:一般用于凸显发评人的身份等。
4. 热评管理:结合 AI 和人工,为用户营造更好的评论区氛围。
架构设计
评论是主体内容的外延。因此一般会作为一个独立系统拆分设计。
架构设计 - 概览
架构设计 - reply-interface
reply-interface 是评论系统的接入层,主要服务于两种调用者:一是客户端的评论组件,二是基于评论系统做二次开发或存在业务关联的其他业务后端。
面向移动端/WEB 场景,设计一套基于视图模型的 API,利用客户端提供的布局能力,BFF 层负责组织业务数据模型,并转换为视图模型,编排后下发给客户端。
面向服务端场景,设计的 API 需要体现清晰的系统边界,最小可用原则对外提供数据,同时做好安全校验和流量控制。
对评论业务来说,业务数据模型是最为复杂的。B 站评论系统历史悠久,承载的功能模块相当之多,其中最核心的是发布类接口以及列表类接口,一写一读,数据字段多、依赖服务多、调用关系复杂,特别是一些依赖的变更,容易造成整个系统的腐化。
因此,我们将整个业务数据模型组装,分为两个步骤,一是服务编排,二是数据组装。服务编排拆分为若干个层级,同一层级的可以并发调用,前置依赖较多的可以流水线调用,结构性提升了复杂调用场景下的接口性能下限;针对不同依赖服务所提供的 SLA 不同,设置不同的降级处理、超时控制和服务限流方案,保证少数弱依赖抖动甚至完全不可用情况下评论服务可用。数据组装在服务编排之后执行,例如在批量查询评论发布人的粉丝勋章数据之后,将其转换、组装到各个评论卡片之中。
架构设计 - reply-admin
评论管理服务层,为多个内部管理后台提供服务。运营人员的数据查询具有:
1. 组合、关联查询条件复杂;
2. 刚需关键词检索能力;
3. 写后读的可靠性与实时性要求高等特征。
此类查询需求,ES 几乎是不二选择。但是由于业务数据量较大,需要为多个不同的查询场景建立多种索引分片,且数据更新实时性不高。因此,我们基于 ES 做了一层封装,提供统一化的数据检索能力,并结合在线数据库刷新部分实时性要求较高的字段。
架构设计 - reply-service
评论基础服务层,专注于评论功能的原子化实现,例如查询评论列表、删除评论等。一般来说,这一层是较少做业务逻辑变更的,但是需要提供极高的可用性与性能吞吐。因此,reply-service 集成了多级缓存、布隆过滤器、热点探测等性能优化手段。
架构设计 - reply-job
评论异步处理层,主要有两个职责:
1. 与 reply-service 协同,为评论基础功能的原子化实现,做架构上的补充。
为什么基础功能的原子化实现需要架构的补充呢?最典型的案例就是缓存的更新。一般采用 Cache Aside 模式,先读缓存,再读 DB;缓存的重建,就是读请求未命中缓存穿透到 DB,从 DB 读取到内容之后反写缓存。这一套流程对外提供了一个原子化的数据读取功能。但由于部分缓存数据项的重建代价较高,比如评论列表(由于列表是分页的,重建时会启用预加载),如果短时间内多个服务节点的大量请求缓存未命中,容易造成 DB 抖动。解决方案是利用消息队列,实现「单个评论列表,只重建一次缓存」。归纳而言,所谓架构上的补充,即是「用单线程解决分布式无状态服务的共性问题」。另一方面,repl