目录
2021 年 7 月 13 日晚上 22:52 ,B 站崩了。整个事件的罪魁祸首竟然只是,这么短短 的几行代码;
回到 B 站崩溃那天 ,仅不到半个小时 ,这个消息就冲上了微博的热搜头条。
从 B 站出来的用户甚至带崩了 A 站、豆瓣、知乎等多个网站。
有网友调侃说, ?B 站服务器一蹦 ,紧张加班的除了 B 站的程序员 ,同时让 A 站知乎、豆瓣、微博的程序员默默打开了电脑。
B 站崩溃的背后 ,背后的根本原因到底是什么呢?
时隔一年以后, ?B 站对外公布了导致这个问题的底层原因 ,实际上这个问题并不复杂,但是为了让大家彻底搞懂这个问题 ,我们先来了解一下 B 站的公网架构 ?(如图) ?。 ? ??
? ? 1、CDN 是内容分发网络的一个简称 ,它提供了地域的就近访问功能 ,为用户获取服务器信息提供了加速的功能。
? ? 2、lvs 是一个四层负载均衡器,也就是基于 ip+端口的负载,为 OpenResty 提供高可用集群。
? ? 3、OpenResty ,是一个基于 Nginx+Lua 的高性能 Web 平台 ,简单来说,就是我们可以直接使用 Lua 脚本来扩展 Nginx 的能力 ,从而构建动态的 Web 应用。?
? ? 4、最后 ,使用了多机房部署实现异地多活的架构保证高可用性。
当用户发起请求后 ,经过 CDN 分发到业务主机房 ,然后通过 LVS 四层负载路由 OpenResty 服务器上,最后再转发到对应的应用服务器实例获取相关数据并返回。
针对这样的一种架构, ?(如图) 在 B 站崩溃的时候,运维人员采取了一些常规的措施去 定位和解决问题。
? ? 1、梳理整个请求链路,查看存在异常的服务器节点,SLB 运维人员发现七层负载服务器的 CPU 达到 100%,于是采取了重新加载以及冷重启 SLB 的方式都没有解决这个问题。
? ? 2、接着发现多活机房在 CPU 使用率正常的情况下 ,SLB 存在大量超时请求 ,于是重启多活机房 SLB,恢复了部分业务的使用。
大家发现没有 ,遇到生产事故的时候 ,在不清楚具体问题的情况下,优先重启相关服务节点来达到故障止损是效率最高的手段,因此 B 站的运维人员通过重启 SLB 以及多活节点后。
使得多活机房恢复正常后部分业务可以正常访问。
但是业务主机房还没有恢复 ,这个时候 ,就需要慢慢去排查了。
于是运维人员使用了 Linux 提供的 Perf 系统分析工具,定位到主机房 SLB 服务器的 CPU 热点集中在一个 Lua 函数上。
于是 ,也采取了常规的解决思路- 版本回滚。
一般一个问题的出现 ,在宏观层面没有太多变化的情况下,很有可能是因为最近发布了新版本导致的。
从 B 站的问题复盘来看 ,回滚并没有解决问题 ,最后是通过重新构建新的 SLB 集群解 决的。
整个解决过程耗时 3 小时 ,对于互联网公司来说 ,这是一个非常大的故障。
虽然问题解决了,但是这个问题的根源以及让谁来背这个锅,还没搞清楚,所以需要继续分析原因。
经过一段时间的排查发现,CPU 跑满的原因是 OpenResty 里面的一个 lua 函数导致的(如图) ?。
这个函数的作用是从注册中心同步服务注册地址以及该服务节点的访问权重保存到Nginx 的共享内存里面。
然后使用 lua-resty-balancer 模块对服务地址进行动态路由。
其中 ,在进行目标服务器的动态选择的时候 ,用到了加权轮询算法,并使用了下面 ?(如图) ?这个方法计算所有实例权重的最大公约数。
这个方法本身没有问题 ,但是当节点的权重 weight=“0”的时候,_gcd 函数收到的 入参 b 可能是字符串“0”。
而 Lua 又是弱类型语言 ,允许传入字符串“0”,这个时候 if 条件字符串 0 不等于数字 0 ,会执行_gcd 递归调用 ,其中在执行 a%b 的时候 ,用字符串和数字取模,得到一个 NaN 的结果。
于是再次执行的时候 ,就变成了_gcd(NaN, ?NaN)的递归调用导致死循环问题。
可能大家会有疑惑 ,为什么回滚代码没有解决这个问题。
官方的声明说了,权重这个功能是 2 个月之前上线的,也就是这个问题的潜在风险存在 了 2 个月。
在某种发布模式下,应用实例的权重会短暂调整为 0,导致注册中心返回给 SLB 的权重 是一个字符串的“0”。
这个问题之所以一直没暴露出来 ,是因为这种发布模式的使用频率极低。
一个影响生产环境 3 个小时,造成巨大影响和损失的生成事故,竟然是一个数据类型导 致的当得到这个答案的时候,大家可能会觉得难以接受,这就是千里之堤毁于蚁穴的真实写 照啊。
在这个事故发生后 ,公司内部必然要做的几件事情
? ? 1、出一份详细的事故报告 ,明确事故的责任人和事故的级别
? ? 2、针对事故进行复盘
? ? 3、从技术层面、以及管理层面提出优化和改进的措施 ,避免后续再出现类似问题。 总的来说 ,越是偏向底层的开发 ,对于技术能力的要求以及工作的严谨性就越高。
通过 B 站的这次案例,屏幕前的你们也可以学习一些经验,从容应对未来具有挑战的工作。
?