万字长文告诉你,B 站是怎样崩的

手机软件开发 2024-9-10 07:59:28 7 0 来自 中国
一年之后,B 站终于把故障复盘写了出来。
我简朴看了一下,和我当初推测的缘故原由部门符合,猜对了由于某接口负载过大导致雪崩效应,但没有猜对导致负载过大的缘故原由。
很显然,这篇文章是从纯技能角度解读本次故障的。
B 站有 UP 主做了这方面的视频,但受篇幅所限,讲的还不敷过细,我积极做了补充,但终极照旧决定单独写一篇文章讲讲这件事。
如果各人对技能有肯定相识,好比你听说过微服务、负载平衡、集群、多活,而且大概知道它们的原理和作用,那么发起你去读一读 原文。不看也不要紧,后续的内容我会尽大概用平凡易懂的方式形貌。
阅读这篇文章不须要技能底子,但须要肯定的耐心,故障缘故原由有些复杂,以是文章很长。
那我们开始吧。
至暗时候

原文的内容明白起来比力困难,有许多专业词汇,我们一句一句看。
2021 年 7 月 13 日 22:52,SRE 收到大量服务和域名的接入层不可用报警,客服侧开始收到大量用户反馈 B 站无法利用,同时内部同砚也反馈 B 站无法打开,乃至 App 首页也无法打开。
SRE,全称 Site Reliability Engineer,网站可靠性工程师,很高大上的名字,着实就是负责包管网站运转正常的。
大型网站一般会有内部的体系状态看板,表现一些关键的指标,好比访问乐成率、延时、每秒访问量等。
这些指标决定了最底子的用户体验,网站能不能打开,操纵会不会很慢,会不会频繁报错。
团队会为这些指标设置报警值,当故障发生时,主动关照相干负责人。
服务,这里指的是“用户访问 B 站,看视频、看弹幕、点赞投币批评”这些操纵。
域名,着实就是网址,https://www.bilibili.com/。
既然 B 站崩了,站内的客服体系肯定也无法利用,客服应该是从别的渠道收到的反馈。
这里为什么要夸大 App 首页无法打开呢,由于现在的网页都是动态的,好比你在 B 站首页看到的保举会不停变革。
着实,网页的框架部门是稳固的,欣赏器将框架部门下载下来,然后运行一些代码,从服务器上(并不肯定是下载框架的这台服务器)获取动态的内容,好比用户登录信息,保举信息,然后将它们添补到对应位置展示出来。
而 App 中的框架部门是内置在安装包里的,如果只是下载框架的服务器(专业名词叫”网页服务器“)出了题目,App 应该不受影响,既然 App 也无法打开,分析提供动态内容的服务器也无法利用了。
当然,不扫除有些 App 内置一个欣赏器,然后直接打开网页的情况,这时网页服务器出题目也会导致 App 不可用,这种技能还挺盛行,由于它低落了开辟本钱。
基于报警内容,SRE 第一时间猜疑机房、网络、四层 LB、七层 SLB 等底子办法出现题目,告急发起语音集会,拉各团队相干职员开始告急处理处罚(为了方便明白,下述变乱处理处罚过程做了部门简化)。
机房,字面意思是存放服务器的房间,现在许多网站都利用了云盘算、有专门的云服务提供商(阿里云、腾讯云等)买好硬件,设置好网络,装好体系,把账号暗码给你,你直接登录上去,安装好须要的软件利用即可。
这种情况下,你不须要关心底子架构部门,它叫做 PaaS,Platform as a service,平台即服务。
同样的,尚有 SaaS 软件即服务,好比 B 站大会员,只须要购买之后利用即可,不须要关心它是怎样运作的。
网络,包罗服务器之间的网络,数据中央之间的网络,数据中央到用户的网络,我们反面会表明多个数据中央的作用。
四层 LB,Load Balancer,负载平衡,就是把用户的哀求分给多台服务器处理处罚,避免单台服务器负载过大。
这里的四层指的是传输层,传输层有一个叫做四元组的概念,指的是 (源 IP, 目的 IP, 端标语, 协议) 四个根本要素。
IP 可以明白为每台电脑在互联网上的地点,是独一无二的,端标语每台电脑有 65536 个,一般我们利用 80 和 443 这两个端口访问网站,协议则是互联网传输协议,对于网页访问,一般是 TCP,这是一种稳固的传输协议。
负载平衡也是运行在服务器上的步伐,根据肯定规则将用户的哀求转发给多台服务器,这个规则可以自界说,好比耽误最低、乐成率最高、负载最低等。
云服务商也有现成的负载平衡服务,可以直接购买,将哀求转发给购买的别的服务器,这算是 SaaS 了。
七层 SLB,Server Load Balancer,服务器负载平衡,和上面讲的四层 LB 根本雷同,运行在应用层,也就是网络模子中的最高层,不范围于通过四元组举行平衡,还可以通过装备范例、具体网址等举行转发。
提到底子办法,着实尚有 IaaS,Infrastructure as a Service,底子办法即服务,买服务器,连网线,但不帮你装体系。原文中的底子办法着实包罗 PaaS 和 SaaS,表述有些不准确。
初因定位

