【】月均活跃用户达1.3亿,B站高可用架构实践( 二 )


我们参考了《The power of two choices in randomized load balancing》的思路 , 使用 the choice-of-2 算法 , 随机选取的两个节点进行打分 , 选择更优的节点:

  • 选择 Backend:CPU , client:health、inflight、latency 作为指标 , 使用一个简单的线性方程进行打分 。
  • 对新启动的节点使用常量惩罚值(penalty) , 以及使用探针方式最小化放量 , 进行预热 。
  • 打分比较低的节点 , 避免进入“永久黑名单”而无法恢复 , 使用统计衰减的方式 , 让节点指标逐渐恢复到初始状态(即默认值) 。
通过优化负载均衡算法以后 , 我们做到了比较好的收益 。
限流
避免过载 , 是负载均衡的一个重要目标 。 随着压力增加 , 无论负载均衡策略如何高效 , 系统某个部分总会过载 。
我们优先考虑优雅降级 , 返回低质量的结果 , 提供有损服务 。 在最差的情况 , 妥善的限流来保证服务本身稳定 。
【】月均活跃用户达1.3亿,B站高可用架构实践
本文插图

限流这块 , 我们认为主要关注以下几点:
  • 针对 QPS 的限制 , 带来请求成本不同、静态阈值难以配置的问题 。
  • 根据 API 的重要性 , 按照优先级丢弃 。
  • 给每个用户设置限制 , 全局过载发生时候 , 针对某些“异常”进行控制非常关键 。
  • 拒绝请求也需要成本 。
  • 每个服务都配置限流带来的运维成本 。

【】月均活跃用户达1.3亿,B站高可用架构实践
本文插图

在限流策略上 , 我们首先采用的是分布式限流 。 我们通过实现一个 quota-server , 用于给 Backend 针对每个 Client 进行控制 , 即 Backend 需要请求 quota-server 获取 Quota 。
这样做的好处是减少请求 Server 的频次 , 获取完以后直接本地消费 。 算法层面使用最大最小公平算法 , 解决某个大消耗者导致的饥饿 。
【】月均活跃用户达1.3亿,B站高可用架构实践
本文插图

在客户端侧 , 当出现某个用户超过资源配额时 , 后端任务会快速拒绝请求 , 返回“配额不足”的错误 。
有可能后端忙着不停发送拒绝请求 , 导致过载和依赖的资源出现大量错误 , 处于对下游的保护两种状况 , 我们选择在 Client 侧直接进行流量 , 而不发送到网络层 。
我们在 Google SRE 里学到了一个有意思的公式 , max(0, (requests- K*accepts) / (requests + 1)) 。
通过这种公式 , 我们可以让 Client 直接发送请求 , 一旦超过限制 , 按照概率进行截流 。
【】月均活跃用户达1.3亿,B站高可用架构实践
本文插图

在过载保护方面 , 核心思路就是在服务过载时 , 丢弃一定的流量 , 保证系统临近过载时的峰值流量 , 以求自保护 。
常见的做法有基于 CPU、内存使用量来进行流量丢弃;使用队列进行管理;可控延迟算法:CoDel 等 。
简单来说 , 当我们的 CPU 达到 80% 的时候 , 这个时候可以认为它接近过载 , 如果这个时候的吞吐达到 100 , 瞬时值的请求是 110 , 我就可以丢掉这 10 个流量 。
这种情况下服务就可以进行自保护 , 我们基于这样的思路最终实现了一个过载保护的算法 。
【】月均活跃用户达1.3亿,B站高可用架构实践
本文插图

我们使用 CPU 的滑动均值(CPU>800 )作为启发阈值 , 一旦触发就进入到过载保护阶段 。
算法为:(MaxPass*AvgRT)<InFlight
限流效果生效后 , CPU 会在临界值(800)附近抖动 , 如果不使用冷却时间 , 那么一个短时间的 CPU 下降就可能导致大量请求被放行 , 严重时会打满 CPU 。


推荐阅读