当前位置: 首页 > 科技观察

月均活跃用户达1.3亿,B站高可用架构实践

时间:2023-03-21 13:10:29 科技观察

平均月活跃用户达到1.3亿。在流量洪峰下实现B站的高可用架构是一个挑战。本文阐述了GoogleSRE的系统方法论和实际业务从响应过程出发,进行了一些系统的易用性设计。这将进一步帮助我们了解系统的整体情况和上下游联防。本文来自公众号云加社区(ID:QcloudCommunity)负载均衡负载均衡分为两个方向,一个是前端负载均衡,一个是数据中心内部负载均衡。在前端负载均衡方面,一般来说,用户流量访问级别主要是基于DNS,希望尽量减少用户请求的延迟。用户流量优化分布在多条网络链路、多数据中心、多服务器上,通过动态CDN方案实现最小延迟。以上图为例。用户流量首先会流入BFE的前端接入层。第一层的BFE实际上起到了路由器的作用,选择一个尽可能靠近接入节点的机房来加速用户请求。然后通过API网关转发到下游的服务层,可能是内部的一些微服务或者业务聚合层等,最终形成一个完整的流量格局。基于此,前端服务器的负载均衡主要考虑几个逻辑:尽量选择距离最近的节点,根据带宽策略调度选择API进入机房,根据可用服务容量均衡流量,最忙和最不忙节点消耗的CPU差异很小。但是如果负载均衡没做好,情况可能会像上图左边那样。这可能导致资源调度和编排困难,容器资源无法合理分配。因此,数据中心内部负载均衡主要考虑:均衡流量分配,可靠识别异常节点横向扩展,增加同构节点扩容,减少错误,提高可用性。之前我们发现内网业务在通过同构节点扩容时有CPU占用。过高的异常。通过排查,发现后面的RPC点对点通信之间的HealthCheck开销太大,导致了一些问题。另一方面,如果底层服务只有单套集群,发生抖动时故障面会比较大,需要引入多个集群来解决问题。通过实现Client到Backend的子集连接,我们可以将backend平均分配给clients,同时处理节点变化,持续平衡连接,避免大的变化。在多集群的情况下,需要考虑集群迁移的运维成本,集群之间的业务数据存在小的交集。回到繁忙或空闲时CPU占用率过高的问题,我们会发现这与背后的负载均衡算法有关。第一个问题:对于每一个QPS,其实每一次查询,每一次查询,每一次API请求,它们的成本都是不一样的。节点之间的差异非常大。即使做了均衡的流量分配,从负载的角度来看,其实也是不均衡的。第二个问题:物理机环境有差异。因为我们一般每年都会采购服务器,新采购的服务器通常CPU频率都比较高,所以服务器很难在本质上做到强同质化。基于此,参考JSQ(mostidletraining)负载均衡算法带来的问题,发现缺少的是服务器的全局视图,所以我们的目标需要综合考虑负载和可用性。我们参考《The power of two choices in randomized load balancing》的思想,使用choice-of-2算法,随机选择两个节点打分,选择一个比较好的节点:选择Backend:CPU,client:health,inflight,latency作为指标,以及使用简单的线性方程进行评分。对新启动的节点使用一个恒定的惩罚值(penalty),并使用probe方法来最小化负载量来预热。得分相对较低的节点可以避免进入“永久黑名单”而无法恢复,采用统计衰减的方法逐渐将节点指标恢复到初始状态(即默认值)。经过负载均衡算法的优化,我们取得了比较好的回报。限制电流以避免过载是负载平衡的一个重要目标。随着压力的增加,无论负载均衡策略多么有效,系统的某些部分总是会过载。我们优先考虑优雅降级、返回低质量结果和提供有损服务。在最坏的情况下,使用适当的节流来确保服务本身的稳定性。对于限流,我们认为主要集中在以下几点:QPS的限制带来了不同的请求成本和静态阈值的难以配置。根据API的重要性,按照优先级丢弃。为每个用户设置限制。当发生全局过载时,控制某些“异常”是很关键的。拒绝请求也是有代价的。每个服务都配置了限流带来的运维成本。在限流策略上,我们首先采用分布式限流。我们实现了一个quota-server来控制每个Client的Backend,即Backend需要向quota-server请求获取Quota。这样做的好处是可以减少请求服务器的频率,获取后直接在本地消费。在算法层面,采用最大和最小公平算法来解决大消费者带来的饥饿感。在客户端,当用户超过资源配额时,后端任务会迅速拒绝请求并返回“配额不足”的错误。有可能后端忙于不断发送拒绝请求,导致依赖资源过载和大量错误。在下游保护的两种情况下,我们选择直接在客户端进行流量,而不是将流量发送到网络层。我们在GoogleSRE中学到了一个有趣的公式,max(0,(requests-K*accepts)/(requests+1))。通过这个公式,我们可以让客户端直接发送请求,一旦超过限制,就会按照概率拦截流量。在过载保护方面,核心思想是在服务过载时丢弃一定量的流量,保证系统接近过载时的峰值流量,达到自我保护的目的。常见做法包括根据CPU和内存使用情况丢弃流量;使用队列进行管理;可控延迟算法:CoDel等。简单来说,当我们的CPU达到80%时,此时就可以认为接近过载了。如果此时的吞吐量达到100,请求的瞬时值为110,我可以丢掉这10个流量。在这种情况下,服务可以保护自己。基于这种思路,我们最终实现了一种过载保护算法。我们使用CPU的滑动平均值(CPU>800)作为启发式阈值,一旦触发,将进入过载保护阶段。算法为:(MaxPass*AvgRT)800),是否继续进入过载保护。重试流量的方向一般是从BFE到LB(负载均衡),然后通过API网关到BFF、微服务,最后到数据库。这个过程要经过很多层。在日常工作中,当请求返回错误,部分Backend节点过载时,我们应该怎么办?首先,我们需要限制重试次数和基于重试分布的策略。其次,我们应该只在失败层重试。当重试还是失败时,我们需要全局约定错误码,避免级联重试。此外,我们需要使用随机的、呈指数增长的富集周期,请参阅此处的指数退避和抖动。最后,我们需要设置重试率指标以进行故障排除。在客户端,您需要限制速度。由于用户总是会频繁尝试访问一个不可达的服务,所以客户端需要限制请求的频率,可以通过接口层面的error_details附加到各个API返回的response中。超时我们之前说过,大部分的失败都是由于超时控制不合理造成的。首当其冲的就是高并发下的高延迟服务,导致客户端堆积,线程阻塞。此时上行流量不断涌入,最终导致故障。所以,从本质上理解timeout其实就是一种FailFast策略,就是让我们的请求尽可能多的去消费,像这种堆积起来的请求,基本都是丢弃或者消费。另一方面,当上游超时已经返回给用户时,下游可能还在执行,这会造成资源浪费。还有一个问题就是,我们在调下游服务的时候,怎么配置超时,怎么设置默认策略?在生产环境中,经常会因为手抖或者配置错误导致配置失败和失败。所以我们最好在框架层面做一些防御性的编程,尽可能的保持在一个合理的范围内。流程中超时控制的关键是在每个阶段(网络请求)开始前检查是否有足够的剩余来处理请求。另外,这个过程中可能会有一些逻辑计算。我们通常认为这种时间比较少,所以一般不去控制。现在很多RPC框架都在做跨进程的超时控制,为什么要这么做呢?跨进程的超时控制也可以参考进程中的超时控制思路,将RPC的源数据传递给下游服务,然后使用配额继续传输,让上下游环节不超过一秒。处理级联故障结合我们上面提到的四个方面,处理级联故障,我们有以下几个要点需要考虑。首先,我们需要尽可能避免超载。因为如果节点一个一个挂掉,最终服务会雪崩,集群也有可能宕机,所以我们提到了自我保护。其次,我们使用一些手段来限制电流。可以让某个Client在有大流量并发请求时控制服务,使服务不易挂掉。另外,当我们无法正常服务时,我们也可以提供有损服务,牺牲一些非核心服务来保证关键服务,实现优雅降级。第三,在重试策略上,在微服务中尽可能的回退,尽量兼顾重试放大流量倍数对下游的影响。此外,我们还需要考虑到移动端用户在无法使用某项功能时,通常会频繁刷新页面,由此带来的流量影响,我们也需要配合移动端做流量控制。第四,超时控制强调两点,进程内超时和跨进程传递。最后,它的超时链路由顶层的一个节点决定。只要做到这一点,我认为大概率不会出现连锁故障。第五,变革管理。我们的发布通常是一些变更引起的,所以我们还是要加强变更管理,对变更过程中出现的破坏性行为进行惩罚。注意力。六是极限压力测试和故障演练。在做压力测试的时候,可能会报错就停止。我建议即使报错也最好继续加压,看看你的服务表现如何?能否在过载情况下提供服务?装上过载保护算法后,继续加压,主动剔除,结合熔断,可以产生立体的保护效果。频繁的故障演练可以产生人人都能学习的质量控制手册。经常演练不会引起恐慌,生产环境出现问题也能迅速解决。第七,考虑扩容、重启和消除有害流量。上图所示的参考是对上述策略的经典补充,是解决各种服务问题的玄学。作者:毛健简介:bilibili技术总监,腾讯云最有价值专家(TVP)。负责bilibili数据平台部,近十年服务端研发经验。擅长高性能、高可用服务器开发,熟悉Go、Java、C等语言。参与B站,从单体架构到微服务的全面转型,包括微服务治理、微服务可用性设计、微服务数据一致性设计、微服务中间件、微服务监控、微服务日志采集、微服务负载均衡、微服务RPC框架开发等。更多开源行业有影响力的项目:https://github.com/Terry-Mao/goim,分布式IM长连接广播服务;https://github.com/Terry-Mao/bfs,分布式小文件存储。编辑:陶家龙来源:转载自微信公众号云家社区(ID:QcloudCommunity),本文由B站技术总监毛健先生分享整理于“云家社区沙龙在线”。