22:55 远程在家的相干同砚登岸 VPN 后,无法登岸内网鉴权体系(B 站内部体系有同一鉴权,须要先获取登录态后才可登岸其他内部体系),导致无法打开内部体系,无法实时查察监控、日志来定位题目。
现在远程工作是趋势,明白。
VPN,Virtual Private Network,捏造专用网络,这是一种技能,能在两个差别的网络间架起一座桥梁,将它们毗连起来,上大学的朋侪们大概有相识,在校外访问学校的文献库,就须要利用 VPN。
至于访问一些国外网站,那只是 VPN 的用途之一,而且在这个用途中,VPN 已经被更先辈的毗连方式代替了,这只是一个口口相传的名字,内部实现并非云云。
公司有内网,须要通过 VPN 访问,很合理,内部体系须要登录(鉴权),登录态着实就是一个凭据,同时存储在欣赏器和服务器上,相互比对来确定你的身份,和各人登录 B 站的原理是雷同的。
凭据有逾期时间,因此你重启电脑后打开 B 站不须要重新登录,但过几个月再访问就大概须要重新登录了。
无法打开内部体系,后续发现是由于获取凭据的过程中访问了一个平凡用户利用的服务,但这个服务已经挂掉了,造成登录流程卡住。
这里的监控指的是服务器的各种指标,和前面提到的状态看板差不多,只不外每个部门有本身负责范围内的看板。
日志指的是服务器的运行状态纪录,大平台会有同一的日志中央,可以举行分类查询。
22:57 在公司 Oncall 的 SRE 同砚(无需 VPN 和再次登录内网鉴权体系)发现在线业务主机房七层 SLB(基于 OpenResty 构建) CPU 100%,无法处理处罚用户哀求,其他底子办法反馈未出题目,此时已确认是接入层七层 SLB 故障,扫除 SLB 以下的业务层题目。
Oncall 指随时待命,也就是值班,焦点部门都会有值班职员处理处罚告急情况。
在公司的员工已经登录过内网体系,获取到了凭据,以是不会遇到登录流程卡住造成的题目。
在线业务,可以明白为给各人用的,它尚有一个名字叫生产情况,让用户充钱,生产出贸易代价的情况。
同样的尚有测试情况、预发布情况、开辟情况,这些都是平凡用户感知不到的,在生产情况的开辟过程中会用到。
23:07 远程在家的同砚告急接洽负责 VPN 和内网鉴权体系的同砚后,相识可通过绿色通道登录到内网体系。
这里的绿色通道应该是直接关闭了相应的权限控制本领,为了处理处罚严肃题目暂时捐躯一点点安全性,可以明白。
23:17 相干同砚通过绿色通道陆续登录到内网体系,开始帮助处理处罚题目,此时处理处罚变乱的焦点同砚(七层 SLB、四层 LB、CDN)全部到位。
CDN,Content Delivery Network,内容分发网络,也是一系列服务器,可以明白为京东在各地的堆栈,就近拿货派送,减轻焦点仓储中央的压力,加快派送速率,对应在 B 站的服务上就是减轻焦点机房压力,低落用户访问耽误。
CDN 一般只用来存储静态内容,雷同于仓储中央不会储存报纸这种强时效性、常常更新的货品。
静态内容包罗我们前面提到的网站骨架,尚有各种图片,以及热门视频,毕竟 UP 主修改视频属于小概率变乱,也有对应的办理方法,从 CDN 服务器获取内容前先扣问一下焦点折务器内容是否有更新,共同 CDN 服务器定期重新下载数据。
用户哀求的内容如果可巧能在 CDN 中找到,不须要向焦点折务器获取,叫做 CDN 掷中,反之则叫做 CDN 未掷中,CDN 服务器没有向焦点折务器哀求数据的过程叫做 CDN 回源,”回流“到数据的”源头“。
故障止损

