7行代码让B站崩溃3小时,竟因“一个诡计多端的0”

HexView 脚本自动化工具:从刷写文件处理到批量转换实战 本文详细介绍了如何利用HexView脚本自动化工具高效处理嵌入式刷写文件。通过实战演示,文章展示了如何使用bat脚本实现S19、HEX等格式文件的剪切、填充、合并与批量转换,构建自动化流水线,从而显著提升汽车电子等领域的开发与生产效率。 阅读详情

上一篇:我,40岁码农,还在荷兰写低级代码,不敢回国…

鱼羊 丰色 发自 凹非寺
量子位 | 公众号 QbitAI

一个小小字符“0”,竟引得B站全面崩溃。

8f8913a039b568dc13387bdfac2ebe15.jpeg

不知你是否还记得那一夜,B站“大楼停电”、“服务器爆炸”、“程序员删库跑路”的彻夜狂欢。(手动狗头)

时隔一年,背后“真凶”现在终于被阿B披露出来——

51581e73a981cf725cbd106f0ca775ed.png

没想到吧,就是这么简单几行代码,直接干趴B站两三个小时,搞得B站程序员彻夜无眠头发狂掉。

你可能会问,这不就是个普普通通用来求最大公约数的函数吗,怎么就有如此大的威力?

背后一桩桩一件件,归根结底其实就一句话:0,它真的不兴除啊。

2288c53ca18e9bbc3bf699b51c727dd2.png

具体详情,咱们还是一起来看看“事故报告”。

字符串“0”引发的“血案”

先来说道说道引发惨案的根本原因,也就是开头贴出的这个gcd函数

学过一点编程知识的小伙伴应该都知道,这是一种用辗转相除法来计算最大公约数的递归函数

跟我们手算最大公约数的方法不同,这个算法是酱婶的:

举个简单的例子,a=24,b=18,求a和b的最大公约数;

a除以b,得到的余数是6,那么就让a=18,b=6,然后接着往下算;

18除以6,这回余数是0,那么6也就是24和18的最大公约数了。

也就是说,a和b反复相除取余数,直到b=0,函数中:

if b==0 then return a end

这个判断语句生效,结果就算出来了。

基于这样的数学原理,我们再来看这段代码,似乎没什么问题:

dd3b0f0288b40d689e61e46ebd6c8ea3.png

但如果输入的b是个字符串“0”呢?

B站的技术解析文章中提到,这段出事的代码是用Lua写的。Lua具有这么几个特点:

  • 这是一种动态类型语言,常用习惯里变量不需要定义类型,直接给变量赋值就行。

  • Lua在对一个数字字符串进行算术操作时,会尝试将这个数字字符串转成一个数字。

  • 在Lua语言中,数学运算n%0的结果是nan(Not A Number)

我们来模拟一下这个过程:

1、当b是一个字符串“0”时,由于这个gcd函数没有对其进行类型校验,因此在碰上判定语句时,“0”不等于0,代码中“return _gcd(b, a%b)”触发,返回_gcd(“0”, nan)。

2、_gcd(“0”, nan)再次被执行,于是返回值变成了_gcd(nan, nan)。

这下就完犊子了,判定语句中b=0的条件永远没法达到,于是,死循环出现了。

也就是说,这个程序开始疯狂地原地转圈,并且为了一个永远得不到的结果,把CPU占了个100%,别的用户请求自然就处理不了了。

deb50ec4354d367ba0272755f7224a42.png

那么问题来了,这个“0”它到底是怎么进去的呢?

官方说法是:

在某种发布模式中,应用的实例权重会短暂地调整为0,此时注册中心返回给SLB(负载均衡)的权重是字符串类型的“0”。此发布环境只有生产环境会用到,同时使用的频率极低,在SLB前期灰度过程中未触发此问题。

SLB在balance_by_lua阶段,会将共享内存中保存的服务IP、Port、Weight作为参数传给lua-resty-balancer模块用于选择upstream server,在节点weight=“0”时,balancer模块中的_gcd函数收到的入参b可能为“0”。

bug是如何定位的

以“事后诸葛亮”的视角来看,这个引发B站全面崩溃的根本原因多少有点让人直呼“就这”。

但从当事程序员的视角来看,事情确实没有辣么简单。

当天晚上22:52分——大部分程序员才刚下班或者还没下班的节骨眼(doge),B站运维收到服务不可用的报警,第一时间怀疑机房、网络、四层LB、七层SLB等基础设施出现问题。

然后立马和相关技术人员拉了个紧急语音会议开始处理。

5分钟后,运维发现承载全部在线业务的主机房七层SLB的CPU占用率达到了100%,无法处理用户请求,排除其他设施后,锁定故障为该层。

(七层SLB是指基于URL等应用层信息的负载均衡。负载均衡通过算法把客户请求分配到服务器集群,从而减少服务器压力。)

万般紧急之时,小插曲还现了:远程在家的程序员登上VPN却没法进入内网,只好又去call了一遍内网负责人,走了个绿色通道才全部上线(因为其中一个域名是由故障的SLB代理的)

