B 站评论系统架构设计难点

在这里插入图片描述

更多大厂面试内容可见 -> http://11come.cn

B 站评论系统架构设计难点

这里整理一下在哔哩哔哩技术公众号看到的 B 站评论系统的架构设计文章,自己在学习过程中,对其中感觉比较有帮助的点做一下整理,方便以后查阅,详细版可以点击上方原文链接查看(文中图片均来源于原文)

架构设计

图片来源于原文

在评论业务中,最为核心的功能是 发布类接口列表类接口 ,数据字段多、依赖服务多、调用关系复杂,因此容易造成系统腐化

接口解耦

这里在设计的时候,将整个业务数据的查询分为了两个步骤:服务编排、数据组装

举个例子:在批量查询评论发布人的粉丝勋章数据之后,将其转换、组装到各个评论卡片中

如果不采用这样的方式,而是在查询评论卡片时,再去查询该评论发布人的粉丝勋章数据,那么会导致【查询评论】和【查询发布人粉丝勋章数据】这两个接口耦合度过高的情况,一旦【查询粉丝勋章数据】接口出现了不可用,会导致【查询评论】功能也会不可用

因此先【查询粉丝勋章数据】,再将数据拼接到评论卡片中,降低两个接口的耦合度,将两个接口之间的强依赖关系变为弱依赖关系,并且可以针对两个接口做 不同的降级、限流、超时控制

基础服务 reply-service

图片来源于原文

评论基础服务层(reply-service)专注于评论功能的原子化实现,也是最小粒度的功能,如查询评论、删除评论等功能

该层的接口是需要被其他业务层进行大量调用与业务逻辑组合,因此该层的接口需要保证较高的 可用性和性能

因此会集成 多级缓存、热点探测、布隆过滤器 等性能优化手段

异步处理 reply-job

图片来源于原文

异步处理层 reply-job 主要作用就是为评论基础功能做一些架构上的补充

缓存更新

缓存更新经常采用的 缓存旁路模式(Cache Aside) ,即先读缓存,再读 DB,之后进行缓存的重建

存在的问题: 部分缓存数据重建代价较高,比如评论列表(评论列表是分页的,重建时会预加载,加载多页的数据),那么如果短时间内大量请求未命中,就会导致 DB 瞬时压力过大,造成 DB 抖动

解决方案: 采用消息队列,保证对单个评论列表,只重建一次缓存

reply-job 的另外一个作用:作为数据库 bin log 的消费者,执行缓存的更新操作

削峰/异步化处理

reply-job 还负责与 reply-interface 协同,为一些长耗时/高吞吐的调用进行 异步化/削峰 处理

比如:评论发布功能 ,在发布之前,基于安全/策略考量,会有很多前置调用逻辑,导致耗时很长

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

这里需要保证单个评论区内的发布评论 串行 处理,如果并行处理可能会出现一些数据错乱的风险,因此为了保证串行处理就利用到了 消息队列的有序性

存储设计

数据库设计

评论功能主要是三张表:评论表+评论区表+评论内容表

因为评论内容的大字段,相对独立,很少修改,因此独立设计成一张表(评论内容表)

数据库选型:

刚开始使用 MySQL 分表来实现评论功能,但是很快达到存储瓶颈,从 2020 年起,逐步迁移到 TiDB,从而具备了水平扩容能力

缓存设计

缓存选用 Redis ,主要缓存的信息:

1、评论区的基础信息(redis string 类型,value 使用 JSON 序列化存入)

2、查询 xxx 的评论列表(redis sorted set 类型,member 为评论 id,score 对应 order by 字段)

3、查询 xxx 的评论基础信息(redis)

缓存的一致性依赖于 binlog 刷新,有以下几处关键细节:

1、binlog 投递到消息队列,需要保证单个评论区以及单个评论更新的 串行化 (分片 key 选择评论区)

2、数据库更新后,采用删除缓存而非直接更新的方式,避免并发写时的数据错乱