23:20 SLB 运维分析发现在故障时流量有突发,猜疑 SLB 因流量过载不可用。因主机房 SLB 承载全部在线业务,先 Reload SLB未规复后实验拒绝用户流量冷重启 SLB,冷重启后 CPU 依然 100%,未规复。
突发流量大概会造成 SLB 服务器过载,继而不能转发用户哀求,导致它管理的服务器一并失效,这一排查思绪完全准确。
主机房 SLB 是整个服务的焦点,负责所有服务器的负载平衡,它下面尚有别的负载平衡服务器。
Reload 可以看作重启,众所周知这能办理 90% 的题目,现实上是给这个服务器发送一个信号,让它关闭负载平衡步伐重新启动。
拒绝用户流量冷重启,相称于拔掉数据中央通向用户的网线,重启之后再插上,目的是避免未完全重启的负载平衡服务被大量用户哀求再次打垮。
23:22 从用户反馈来看,多活机房服务也不可用。SLB 运维分析发现多活机房 SLB 哀求大量超时,但 CPU 未过载,准备重启多活机房 SLB 先实验止损。
多活,多个活泼机房,可以明白为多个通道一起做核酸,如果一个通道遇到了题目,只需把排队的人引导到别的通道即可。
听起来像前面提到的负载平衡,着实多活确实可以通过负载平衡实现,它是一种模式,而不是一种服务。
这里的用户反馈应该是“所有服务均不可用”,绝大多数用户并相识服务架构,无法定位到具体的故障位置,而 B 站的保举、视频观看、弹幕、底子互动等焦点业务都利用了多活,这些服务不可用分析多活也遇到了题目。
这里的多活方案叫做“热备”,尚有主从等多活方案,它们都有各自的优缺点,热备是难度较高但非常可靠的一种方案。
哀求大量超时,指的是耽误很高,由于耽误太高,服务器直接向用户返回失败信息,避免大量哀求堆积耗尽资源。
这里的现原形况是大量的 CDN 服务器由于主机房不可用而回源到多活机房,同时加上用户的不停重试,导致多活机房的 SLB 负载过大,并非此次变乱的焦点缘故原由。
23:23 此时内部群里同砚反馈主站服务已规复,观察多活机房 SLB 监控,哀求超时数量大大低落,业务乐成率规复到 50% 以上。此时做了多活的业务焦点功能根本规复正常,如 App 保举、App 播放、批评&弹幕拉取、动态、追番、影视等。非多活服务暂未规复。
这里主站服务规复是由于 CDN 回源反复超时而不再重试,加上用户重试频率随时间低落,过载的 SLB 规复正常。
反面提到的这些规复正常的服务就是 B 站的焦点业务。
23:25 - 23:55 未规复的业务暂无其他立即有效的止损预案,此时实验规复主机房的 SLB。
多活机房撑住了,情况暂时稳固下来,这时开始动手完全规复服务。
我们通过 Perf 发现 SLB CPU 热门会合在 Lua 函数上,猜疑跟最近上线的 Lua 代码有关,开始实验回滚最近上线的 Lua 代码。
Perf 指的是性能分析,可以获取到步伐对资源的利用情况,继而举行故障定位大概优化。
热门 HotPoint,是步伐斲丧资源最多的位置,一般是故障的根源大概性能瓶颈。
Lua 是一种编程语言,它的特性和 Python 相似,都属于脚本语言。
编程语言中的函数是一段代码,可以像数学中的函数一样罗致输入,返回输出,在内部举行一些数据处理处罚。
上线指摆设到生产情况供用户利用。
回滚指回到上一个版本,上线后出现题目时可以回滚两个版本间改变的代码,以此确认题目是否是变更部门引起的。
后续排查发现题目并非新版本引起,但这一操纵是准确的。
近期SLB共同安全同砚上线了自研 Lua 版本的 WAF,猜疑 CPU 热门跟此有关,实验去掉 WAF 后重启 SLB,SLB 未规复。
WAF,Web Application Firewall,网络应用防火墙,是一种安全步伐,这是一个捐躯安全性实验定位故障的操纵。
SLB 两周前优化了 Nginx 在 balance_by_lua 阶段的重试逻辑,避免哀求重试时哀求到上一次的不可用节点,此处有一个最多10次的循环逻辑,猜疑此处有性能热门,实验回滚后重启 SLB,未规复。
Nginx 是一个 Web 服务器软件,可以用于负载平衡,以高性能和高度自界说著称,而且它的源代码是公开的,根本不须要猜疑 Nginx 本身的代码,但 Nginx 中调用的别的代码大概存在题目。
balance_by_lua 应该是一个函数名,意为“通过 Lua 举行负载平衡”,这里的优化是为了进步重试的乐成率,重试上限为 10 次,工程师猜疑这里出现了死循环,大概在重试逻辑中有大量斲丧资源的操纵。
SLB 一周前上线灰度了对 HTTP2 协议的支持,实验去掉 H2 协议相干的设置并重启 SLB,未规复。
HTTP 是访问网站时利用的协议,在 TCP 的上层(TCP 是传输层协议,HTTP 是应用层协议),HTTP/2 是这个协议的第二版,带来了一些性能提拔,这个版本已经发布了很长一段时间,现在进入测试阶段是正常的,不算过于激进。
灰度全称灰度测试,是生产情况中利用的一种测试方法,将肯定比例的哀求利用新版本处理处罚,别的大部门仍利用旧版本,通过观察新版本的乐成率和性能,发现埋伏的题目,如果新版本在一段时间内运行正常,就可以“全量上线”,也就是把所有的哀求都利用新版本处理处罚。
新建源站SLB