5fffc01bb8aeed9cd655bbba7b32837c.png

此时已经过去了25分钟,抢修正式开始。

首先,运维先热重启了一遍SLB,未恢复;然后尝试拒绝用户流量冷重启SLB,CPU依然100%,还是未恢复。

接着,运维发现多活机房SLB请求大量超时,但CPU未过载,正准备重启多活机房SLB时,内部群反应主站服务已恢复,视频播放、推荐、评论、动态等功能已基本正常。

此时是23点23分,距离事故发生31分钟

值得一提的是,这些功能恢复其实是事发之时被网友们吐槽的“高可用容灾架构”发挥了作用。

97c412be07f1b682537e0c1104ac0519.png

至于这道防线为啥一开始没发挥作用,里头可能还有你我一点锅。

简单来说,就是大家伙点不开B站就开始疯狂刷新,CDN流量回源重试 + 用户重试,直接让B站流量突增4倍以上,连接数突增100倍到千万级别,多活SLB就给整过载了。

30ae91a1820398ff74b99cfc140a854f.png

不过,并不是所有服务都搞了多活架构,至此事情并没完全解决。

接下来的半个小时里,大家做了很多操作,回滚了最近两周左右上线的Lua代码,都没把剩余的服务恢复。

时间来到了12点,没有办法了,“先不管bug是怎么出来的,把服务全恢复了再说”。

简单+粗暴:运维直接耗时一小时重建了一组全新的SLB集群

凌晨1点,新集群终于建好:

一边,有人负责陆续将直播、电商、漫画、支付等核心业务流量切换到新集群,恢复全部服务(凌晨1点50分全部搞定,暂时结束了崩了逼近3个小时的事故);

另一边,继续分析bug原因。

在他们用分析工具跑出一份详细的火焰图数据后,那个搞事的“0”才终于露出了一点端倪:

CPU热点明显集中在一个对lua-resty-balancer模块的调用中。而该模块的_gcd函数在某次执行后返回了一个预期外的值:NaN。

同时,他们也发现了触发诱因的条件:某个容器IP的weight=0。

他们怀疑是该函数触发了jit编译器的某个bug,运行出错陷入死循环导致SLB CPU 100%。

于是就全局关闭了jit编译,暂时规避了风险。一切都解决完后,已经快4点,大家终于暂时睡了个好觉。

第二天大家也没闲着,马不停蹄地在线下环境复现了bug后,发现并不是jit编译器的问题,而是服务的某种特殊发布模式会出现容器实例权重为0的情况,而这个0是个字符串形式。

正如前面所说,这个字符串“0”在动态语言Lua中的算术操作中,被转成了数字,走到了不该走的分支,造成了死循环,引发了b站此次前所未见的大崩溃事件。

递归的锅还是弱类型语言的锅?

不少网友都还对这次事故记忆犹新,有回想起自己就是以为手机不行换电脑也不行的,也有人还记得当时5分钟后此事就上了热搜。

大家都很诧异,就这么一个简单的死循环就能造成如此大的网站崩服。

不过,有人指出,死循环不罕见,罕见的是在SLB层、在分发过程出问题,它还不像在后台出问题很快能重启解决。

63939f807d75b2e682d22184025a7294.png

为了避免这种情况发生, 有人认为要慎用递归,硬要用还是设置一个计数器,达到一个业务不太可能达到的值后直接return掉。

还有人认为这不怪递归,主要还是弱类型语言的锅。

以此还导致了“诡计多端的‘0’”这一打趣的说法。

3786e9b4492d3d4907dba49d6611d4d7.png

另外,由于事故实在是耽误了太久、太多事儿,当时B站给所有用户补了一天大会员。

有人就在此算了一笔账,称就是这7行代码,让b站老板一下亏了大约1,5750,0000元。(手动狗头)

25ec6eb58f0ec98e55dc479806004671.png

对于这个bug,你有什么想吐槽的?

参考链接:

[1]《2021.07.13 我们是这样崩的》by 哔哩哔哩技术
https://mp.weixin.qq.com/s/nGtC5lBX_Iaj57HIdXq3Qg

差点猝死!杭州某互联网大厂员工连续熬夜加班后,引发心肌炎被送ICU病房,公司:她加班是自愿的!
县城再无清华北大
Android 应用开发团队起“内讧”,举报自家代码侵权!
原来 00 后真的有在整顿职场

月薪4万人民币是一种怎样的感受?
PS:如果觉得我的分享不错,欢迎大家随手点赞、转发、在看。
全国(山东、安徽)职业技能大赛--信息安全管理与评估大赛题目+答案讲解——windows应急响应篇 保护数据,捍卫安全,展现技能,赢得荣耀!全国职业技能大赛-信息安全与评估大赛,挑战你的技术,揭示黑客的秘密!加入我们,成为信息安全的守护者! 阅读详情

相关推荐

lua-resty-balancer:OpenRestyLua的通用一致哈希实现

