B 站高可用架构实践

VSole2022-05-05 22:07:44

负载均衡

BFE 就是指边缘节点,BFE 选择下游 IDC 的逻辑权衡:

  • 离 BFE 节点比较近的
  • 基于带宽的调度策略
  • 某个 IDC 的流量已经过载,选择另外一个 IDC

当流量走到某个 IDC 时,这个流量应该如何进行负载均衡?

问题:RPC 定时发送的 ping-pong,也即 healthcheck,占用资源也非常多。服务 A 需要与账号服务维持长连接发送 ping-pong,服务 B 也需要维持长连接发送 ping-pong。这个服务越底层,一般依赖和引用这个服务的资源就越多,一旦有任何抖动,那么产生的这个故障面是很大的。那么应该如何解决?

解决:以前是一个 client 跟所有的 backend 建立连接,做负载均衡。现在引入一个新的算法,子集选择算法,一个 client 跟一小部分的 backend 建立连接。图片中示例的算法,是从《Site Reliability Engineering》这本书里看的。

如何规避单集群抖动带来的问题?多集群。

如上述图片所示,如果采用的是 JSQ 负载均衡算法,那么对于 LBA 它一定是选择 Server Y 这个节点。但如果站在全局的视角来看,就肯定不会选择 Server Y 了,因此这个算法缺乏一个全局的视角。

如果微服务采用的是 Java 语言开发,当它处于 GC 或者 FullGC 的时候,这个时候发一个请求过去,那么它的 latency 肯定会变得非常高,可能会产生过载。

新启动的节点,JVM 会做 JIT,每次新启动都会抖动一波,那么就需要考虑如何对这个节点做预热?

如上图所示,采用 “the choice-of-2” 算法后,各个机器的 CPU 负载趋向于收敛,即各个机器的 CPU 负载都差不多。Client 如何拿到后台的 Backend 的各项负载?是采用 Middleware 从 Rpc 的 Response 里面获取的,有很多 RPC 也支持获取元数据信息等。

还有就是 JVM 在启动的时候做 JIT,以前的预热做法:手动触发预热代码,然后再引入流量,再进行服务发现注册等,不是非常通用。通过改进负载均衡算法,引入惩罚值的方式,慢慢放入流量进行预热。

限流

用 QPS 限制的陷阱:

  • 不同的参数,请求的数据量是不同的,对一个进程的一个吞吐是有影响的。
  • 业务是经常迭代的,配一个静态的阈值,这个非常困难。能否按照每一个服务用多少个 CPU 来做限流?

每一个 API 都是有重要性的:非常重要、次重要,这样配置限流、做过载保护的时候,可以使用不同的阈值。

每个服务都要配一个限流,是非常烦人的,需要压测,是不是可以自适应去限流

每个 Client 如何知道自己这一次需要申请多少 Quota ?基于历史数据窗口的 QPS。

节点与节点之间是有差异的,分配算法不够好,会导致某些节点产生饥饿。那么可以采用最大最小公平算法,尽可能地比较公平地去分配资源,来解决这个问题。

当量再大一点的时候,如果 Backend 一直忙着拒绝请求,比如发送 503,那么它还是会挂掉。这种情况就要考虑从 Client 去截流。此处,又提到了 Google 《Site Reliability Engineering》这本书里面的一个算法,即 Client 是按照一定概率去截流。那么这个概率怎么计算?一个是总请求量:requests,一个是成功的请求量:accepts。如果服务报错率比较高,意味着 accepts 不怎么增长,requests 一直增长,最终这个公式求极限,它会等于 1,所以它的丢弃概率是非常高的。基于这么一个简单的公式,不需要依赖什么 ZooKeeper,什么协调器之类的,就可以得到一个概率丢弃一些请求。它尽可能的在服务不挂掉的情况下,放更多的流量进去,而不是像 Netflix 一样全部拒掉。

连锁故障通常都是某一个节点过载了挂掉,流量又会去剩下的 n - 1 个节点,又扛不住,又挂掉,所以最终一个一个挨着雪崩。所以过载保护的目的是为了自保。

B 站参考了阿里的 Sentinel 框架、Netflix 的一些文章等,最终采用的是类似于 TCP BBR 探测的思路和算法。简单说:当 CPU 达到 80% 的时候,这个时候我们认为流量过载,如果此时吞吐量比如 100,用它作为阈值,瞬时值的请求比如是 110,那就可以丢掉 10 个流量。这样就可以实现一个限流算法。

