设计一个支持10W QPS的评论中台,你会怎么设计?

在B站,UP主每天都会发布海量的视频、动态、专栏等内容,随之而来的是弹幕和评论区的各种讨论。

播放器中直接滚动播放的弹幕,如同调味剂,重在提升视频观看体验;

而点进评论区,相对而言评论文本更长,内容的观点、形式都更丰富,更像是饭后甜点。

随着业务不断发展,B站的评论系统逐渐组件化、平台化;

通过持续演进架构设计,管理不断上升的系统复杂度,从而更好地满足各类用户的需求。

评论的基础功能模块是相对稳定的。

  1. 发布评论:支持无限盖楼回复。
  2. 读取评论:按照时间、热度排序;显示评论数、楼中楼等。
  3. 删除评论:用户删除、UP主删除等。
  4. 评论互动:点赞、点踩、举报等。
  5. 管理评论:置顶、精选、后台运营管理(搜索、删除、审核等)。

结合B站以及其他互联网平台的评论产品特点,评论一般还包括一些更高阶的基础功能:

  1. 评论富文本展示:例如表情、@、分享链接、广告等。
  2. 评论标签:例如UP主点赞、UP主回复、好友点赞等。
  3. 评论装扮:一般用于凸显发评人的身份等。
  4. 热评管理:结合AI和人工,为用户营造更好的评论区氛围。

由于篇幅限制,只能给大家展示小部分内容,

全套面试笔记及答案【点击此处】即可免费获取

 

7.1 总体的架构设计

评论系统 中台,从总体的架构上来区分,分为:

(1)接入层

(2)服务层

(3)异步任务层

(4)cache层

(5)DB层

 

7.2 接入层架构 reply-interface

reply-interface是评论系统的接入层,主要服务于两种调用者:

一是客户端的评论组件,

二是基于评论系统做二次开发或存在业务关联的其他业务后端。

面向移动端/WEB场景,设计一套基于视图模型的API,利用客户端提供的布局能力,接入层负责组织业务数据模型,并转换为视图模型,编排后下发给客户端。

面向服务端场景,接入层设计的API需要体现清晰的系统边界,最小可用原则对外提供数据,同时做好安全校验和流量控制。

接入层整个业务数据模型组装,分为两个步骤:

一是服务编排,

二是数据组装。

服务编排拆的架构为:

(1)对服务进行分层,分为若干个层级,

(2)前置依赖通过流水线调用,

(3)同一层级的可以并发调用,结构性提升了复杂调用场景下的接口性能下限;

(4)针对不同依赖服务所提供的SLA不同,设置不同的降级处理、超时控制和服务限流方案,保证少数弱依赖抖动甚至完全不可用情况下评论服务可用。

SLA一般指服务级别协议。服务级别协议是指提供服务的企业与客户之间就服务的品质、水准、性能等方面所达成的双方共同认可的协议或契约。

7.3 服务层架构

7.3.1 评论管理服务层reply-admin

评论管理服务层,为多个内部管理后台提供服务。

运营人员的数据查询具有:

  1. 组合、关联查询条件复杂;
  2. 刚需关键词检索能力;
  3. 写后读的可靠性与实时性要求高等特征。

此类查询需求,ES几乎是不二选择。

但是由于业务数据量较大,需要为多个不同的查询场景建立多种索引分片,且数据更新实时性不高。

因此,我们基于ES做了一层封装,提供统一化的数据检索能力,并结合在线数据库刷新部分实时性要求较高的字段。

7.3.2 评论基础服务 reply-service 架构设计

评论基础服务层,专注于评论功能的原子功能,例如:

  • 查询评论列表
  • 删除评论等。

这一层的特点是:

  • 较少做业务逻辑变更的,
  • 极高的可用性
  • 极高性能吞吐。

这一层采用了多种高性能方案:

  • 多级缓存
  • 布隆过滤器
  • 热点探测等。
7.3.3 异步任务层reply-job 架构设计

异步任务层,主要有两个职责:

  1. 为原子的业务操作操作,提供异步协助

与reply-service协同,为评论基础功能的原子化实现做架构上的补充。

  1. 异步削峰处理

为 长耗时/高吞吐的调用, 做异步化/削峰处理

职责1:提供异步协助

为原子的业务操作操作,提供异步协助, 最典型的案例就是缓存的更新。

一般采用Cache Aside模式,先读缓存,再读DB;

Cache Aside模式下的缓存的重建策略:就是读请求未命中缓存穿透到DB,从DB读取到内容之后反写缓存。

这一套流程对外提供了一个原子化的数据读取功能。

但由于部分缓存数据项的重建代价较高,比如评论列表。

为啥呢?