00:00 SLB 运维实验回滚相干设置仍旧无法规复 SLB 后,决定重修一组全新的 SLB 集群,让 CDN 把故障业务公网流量调治过来,通过流量隔离观察业务可否规复。
这里的重修着实并不是给负载平衡服务器重新装体系,而是在云服务商的控制台买一组新的负载平衡服务,这也是云盘算的上风之一,可以快速举行故障修复。
CDN 负责网站静态资源的缓存,将流量调治到新的负载平衡服务上,与原有的负载平衡服务隔离开来。
00:20 SLB 新集群初始化完成,开始设置四层 LB 和公网 IP。
由于没有对完备的设置过程做过演练,这里的设置速率着实是比力慢的。
01:00 SLB 新集群初始化和测试全部完成,CDN 开始切量。SLB运维继承排查 CPU 100% 的题目,切量由业务 SRE 同砚帮助。
CDN 渐渐将用户哀求从故障服务切换到正常运行的新服务上,算是一种故障规复中的灰度测试。
别的工作职员现在的重要工作并不是排查故障,而是纪录故障服务的状态,在生产情况规复正常后再分析。
01:18 直播业务流量切换到 SLB 新集群,直播业务规复正常。
01:40 主站、电商、漫画、付出等焦点业务陆续切换到 SLB 新集群,业务规复。
01:50 此时在线业务根本全部规复。
这里各人能感知到的服务已经全部规复。
规复SLB

01:00 SLB新集群搭建完成后,在给业务切量止损的同时,SLB 运维开始继承分析 CPU 100% 的缘故原由。
01:10 - 01:27 利用 Lua 步伐分析工具跑出一份具体的火焰图数据并加以分析,发现 CPU 热门显着会合在对 lua-resty-balancer 模块的调用中,从 SLB 流量入口逻辑不绝分析到底层模块调用,发现该模块内有多个函数大概存在热门。
许多编程语言自带大概有第三方的性能分析工具。
火焰图是性能分析中常用的一种图表,可以直观表现步伐运行过程中的函数调用情况和时间斲丧。
[图片上传失败...(image-424729-1658900045359)]
横轴代表运行时间,纵轴从下到上代表调用栈,也就是步伐中调用别的函数的层级。
如果发现图中有不正常的高峰(过深的调用栈)大概山顶部门过于平缓(单函数实行耗时过长),则分析对应位置大概存在性能瓶颈。
01:28 - 01:38 选择一台 SLB 节点,在大概存在热门的函数内添加 debug 日志,并重启观察这些热门函数的实行结果。
debug 即修复 Bug,debug 日志是最具体的日志品级,纪录了大量的运行细节,便于定位故障。
热门函数可以明白为频繁利用的函数。
01:39 - 01:58 在分析 debug 日志后,发现 lua-resty-balancer 模块中的 _gcd 函数在某次实行后返回了一个预期外的值:nan,同时发现了触发诱因的条件:某个容器 IP 的 weight=0。
步伐自微观到宏观可分为以下几层:

  • 语句:一行代码,比方返回一条数据
  • 函数:一段代码,实行特定操纵,比方查询用户的点赞量并返回
  • 模块:一个文件,包含一系列函数,比方用户数据查询模块
  • 包:一个文件夹,包含一系列模块,比方用户包,包含数据查询、数据修改等模块
  • 服务:一系列包,实现一整块功能,比方互动服务