此时会存在大量写操作后, 读操作缓存命中率低的问题 ,利用 singleflight 进行控制,防止 缓存击穿

(singleflight 是一种编程模式,用来防止在高并发环境下对于同一资源的重复请求,尤其适用于处理缓存击穿问题。缓存击穿指的是当缓存失效的瞬间,由于并发请求同一数据,导致大量请求直接落到数据库上,从而可能引起数据库的性能问题)

可用性设计

写热点和读热点

上边有大量的评论区维度的串行操作,导致 发布评论 吞吐量较低,出现热点文章下发布大量评论,就会出现严重延迟

针对吞吐量低的问题,做出如下优化:

1、评论区评论计数的更新:在内存中先合并再更新,减少热点场景下的 SQL 执行次数,评论表的插入也改为批量插入 (合并是很常见的优化,对于一些实时性要求不强的场景,会将多条数据合并,比如达到几秒合并一次,或者达到多少条数据合并一次,之后通过一次 SQL 完成插入)

2、非数据库写操作的其他业务逻辑,将这些逻辑从【数据写入主线程】中剥离,交给其他线程并发执行

经过上述优化,热点评论区发布评论 TPS 提升了 10 倍以上

图片来源于原文

接下来说一下 读热点问题 中的典型特征:

1、由于大量接口都需要读取评论区基础信息,存在读放大(在读取数据时,需要关联的读取其他大量数据即为读放大),因此该操作是最先感知到读热点存在的

2、评论业务下游依赖较多,因此对下游来说也是读放大,很多下游依赖是体量相对小的业务单元,难以承载大流量

3、读热点集中在评论列表的第一页,以及热评

4、评论列表的业务数据模型也包含部分个性化信息

基于以上特征, 读热点探测 放在【读取评论区基础信息】阶段进行,探测到热点之后,在本地缓存中进行热点数据的读取

image-20240507221540605

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

首先,我们进行系统容量设计,列出容量计算的数学公式,主要包括各接口QPS的关系、服务集群总QPS与节点数的关系、接口QPS与CPU/网络吞吐的关系等;然后,收集系统内部以及相应依赖方的一些的热点相关统计信息,通过前面列出的公式,计算出探测数据项的单机QPS热点阈值。最后通过热点压测,来验证相应的热点配置与代码实现是符合预期的。

扩展:LFU 和 LRU(Least Recently Used) 的区别:

LRU :LRU是另一种流行的缓存替换策略,它基于数据项的最近访问时间进行缓存管理,最近最少访问的数据项将被首先替换。这种策略假设最近使用过的数据将来很可能再次被使用。

LFU :与LRU基于时间的策略不同,LFU更关注数据项的访问频率。理论上,LFU能更好地识别并保留那些即使不是最近使用但访问频率高的长期热点数据。

冗余与降级

冗余与降级是保证可用性必不可少的手段

上边的评论基础服务集成了 多级缓存 ,那么在上一级缓存不可用时,要求可以降级至下一级缓存,保证功能的可用性

评论系统架构为同城读双活,数据库与缓存均是双机房独立部署的,均支持多副本,具备水平扩容的弹性。针对双机房架构下特有的副机房数据延迟故障,支持入口层切流/跨机房重试/应用层补偿,尽可能保证极端情况下用户无感。

在功能层面,我们做了重要级别划分,把相应的依赖划分为强依赖(如审核)、弱依赖(如粉丝勋章)。对于弱依赖,我们一方面在异常情况下坚决限流熔断,另一方面也通过超时控制、请求预过滤、优化调用编排甚至技术方案重构等方式持续优化提升非核心功能的可用性,为业务在评论区获得更好的曝光展现。

原文中还有一部分是关于 热评的设计 ,即对于热评的存储、热评的查询、热评的排序如何进行设计,这一部分较为复杂,如果感兴趣可以查看原文第 7 部分:热评设计

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/835627.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

你要顺着毛撸Rust——简评LogLogGames放弃Rust游戏开发