由于列表是分页的,缓存重建时会启用预加载,也就是要多加载几页,

如果短时间内大量请求缓存未命中,并且多个服务节点的同时重建缓存,容易造成DB抖动。

解决方案是啥?

利用消息队列+reply-job ,实现单个评论列表异步重建,只重建一次缓存。

另外呢,reply-job还作为数据库binlog的消费者,执行缓存的更新操作。

职责2:异步削峰处理

与reply-interface协同,为 长耗时/高吞吐的调用,做异步化/削峰处理

诸如评论发布等操作,基于安全/策略考量,会有非常重的前置调用逻辑。

对于用户来说,这个长耗时几乎是不可接受的。同时,时事热点容易造成发评论的瞬间峰值流量。

因此,reply-interface在处理完一些必要校验逻辑之后,会通过消息队列送至reply-job异步处理,包括送审、写DB、发通知等。

那么异步处理后用户体验是如何保证的呢?

首先是当次交互,返回最新数据。

C端的发评接口会返回展示新评论所需的数据内容,客户端据此展示新评论,完成一次用户交互。

其次,控制延迟时长,如果太长则进行预警和调优

若用户重新刷新页面,因为发评的异步处理端到端延迟基本在2s以内,此时所有数据已准备好,不会影响用户体验。

7.3.4 消息队列的保证有序

利用了消息队列的「有序」特性,将单个评论区内的发评串行处理,避免了并行处理导致的一些数据错乱风险。

一个有趣的问题是,早年间评论显示楼层号,楼层号实际是计数器,且在一个评论区范围内不能出现重复。

因此,这个楼层发号操作必须是在一个评论区范围内串行的(或者用更复杂的锁实现),否则两条同时发布的评论,获取的楼层号就是重复的。

而分布式部署+负载均衡的网关,处理发评论请求是无法实现这种串行的,因此需要放到消息队列中处理。

 

7.4 数据存储架构

7.4.1 结构化模型设计

结合评论的产品功能要求,评论需要至少两张表:

(1)首先是评论表,主键是评论id,关键索引是评论区id;

(2)其次是评论区表,主键是评论区id,平台化之后增加一个评论区type字段,与评论区id组成一个”联合主键“。

(3)评论内容表. 由于评论内容是大字段,且相对独立、很少修改,因此独立设计第3张表。主键也是评论id。

评论表和评论区表的字段主要包括4种:

  1. 关系类,包括发布人、父评论等,这些关系型数据是发布时已经确定的,基本不会修改。
  2. 计数类,包括总评论数、根评论数、子评论数等,一般会在有评论发布或者删除时修改。
  3. 状态类,包括评论/评论区状态、评论/评论区属性等,评论/评论区状态是一个枚举值,描述的是正常、审核、删除等可见性状态;评论/评论区属性是一个整型的bitmap,可用于描述评论/评论区的一些关键属性,例如UP主点赞等。
  4. 其他,包括meta等,可用于存储一些关键的附属信息。

评论回复的树形关系,如下图所示:

以评论列表的访问为例,我们的查询SQL可能是(已简化):

  1. 查询评论区基础信息:SELECT * FROM subject WHERE obj_id=? AND obj_type=?
  2. 查询时间序一级评论列表:SELECT id FROM reply_index WHERE obj_id=? AND obj_type=? AND root=0 AND state=0 ORDER BY floor=? LIMIT 0,20
  3. 批量查询根评论基础信息:SELECT * FROM reply_index,reply_content WHERE rpid in (?,?,...)
  4. 并发查询楼中楼评论列表:SELECT id FROM reply_index WHERE obj_id=? AND obj_type=? AND root=? ORDER BY like_count LIMIT 0,3
  5. 批量查询楼中楼评论基础信息:SELECT * FROM reply_index,reply_content WHERE rpid in (?,?,...)
7.4.2 分库分表架构

评论系统对数据库的选型要求,有两个基本且重要的特征:

  1. 必须有事务;
  2. 必须容量大。

一开始,B站采用的是MySQL分表来满足这两个需求。MySQL分库分表数据量起来之后,原来的MySQL分表架构很快到达存储瓶颈。

提示:
mysql 不停服在线扩容实际非常复杂,很多公司选择停服切换, 估计B站为了不停服, 或者不愿意发生停服的风险, 选择了 专门的商用 分布式 TiDB, 毕竟这个是花了钱的。

于是从2020年起,我们逐步迁移到TiDB,从而具备了在线水平扩容能力。

7.4.3 高并发写入架构,TPS提升了10倍以上

面对10Wqps的并发写入超大规模吞吐量,做了如下优化:

方案一:内存聚合+ 批量写入评论区评论计数的更新,先做内存合并再更新,可以减少热点场景下的SQL执行条数;评论表的插入,改成批量写入。

方案二:核心逻辑和非核心异步化,为核心操作瘦身

非数据库写操作的其他业务逻辑,拆分为前置和后置两部分,

其他业务逻辑从数据写入主线程中剥离,交由其他的线程池并发执行。

总之,采用新的高并发写入架构之后,性能得到极大提升。

写入架构调整之后,系统的并发处理能力有了极大提升,同时支持配置并行度/聚合粒度,在吞吐方面具备更大的弹性,热点评论区发评论的TPS提升了10倍以上。

7.5 缓存层架构

7.5.1 数据的缓存模型架构

主要有3项缓存:

  1. subject,对应于「查询评论区基础信息」,

redis string类型,value使用JSON序列化方式存入。

  1. reply_index,对应于「查询xxx评论列表」,

redis sorted set类型。

member是评论id,score对应于ORDER BY的字段,如floor、like_count等。

  1. reply_content,对应于「查询xxx评论基础信息」

存储内容包括同一个评论id对应的reply_index和reply_content表的两部分字段。

7.5.2 缓存的一致性架构

缓存的一致性依赖binlog刷新,主要两个要点:

  1. 消息队列,保证 同一个评论区内有序

binlog投递到消息队列,分片key选择的是评论区,保证单个评论区和单个评论的更新操作是串行的,消费者顺序执行,保证对同一个member的zadd和zrem操作不会顺序错乱。

  1. 采用删除缓存而非直接更新的方式

程序主动写缓存和binlog刷缓存,都采用删除缓存而非直接更新的方式,避免并发写操作时,特别是诸如binlog延迟、网络抖动等异常场景下的数据错乱。

7.5.3 缓存击穿解决方案

那大量写操作后读操作缓存命中率低的问题如何解决呢?

读缓存的时候, 可以利用 锁的机制,进行同步控制,防止缓存击穿。

7.5.4 热点探测架构

除了写热点,评论的读热点也有一些典型的特征:

  1. 由于大量接口都需要读取评论区基础信息,存在读放大,因此该操作是最先感知到读热点存在的。
  2. 由于评论业务的下游依赖较多,且多是批量查询,对下游来说也是读放大。此外,很多依赖是体量相对小的业务单元,数据稀疏,难以承载评论的大流量。
  3. 评论的读热点集中在评论列表的第一页,以及热评的热评。
  4. 评论列表的业务数据模型也包含部分个性化信息。

在读取评论区基础信息阶段探测热点,并将热点标识传递至服务层;

服务层实现了页面请求级的热点本地缓存,感知到热点后即读取本地缓存,然后再加载个性化信息。

热点探测的实现基于单机的滑动窗口+LFU,那么如何定义、计算相应的热点条件阈值呢?

首先,我们进行系统容量设计,列出容量计算的数学公式,主要包括各接口QPS的关系、服务集群总QPS与节点数的关系、接口QPS与CPU/网络吞吐的关系等;

然后,收集系统内部以及相应依赖方的一些的热点相关统计信息,通过公式,计算出探测数据项的单机QPS热点阈值。

最后通过热点压测,来验证相应的热点配置与代码实现是符合预期的。

…… 