这里定位到的模块名为 lua-resty-balancer,意为 OpenResty 这个步伐中利用 Lua 语言的负载平衡器,函数名为 _gcd,意为盘算最大公约数(差别语言中的下划线有差别语义)。
NaN,Not a Number,不是数字,一种特别变量,一般在盘算无效时返回此值。
这里涉及到了一个紧张概念:容器。
现在的服务端步伐,有一个行业标准级的筹划头脑,微服务。
顾名思义,微服务就是把一个大的服务拆分成多个小服务,通过内部网络毗连起来。
比方 B 站的视频点赞,大概包含以下几个服务:

  • 网关,负责罗致用户和别的服务的哀求,并举行负载平衡
  • 计数服务,由于点赞是高频互动操纵,而且须要包管数字准确,以是须要一个单独的服务负责计数
  • 数据库,用于存储数据,为了进步性能,计数服务的数据一般存储在内存中,须要数据库将其存储到硬盘
而容器就是某个微服务的载体,是一个轻量级的捏造机,与物理服务器的情况隔离,可以在差别硬件、差别情况的服务器上运行。
每个服务可以有多个容器,容器调治引擎会负责管理它们,在某个容器出现故障时制止向其调治哀求,并根据规则重启或重新创建容器。
容器的数据是存储在外部的,不随容器的烧毁而消散,我们称容器是无状态的,也就是内部的数据并不须要恒久存储。
现在业内主流的容器引擎是 Docker,主流的容器调治引擎是 Kuberneters,简称 k8s。
k8s 是一个非常完满的容器调治办理方案,拿来一台新的服务器,只须要安装并设置好 k8s,使这台服务器到场集群,k8s 就会主动调治得当的容器到这台呆板上运行。
网络通讯与存储也可以分散到多台呆板上,集群被捏造成了理论性能无穷的单台呆板,差别装备的存储被捏造成一个或几个巨大的磁盘。
顺带一提,在容器调治时,可以设置对应的条件,如某个容器只能调治到剩余内存大于 8GB 的呆板上,k8s 会尽大概依照这些限定,以最佳方式调治容器,最大化集群性能。
某个服务举行升级时,可以一个个升级对应的容器,并按照肯定规则渐渐将用户哀求分配给新版本容器,这种用户无感知,不会造成服务制止的升级被称为平滑升级。
关于我们利用 Docker 的方式,请参照这篇文章:技能说 | Docker 怎样资助我们构建面向未来的服务。
weight 在这里代表权重,可以明白为权重越高的容器被选中处理处罚用户哀求的概率越大,这里将权重设置为 0 是想要在容器不可用期间避免被调治随处理处罚用户哀求。
01:59 - 02:06 猜疑是该 _gcd 函数触发了 JIT 编译器的某个 bug,运行堕落陷入死循环导致 SLB CPU 100%,暂时办理方案:全局关闭 JIT 编译。
JIT,Just In Time,即时编译,一种提拔步伐性能的技能。
可以简朴明白为步伐以为某一段代码常常被利用,以是主动优化了它的实行逻辑,之后利用时就能得到性能提拔。
全局关闭 JIT 编译会低落整体性能,着实这里就属于碰运气了,Lua 的代码是公开的,如果 JIT 编译器在云云简朴的一个函数上都能出现题目,早就被开辟者们修复了。
02:07 SLB 运维修改 SLB 集群的设置,关闭 JIT 编译并分批重启进程,SLB CPU 全部规复正常,可正常处理处罚哀求。同时保存了一份非常现场下的进程 core 文件,留作后续分析利用。
02:31 - 03:50 SLB 运维修改其他 SLB 集群的设置,暂时关闭 JIT 编译,规避风险。
进程 core 文件,又名内存转储文件,遇到过 Windows 蓝屏并实验分析过缘故原由的朋侪们大概听说过,它生存了堕落时内存中的一些紧张信息,是分析故障的紧张资料之一。
根因定位