CPU 抖来抖去,使用 CPU 滑动均值(绿色线)可以跳动的没有这么厉害。这个 CPU 针对不同接口的优先级,例如低优先级 80% 触发,高优先级 90% 触发,可以定为一个阈值。

那么吞吐如何计算?利特尔法则。当前的 QPS * 延迟 = 吞吐,可以用过去的一个窗口作为指标。一旦丢弃流量,CPU 立马下来,算法抖动非常厉害。图二右侧黄色线表示抖动非常高,绿色线表示放行的流量也是抖动非常高,所以又加了冷却时间,比如持续几秒钟,再重新判断。

重试

  • BFE: 动态 CDN
  • SLB: LVS + Nginx 实现,四七层负载均衡
  • BFF: 业务逻辑组装、编排

问题:每一层都重试,这一层 3 次,那一层 3 次,会指数级的放大。解决:只在失败这一层重试,如果重试之后失败,请返回一个全局约定好的错误码,比如说:过载,无需重试,发现这个错误码,通通放行,避免级联重试。

重试都应该无脑的重试三次吗?API 级别的重试需要考虑集群的过载情况。是不是可以约定一个重试比例呢?比如只允许 10% 的流量进行重试,Client 端做统计,当发现有 10% 都是重试,那么剩下的都拒绝掉。这样最多产生 1.1 倍的放大,重试 3 次,极端情况下,会产生 3 倍放大。还有在重试的时候,尽量引入随机、指数递增的一个重试周期,大家不要都重试 1 秒钟,有可能会堆砌一个重试的波峰

重试的统计图和记录 QPS 的图分开。问题诊断的时候,可以知道它是来自流量重试导致的问题放大。

某个服务不可用的时候,用户总是会猛点,那么这个时候,需要去限制它的频次,一个短周期内不允许发重复请求。这种策略,有可能会根据不同的过载情况经常调这种策略,那么可以挂载到每一个 API 里面。

超时

大部分的故障都是因为超时控制不合理导致的。

  • 某个高延迟服务可能会导致 Client 堆积,Client 线程会阻塞,上游流量不断进来,下游的消费速度跟不上上游的流入速度,进程会堆积越来越多请求,可能会 OOM。
  • 超时的策略本质是就是为了丢弃或者消耗掉请求。
  • 下游 2 秒返回,上游配置了 1 秒,上游超时已经返回给用户,下游还在执行,浪费资源。

某个服务需要在 1 秒返回,内部可能需要访问 Redis,需要访问 RPC,需要访问数据库,时间加起来就超过 1 秒,那么访问完每一层,应该计算供下一层使用的超时时间还剩多少可用。在 go 语言里,可能会使用 Context,每一个网络请求开始的阶段,都要根据配置文件配置的超时时间,和当前剩余多少,取一个最小值,最终整个超时时间不会超过 1 秒。

通过 RPC 的元数据传递,类似 HTTP 的 request header,带给其它服务。例如在图中,就是把 700ms 这个配额传递给 Service B。

下游服务作为服务提供者,在他的 RPC.IDL 文件中把自己的超时要配上,那么用 IDL 文件的时候,就知道是 200 ms,不用去问。

应对连锁故障

优雅降级:一开始千人千面,后来只返回热门的

QA

  • Q: 请问负载均衡依据的 metric 是什么?
  • A: 服务端主要用 CPU,客户端用的是健康度,指连接的成功率,延迟也很重要,每个 Client 往不同的 Backend 发了多少个请求,四个指标归一,写一个线性方程,进行打分。

  • Q: BFE 到 SLB 走公网还是专线?
  • A: 既有公网,又有专线。

  • Q: Client 几千量级,每 10 秒 ping-pong 一下,会不会造成蛮高的 CPU?
  • A: 如果 Backend 很多的话,那么这个的确会造成。

  • Q: 多集群切换是否有阻塞的点?
  • A: 一个 Client 连接到各个集群,subset 算法,每个集群都有 Cache

  • Q: 负载均衡的探针是怎么做的?
  • A: 惩罚值,比如 5 秒,慢慢放流量

  • Q: Quota-Server 限流有开源实现吗?
  • A: 目前看到的都是针对单节点的。

  • Q: 客户端统计是否有点太多?
  • A: 可以做到 Sidecar、Service Mesh 里面

  • Q: 超时传递是不是太严格?
  • A: 有些情况下即便超时也要运行,可以通过 RPC Context 管控

  • Q: 每个 RPC 都获取 CPU 会不会很昂贵?
  • A: 后台开启线程定时计算 CPU 平滑均值

  • Q: 线上压测和测试环境压测 CPU 不一致
  • A: RPC 路由加影子库

  • Q: CC 攻击
  • A: 边缘节点或者核心机房都有防止 CC 攻击的一些手段,只要不是分布式搞你,都能找到流量特征进行管控