庄晓立/LIIGO,2024年5月11日。 上个月底,游戏开发工作室LogLogGames发文《Leaving Rust gamedev after 3 years》,声明在经历3年磨难后决定放弃用Rust语言开发游戏。万字长文,开启吐槽模式,引发国内外大量争论。 我尊…

Portforge:一款功能强大的轻量级端口混淆工具

关于Portforge Portforge是一款功能强大的轻量级端口混淆工具,该工具使用Crystal语言开发,可以帮助广大研究人员防止网络映射,这样一来,他人就无法查看到你设备正在运行(或没有运行)的服务和程序了。简而言…

XML属性

XML属性是XML元素的附加信息&#xff0c;它们提供有关元素的更多细节或定义其行为的方式。属性通常被包含在开始标签中&#xff0c;并使用关键字“键值对”的形式表示。 下面是几个示例以说明XML属性的使用&#xff1a; HTML元素的属性&#xff1a; <p id"paragraph…

邂逅Linux--常见指令,万物为文件(一)

引子&#xff1a;在之前&#xff0c;我们经常听到Linux&#xff0c;那什么是Linux呢&#xff1f;Linux是一种免费使用和自由传播的类UNIX操作系统&#xff0c;其内核由林纳斯本纳第克特托瓦兹&#xff08;Linus Benedict Torvalds&#xff09;于1991年10月5日首次发布&#xff…

力扣每日一题-统计已测试设备-2024.5.10

力扣题目&#xff1a;统计已测试设备 题目链接: 2960.统计已测试设备 题目描述 代码思路 根据题目内容&#xff0c;第一感是根据题目模拟整个过程&#xff0c;在每一步中修改所有设备的电量百分比。但稍加思索&#xff0c;发现可以利用已测试设备的数量作为需要减少的设备电…

Spring底层入门(十)

1、内嵌tomcat boot框架是默认内嵌tomcat的&#xff0c;不需要手动安装和配置外部的 Servlet 容器。 简单的介绍一下tomcat服务器的构成&#xff1a; Catalina&#xff1a; Catalina 是 Tomcat 的核心组件&#xff0c;负责处理 HTTP 请求、响应以及管理 Servlet 生命周期。它包…

Vitis HLS 学习笔记--理解串流Stream(1)

目录 1. 介绍 2. 示例 2.1 代码解析 2.2 串流数据类型 2.3 综合报告 3. 总结 1. 介绍 在Vitis HLS中&#xff0c;hls::stream是一个用于在C/C中进行高级合成的关键数据结构。它类似于C标准库中的std::stream&#xff0c;但是专门设计用于硬件描述语言&#xff08;如Veri…

基于springboot实现贸易行业crm系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现贸易行业crm系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了基于springboot的贸易行业crm系统的开发全过程。通过分析基于springboot的贸易行业crm系统管理的不足&#xff0c;创建…

【栈】Leetcode 字符串解码

题目讲解 394. 字符串解码 算法讲解 这道题有四种情况&#xff1a;1.遍历的时候遇到数字&#xff0c;我们计算并保存数字&#xff0c;将它加入到数字栈中&#xff1b;2.遍历的时候遇到[&#xff0c;我们就把字符保存&#xff0c;加入到字符栈中&#xff1b;3.当遇到]&#x…

如何远程控制另一部手机:远程控制使用方法

在现今高科技的社会中&#xff0c;远程控制手机的需求在某些情境下变得越来越重要。不论是为了协助远在他乡的家人解决问题&#xff0c;还是为了确保孩子的在线安全&#xff0c;了解如何实现这一功能都是有益的。本文将为您简要介绍几种远程控制手机的方法及其使用要点。 KKVi…

探索前端技术的未来:新兴工具与框架的引领

随着互联网的迅速发展&#xff0c;前端技术也在不断演进。作为前端开发者&#xff0c;我们时刻都要保持对新兴工具和框架的关注&#xff0c;以便跟上技术的脚步&#xff0c;同时也为自己的职业发展做好准备。在这篇文章中&#xff0c;我们将探索前端技术的未来趋势&#xff0c;…