11:40 在线下情况乐成复现出该 bug,同时发现 SLB 纵然关闭 JIT 编译也仍旧存在该题目。此时我们也进一步定位到此题目发生的诱因:在服务的某种特别发布模式中,会出现容器实例权重为 0 的情况。
猜对了,题目并非出现在 JIT 编译器上。
线下情况指的应该是测试情况,大概为了排查故障暂时创建的新情况,在这个情况上的操纵不影响用户的正常利用。
一般来说,k8s 作为成熟的容器调治引擎,会主动检测容器的状态,并在发生故障时停息该容器的调治、,但在这个所谓“特别发布模式”中,容器的权重被手动设置成了 0。
12:30 颠末内部讨论,我们以为该题目并未彻底办理,SLB 仍旧存在极大风险,为了避免题目的再次产生,终极决定:平台克制此发布模式;SLB 先忽略注册中央返回的权重,逼迫指定权重。
先禁用存在题目的发布模式,避免题目重新出现,同时忽略掉手动设置的权重,捐躯机动性包管安全性。
注册中央同样是微服务中的概念,它用来罗致服务的上线与下线信息,共同负载平衡器实现哀求的转发。
比方,一个容器在升级过程中会向注册中央发送这些信息:

  • 旧版本服务:哀求下线,因由于升级
  • 注册中央:操纵乐成,已制止调治哀求,请在处理处罚完现有哀求后下线
  • 旧版本服务:已处理处罚完现有哀求,开始下线
  • 新版本服务:服务已乐成启动,哀求上线,权重为 xxx
  • 注册中央:操纵乐成,开始调治哀求
13:24 发布平台克制此发布模式。
14:06 SLB 修改 Lua 代码忽略注册中央返回的权重。
14:30 SLB 在 UAT 情况发版升级,并多次验证节点权重符合预期,此题目不再产生。
15:00 - 20:00 生产所有 SLB 集群渐渐灰度并全量升级完成。
直到这里,故障诱因已经被消除。
缘故原由分析

这里原文中的内容偏技能性,不再逐句剖析。
配景

B 站在 2019 年 9 月更换了负载平衡体系,新的体系 OpenResty 支持利用 Lua 语言编写代码来扩展功能,于是 B 站本身对接了注册中央和负载平衡体系,此中注册中央是自研的。
在故障发生的两个月之前,有人提出了如许一个需求:通过变更服务在注册中央中的权重,实现负载平衡体系中服务权重的动态调解,经相干团队讨论后继承。
诱因

在一种特别发布模式中,容器权重会短暂调解为 0,这时注册中央给负载平衡体系的权重数值并非整数 0,而是字符串的 "0"。
这种发布模式只在生产情况中利用,而且利用频率极低,因此没有在测试中发现。
在 "0" 被通报给负载平衡体系时,我们的主角 _gcd 函数会罗致到字符串 "0" 作为传入参数。
根因