<think>嗯,用户让我介绍一下分布式系统设计与开发,首先我需要明确用户的需求是什么。可能用户是学生或者刚入行的开发者,想了解这个领域的基础知识。或者他们可能在实际项目中遇到了问题,需要一些指导。 首先,我应该从定义开始,解释什么是分布式系统。然后,可能需要分几个部分来介绍,比如关键特性、设计挑战、核心技术、开发流程和实际案例。这样结构清晰,用户容易理解。 关键特性方面,可用性、扩展性、容错性、一致性这些是重点。需要分别解释每个特性的重要性,比如可用性通过冗余实现,扩展性分水平和垂直,容错性涉及冗余和故障恢复,一致性则要提到不同的模型比如强一致和最终一致。 设计挑战部分,网络问题、数据一致性、时钟同步、安全这些是常见的难点。需要具体说明每个挑战的具体表现,比如网络延迟导致的数据不同步,如何解决脑裂问题,时钟不同步带来的影响,以及安全方面的认证和加密措施。 核心技术点可能需要列举CAP定理、共识算法、分片、微服务、容器化、消息队列、监控等。每个技术点需要简要解释其作用,比如Raft和Paxos用于共识,分片如何提升性能,微服务的优缺点,Kubernetes在容器编排中的作用,消息队列解耦系统组件,监控的重要性。 开发流程部分,需求分析、架构设计、技术选型、编码测试、部署维护这些步骤需要按顺序说明,强调每个阶段的关键点,比如在需求分析中明确一致性要求,架构设计中的模块划分,技术选型时的社区支持考虑,测试中的混沌工程,部署中的自动化工具。 实际案例可以举电商、社交、金融科技的例子,说明分布式系统在不同场景下的应用,比如电商的高并发处理,社交平台的实时消息,金融系统的低延迟需求。 可能用户需要了解实际应用中的挑战和解决方案,所以结合案例会有帮助。同时要注意使用正确的中文术语,避免翻译腔,保持口语化但专业。 需要检查是否遵循了系统级指令,比如数学公式是否正确使用$...$,独立公式用$$...$$,但这里可能数学内容不多,主要注意结构分点和LaTeX的正确使用。不过用户的问题可能不涉及太多数学,但如果有提到算法或公式,比如共识算法中的术语,可能需要用LaTeX,但例子中没有,所以暂时不用。 最后,确保回答结构清晰,分点明确,帮助用户逐步理解分布式系统的设计与开发。避免过于技术化的术语,用易懂的语言解释概念,同时保持专业性。</think>好的,我将逐步为您介绍分布式系统设计与开发的核心内容和关键要点: 一、分布式系统的定义 $$ \text{分布式系统} = \{ 多台计算机 + 网络通信 + 协调机制 \} $$ 指由多个通过网络连接的节点(物理机/虚拟机/容器)协同工作,对外表现为统一整体的计算系统。典型代表:云计算平台、分布式数据库、微服务架构等。 二、关键特性与设计目标 1. **高可用性**(Availability) - 通过冗余设计实现$99.9\%$+的正常运行时间 - 示例:$N+1$冗余、跨机房部署 2. **可扩展性**(Scalability) - 水平扩展(加机器) vs 垂直扩展(升配置) - 动态扩缩容能力:$Load \propto \frac{1}{Resource}$ 3. **容错性**(Fault Tolerance) - 实现故障检测(心跳机制)和自动恢复 - 使用冗余副本:$副本数 \geq 2f+1$(容忍f个故障) 4. **一致性模型** - 强一致性(ACID) vs 最终一致性(BASE) - 常见折中方案:$Quorum = W + R > N$ 三、核心设计挑战 1. **网络不确定性** - 处理延迟($Latency \in [1ms, 500ms]$)、丢包、分区 - 必须考虑部分失败(Partial Failure)场景 2. **数据一致性难题** - CAP定理:$$ \text{一致性(C)} \cap \text{可用性(A)} \cap \text{分区容错(P)} = \emptyset $$ - 典型解决方案:Paxos/Raft共识算法 3. **时钟同步问题** - 物理时钟误差:$|Clock_A - Clock_B| \leq \epsilon$ - 使用逻辑时钟(Lamport Timestamp)解决事件排序 四、核心技术组件 1. **通信层** - RPC框架(gRPC/Dubbo) - 消息队列(Kafka/RabbitMQ) 2. **协调服务** - ZooKeeper/etcd实现分布式锁、配置管理 - 使用Watch机制:$Watch(key) \rightarrow Event$ 3. **数据存储** - 分布式数据库(Cassandra/Spanner) - 对象存储(S3/OSS)的分片策略:$Hash(key) \mod N$ 4. **资源调度** - 容器编排(Kubernetes/Mesos) - 调度算法:$Scheduler = f(CPU, Mem, Network)$ 五、开发实践流程 1. 需求分析阶段 - 明确一致性级别要求 - 预估QPS:$$ Throughput = \frac{Requests}{Second} $$ 2. 架构设计阶段 - 选择合适的模式: ```mermaid graph LR A[单体] --> B[服务拆分] B --> C[数据分片] C --> D[多副本] ``` 3. 技术选型原则 - 成熟度 vs 创新性 - 社区活跃度:$Commit_{30d} > 50$ 4. 测试验证 - 混沌工程(Chaos Engineering) - 模拟网络分区:$iptables -A INPUT -p tcp --dport 8080 -j DROP$ 六、典型应用场景 1. 电商系统 - 库存服务:$$ Stock = \sum_{node=1}^N Stock_{node} $$ - 订单分库:$UserID \% 16$ 2. 社交平台 - 消息扩散:$$ Fan-out = Push \oplus Pull $$ - 分布式计数器(HyperLogLog) 3. 金融科技 - 分布式事务(Saga模式) - 全局唯一ID生成:$Snowflake = Timestamp + NodeID + Sequence$ 建议学习路径:从理解CAP定理开始→掌握Raft协议→实践微服务开发→研究大规模系统案例(如Google Spanner)。实际开发中需特别注意:幂等性设计、重试机制、监控指标埋点(如P99延迟)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值