转自:
kunzhao.org/docs/cloud-plus-bbs/bilibili-high-availability/
负载均衡流量
本作品采用《CC 协议》,转载必须注明作者和本文链接
用户名:加密密码:密码最后一次修改日期:两次密码的修改时间间隔:密码有效期:密码修改到期到的警告天数:密码过期之后的宽限天数:账号失效时间:保留。查看下pid所对应的进程文件路径,
ELB 弹性负载均衡(Elastic Load Balance,简称ELB)是将访问流量根据分配策略分发到后端多台服务器的流量分发控制服务。弹性负载均衡可以通过流量分发扩展应用系统对外的服务能力,同时通过消除单点故障提升应用系统的可用性。 01信息搜集 查询IP地址组列表
导语近日,由广东省信息技术应用创新产业联盟组织的“2023 年广东省信息技术应用创新成果交流会”在广州顺利召开。 Coremail作为会员单位受邀出席此次交流会。会上,Coremail荣获优秀产品和解决方案奖项,CACTER邮件安全网关获评“2022年广东省信息技术应用创新优秀产品和解决方案”。本次大会以“筑牢自主技术底座,推动行业创新发展”为主题,邀请省政数局、省工信厅、省委网信办、省
腾讯安全威胁情报中心推出2023年10月份必修安全漏洞清单
数字经济发展速度之快、辐射范围之广、影响程度之深前所未有,正在成为重组全球要素资源、重塑全球经济结构、改变全球竞争格局的关键力量。10月18日,中共中央政治局就推动我国数字经济健康发展进行第三十四次集体学习,习近平总书记强调,要加快新型基础设施建设,加强战略布局,加快建设高速泛在、天地一体、云网融合、智能敏捷、绿色低碳、安全可控的智能化综合性数字信息基础设施,打通经济社会发展的信息“大动脉”。
VMware公司近日对其独立的负载均衡器进行了升级,并将其与NSX-T虚拟网络以及用于私有数据中心和公共云的安全软件集成。他正在进行两个项目涉及VMware虚拟网络技术。VMware公司将继续支持使用NSX-T中的负载均衡功能的客户。否则,企业必须为未使用的服务器容量付费,以应对流量高峰。在此之前,该产品会存在配置错误,并将其应用于所有应用程序服务器。新产品将仅在主服务器中安装配置更改。
NAT模式支持对IP地址和端口进行转换。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。
0x00 介绍工具介绍RedGuard,是一款C2设施前置流量控制技术的衍生作品,有着更加轻量的设计、高效的流量交互、以及使用go语言开发具有的可靠兼容性。它所解决的核心问题也是在面对日益复杂的红蓝攻防演练行动中,给予攻击队更加优秀的C2基础设施隐匿方案,赋予C2设施的交互流量流量控制功能,拦截那些“恶意”的分析流量,更好的完成整个攻击任务。RedGuard是一个C2设施前置流量控制工具,可以避免Blue Team,AVS,EDR,Cyberspace Search Engine的检查。
0x00 介绍工具介绍RedGuard,是一款C2设施前置流量控制技术的衍生作品,有着更加轻量的设计、高效的流量交互、以及使用go语言开发具有的可靠兼容性。它所解决的核心问题也是在面对日益复杂的红蓝攻防演练行动中,给予攻击队更加优秀的C2基础设施隐匿方案,赋予C2设施的交互流量流量控制功能,拦截那些“恶意”的分析流量,更好的完成整个攻击任务。RedGuard是一个C2设施前置流量控制工具,可以避免Blue Team,AVS,EDR,Cyberspace Search Engine的检查。
随着金融科技的进步和金融业务的发展,网络规模和网络流量都有飞速的增长,网络运维和网络安全保障的复杂度与难度也日益提高。尤其在网络流量管理和应用方面,如何实现全网流量的平台化输入输出管理、如何实现流量的灵活分配和处理、如何采用较新技术实现流量的业务性能可视化和安全态势可视化,都是非常值得研究和实践的内容。本文结合工作实际,对以上内容进行分析研究,并介绍相关实践。
VSole
网络安全专家