终于来了,上代码!
[图片上传失败...(image-4c23e6-1658900045359)]
一段很简朴的代码,我们逐行来表明。
17 行界说了一个变量,这是 Lua 语法的规定。
18 行界说了 _gcd 这个函数,它有两个参数,分别为 a 和 b。
19、20、21 行是一个条件判定,如果 b 为 0,则返回 a 的值。
23 行返回了一个函数的结果,在函数里调用自身,这种编程方式叫做递归,本身调用本身。
递归调用中的 a 参数为 b 的值,b 参数为 a 除以 b 的余数,% 是取余运算。
正常情况下,这个函数调用到肯定次数时,最内层将满足条件 a 便是 b,进而返回 a,函数逐层向上返回,终极竣事调用。
但当参数 b 为 "0" 时,情况就会酿成如许:
字符串的 "0" 和整数 0 并不相等,以是不会直接返回 a 的值。
递归调用,参数 a 为 b 的值,也就是"0",参数 b 为 a % "0"。
在 Lua 语言中,如果取余运算遇到了非数字,会实验主动转换范例,因此 b 被转换成了整数 0。
而筹划者又规定任何整数与 0 取余,结果为 NaN。
因此,递归调用就酿成了如许:_gcd(a, NaN)。
之后,函数向下调用一层,NaN 自然未便是 0,步伐依然不会返回,之后的调用就是如许的:_gcd(NaN, NaN)。
因此,这个函数会不停向内部递归,永远不会退出,也就是“死递归”。
死递归会灵敏耗尽服务器的 CPU 和内存资源。
好巧不巧,这个函数是由负载平衡体系的焦点之一 Nginx 步伐实行的,因此 Nginx 进程陷入死循环,耗尽了服务器的资源,无法处理处罚用户哀求。
之后的变乱就很清朗了,主机房 SLB 因此过载,CDN 回源与用户重试使多活机房 SLB 过载,所有服务不可用。
这次变乱可以称为诡计多端的"0"
故障总结


  • SRE 发现服务不可用,其他员工证实
  • 由于内网体系登录流程与用户侧有关联,远程工作的员工无法帮助处理处罚题目
  • 根据故障表现判定故障发生在 SLB 中
  • 远程工作的员工通过绿色通道乐成登录
  • 猜疑主机房 SLB 过载导致题目,实验重载失败,冷重启失败
  • 重启多活机房 SLB,焦点业务规复
  • 实验规复主机房 SLB

    • 回滚近期代码,无效
    • 关闭 WAF,无效
    • 回滚哀求重试逻辑,无效
    • 回滚 HTTP/2 协议支持,无效

  • 新建源站 SLB,CDN 切量,所有服务规复
  • 对故障 SLB 举行性能分析,到场日志纪录
  • 发现 _gcd 函数的某次实行返回值为 NaN
  • 发现诱由于某个容器的 weight=0
  • 猜疑为 JIT 编译器题目,全局关闭 JIT
  • 生存 core 文件留待分析
  • 重启原有 SLB 集群,规复正常
  • 关闭所有 SLB 集群的 JIT,规避风险
  • 发现在某种特别发布模式种容器权庞大概为 0
  • 克制对应发布模式,SLB 忽略注册中央权重
个人看法

B 站至少有 5 个方法制止这次变乱发生,大概低落变乱影响。
第一,如果在新的 SLB 集群测试时包含了所有大概的发布模式,就能检测出特别发布模式产生的题目,继而完全避免变乱发生。
第二,如果在检测到故障时立即制止所有正在发布的服务,并将其回滚到旧版本,SLB 重启后服务就可以立即规复正常,大大收缩故障时长。
第三,如果多活机房的容量充足大,扛住了当时 4 倍的流量和 100 倍的 TCP 毗连数,焦点业务就不会受到影响。
第四,如果多活机房 SLB 在明知无法蒙受云云大流量的情况下,灵敏进入熔断状态,捐躯部门用户的体验,就不会造成哀求的大量超时,CDN 在哀求失败率过高的情况下放弃重试后,流量进一步低落,熔断规复,就可以大幅提拔焦点业务的访问乐成率。
第五,如果 SLB 团队提前演练过相应的故障处理处罚方法,就能灵敏完成集群的新建和设置,继而大大收缩故障时长。
再大的平台也终究被海因里希法则打垮了,可谓是看到了高楼大厦内部脆弱的地基。
无论怎样,我很高兴看到 B 站没有接纳冷处理处罚的方式,固然这份陈诉姗姗来迟,但终究告诉了我们变乱的原形。
如果能在故障规复后尽快发布复盘陈诉,大概至少发表一份声明,否认遭到外界攻击导致故障,也能让各人安下心来。
这次 B 站算是坐实“小破站”的名号了,激进的技能选型背后,焦点业务照旧要包管稳固性。
下次别用动态语言了,用 Go 重写吧,真的。
参考资料

2021.07.13 我们是如许崩的 - 哔哩哔哩技能
2021.07.13 B站是如许崩的 - 三太子敖丙
7.13 B站变乱当事人:这是我从业以来压力最大的一晚 - 三太子敖丙
SRE - 百度百科
负载平衡(LB)大略先容 - 后端码匠
四层负载平衡 - backzy
SLB(服务器负载平衡)- 百度百科
WAF - 百度百科
火焰图(Flame Graphs)- 0x007c00
海因里希法则 - 百度百科
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-19 02:25, Processed in 0.196428 second(s), 32 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表