交直流充电桩检测有哪些实验项目

交直流充电桩检测是为了保证充电桩的正常运行和使用安全&#xff0c;对充电桩的各项性能进行检测的过程。 1. 充电功能检测&#xff1a;检测充电桩的充电功能是否正常&#xff0c;包括充电电流、电压、功率等参数的测量和调整&#xff0c;以及充电过程中的故障诊断和处理。 2.…

Vue.js中使用JavaScript实现路由跳转详解

在Vue应用中&#xff0c;利用Vue Router进行页面间的导航是一个常见需求。本篇博客将通过示例代码详细介绍如何在Vue组件中使用JavaScript实现路由跳转&#xff0c;包括传递参数的两种方式&#xff1a;通过params和query。让我们一步步深入了解。 基础设置 首先&#xff0c;确…

Python图形界面(GUI)Tkinter笔记(目录)

【1】Python图形界面(GUI)Tkinter笔记&#xff08;一&#xff09;&#xff1a;根窗口的创建 【2】Python图形界面(GUI)Tkinter笔记&#xff08;二&#xff09;&#xff1a;标签Label的基本应用 【3】Python图形界面(GUI)Tkinter笔记&#xff08;三&#xff09;&#xff1a;控…

2024年4月24日华为春招实习试题【三题】-题目+题解+在线评测,2024.4.24,华为机试

2024年4月24日华为春招实习试题【三题】-题目题解在线评测&#xff0c;2024.4.24&#xff0c;华为机试 &#x1f3e9;题目一描述&#xff1a;输入格式输出格式样例1样例2样例3数据范围解题思路一&#xff1a;dfs解题思路二&#xff1a;直接二分查找哇&#xff01;解题思路三&am…

队列:动物收养所

问题 题目描述 有家动物收容所只收留猫和狗&#xff0c;但有特殊的收养规则。收养人有两种收养方式:第一种为直接收养所有动物中最早进入收容所的。第二种为选择收养的动物类型(猫或狗)&#xff0c;并收养该种动物中最早进入收容所的。给定一个操作序列代表所有事件。 若第一个…

实验室一块GPU都没有?这个云平台直接送4090免费无门槛代金券!

你有没有一些年代久远的老照片&#xff0c;或是网络下载的图片和视频&#xff0c;低分辨率、模糊还有噪点&#xff0c;如果能一键修复成高清就好了&#xff01;现在在AI算法工程师圈子里很火的GpuMall智算云&#xff0c;上面的镜像可以一键帮你修复照片&#xff01;比如我们用R…

【碳化硅】陷阱(traps)对SiC MOSFET阈值电压漂移的影响

这篇文章是关于硅碳化物(SiC)金属氧化物半导体场效应晶体管(MOSFET)的阈值电压漂移问题的研究。文章的主要目的是通过研究不同的陷阱(traps)对阈值电压漂移的影响,来解决SiC MOSFET的可靠性问题。 摘要(Abstract) 文章提出了一种研究方法,用于分析影响SiC MOSFET阈值…

LabVIEW学习记录4-局部变量、全局变量、共享变量

【LabVIEW】局部变量、全局变量、共享变量 一、变量定义二、内存分配三、竞争状态四、变量创建及简单使用示例4.1 局部变量4.1.1 局部变量的创建4.1.2 局部变量的编程实例 4.2 全局变量4.2.1 创建4.2.2 调用4.2.3 编程实例 4.3 共享变量 一、变量定义 LabVIEW&#xff08;Labor…

【Web后端】servlet基本概念

1.ServletAPI架构 HttpServlet继承GenericServletGenericServlet实现了Servlet接口&#xff0c;ServletConfig接口,Serializable接口自定义Servlet继承HttpServlet 2.Servlet生命周期 第一步&#xff1a;容器加载Servlet第二步&#xff1a;调用Servlet的无参构造方法&#xf…