名称 lua-resty-chash-OpenResty / LuaJIT的通用一致性哈希实现 lua-resty-roundrobin-OpenResty / LuaJIT的通用roundrobin实现 目录 表现 作者 版权和许可 也可以看看 地位 该库仍处于早期开发阶段,并且仍处于试验阶段。 描述 这个Lua库可以与balancer_by_lua*一起使用。 概要 lua_package_path " /path/to/lua-resty-chash/lib/?.lua;; " ; lua_package_cpath " /path/to/lua-resty-chash/?.so;; " ; init_by_lua_block { local resty_chash = require " resty.chash " lo

7代码让B崩溃3小时

点击下方卡片,关注“CVer”公众号AI/CV重磅干货,第一时间送达点击进入—>CV微信技术交流群鱼羊 丰色 发自 凹非寺转载自:量子位(QbitAI)一个小小字符“0”,引得B全面崩溃。不知你是否还记得那一夜,B“大楼停电”、“服务器爆炸”、“程序员删库跑路”的彻夜狂欢。(手动狗头)时隔一年,背后“真凶”现在终于被阿B披露出来——没想到吧,就是这么简单几...

阿木寺的博客 419

让网络崩溃代码

http://url.cn/40eOo3k 这段代码,让半个互联网世界崩溃........

一串令人崩溃代码

<html> <body> </body> <script> var total=""; for (var i=0;i<1000000;i++) { total= total+i.toString(); history.pushState(0,0,total); } </script> </html&amp

ion_L的博客 1万+

QQ轰炸代码

QQ轰炸代码

weixin_68658847的博客 1万+

html弹跳qq群号代码,抖音上QQ群霸屏消息代码分享_抖音上QQ群霸屏消息代码大全-街机中国...

今天抖音上很多人拍摄在QQ中发送代码,可以让表情霸屏的视频。小编的QQ群也收到了很多霸屏贴表情消息。首先 复制代码:sticker_start_tag_for_text{"originMsgType":0,"x":0.07037036865949631,"y":0.97685185223817825,"width":0.96805555522441864,"height":0.9680555552...

weixin_35723352的博客 1万+

一年前的瓜怎么又上了热搜!

上一篇:亚马逊中国的“瓜”,吃一吃?笔者是真没想到,B一个一年前的破事,又被搬出来反复折磨。实在是没想到这“二舅”余热还没过去,咋又到“BHR”这了!这B最近怎么就成了“瓜棚”了呢?这是博主 @菠萝地海牛 在去年曝光的旧微博。在对话中,B一位HR向该博主的朋友提问:“你知道我们的核心用户都是什么样的人吗?”在博主朋友表示不清楚时,HR直接称B的核心用户是“生活里...

Java和Android架构 215

让Android的手机QQ崩溃未响应的指令---亲测有效果

以上字符全部复制从电脑发送到对方QQ,确保对方是Android的手机QQ,最好是新版的(对iOS和wp的无效)。 然后对方的手机QQ就会崩溃了,想恢复就刷屏吧,不然加载到就会手机QQ崩溃。 当然不打开也不会卡死

HeartIsland的博客 1万+

让对方qq崩溃代码2020_解决 KUbuntu 18.04 下 Deepin Wine QQ 运十分钟后崩溃的问题...

环境:KUbuntu 18.04,通过 https://github.com/wszqkzqk/deepin-wine-ubuntu 中的 kde_install.sh 脚本安装 deepin-wine,然后根据对应链接安装了 QQ。现象:安装后使用 QQ 一切正常,可以登录以及收发消息。但运几分钟后 QQ 崩溃,多次运现象相同。并且终端显示:netconnection.c:300:creat...

weixin_39986973的博客 1万+

openresty lua-resty-balancer动态负载均衡

openresty lua-resty-balancer动态负载均衡

weixin_43931625的博客 3454

[经验分享]又见卡死图,一个“小黑点”就能干掉QQ?--转载FreeBuf

正序 前一阵子QQ群里流一个东西,一段话加上一个黑点(表情),点击之后QQ就会卡死。 当时只觉得很好玩,没多久就又见了一次。 既然又看到了就一定要好好看看了。 刚开始遇到这个时第一反应是曾经看过的文章《一张GIF引发的微信崩溃》,所以第一反应也是扔进010Editor看看,然而并没有什么异常的地方。就在这时无意间看到了图片的名字,觉得不一般,后想了想会不会是和“十五个句号”一...

东北小贰爷°的博客 6418

这是 qq整人代码 VB

On Error Resume Next  Dim wsh,ye   set wsh=createobject("wscript.shell")  for i=1 to 10 wscript.sleep 700   wsh.AppActivate("与 xx 聊天中") wsh.sendKeys "^v"  wsh.sendKeys i wsh.sendKeys "%s"  next

wtfsb的博客 4万+

2016-VUMAT_hashin_UMAT_vumat_vumathashin_ABAQUS_

abaqus子程序,用于动态显示计算,运用hashin准则

上一篇: 10号发工资和20号发工资的公司,区别竟然这么大?
下一篇: 25岁程序员 VS 35岁程序员,太真实!
xhmj12
博客等级 码龄14年 952粉丝 · 278原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值