导读:B站“713事故”首次公开复盘。
-
我们通过Perf发现SLB CPU热点集中在Lua函数上,怀疑跟最近上线的Lua代码有关,开始尝试回滚最近上线的Lua代码。 -
近期SLB配合安全同学上线了自研Lua版本的WAF,怀疑CPU热点跟此有关,尝试去掉WAF后重启SLB,SLB未恢复。 -
SLB两周前优化了Nginx在balance_by_lua阶段的重试逻辑,避免请求重试时请求到上一次的不可用节点,此处有一个最多10次的循环逻辑,怀疑此处有性能热点,尝试回滚后重启SLB,未恢复。 -
SLB一周前上线灰度了对 HTTP2 协议的支持,尝试去掉 H2 协议相关的配置并重启SLB,未恢复。
-
在某种发布模式中,应用的实例权重会短暂的调整为0,此时注册中心返回给SLB的权重是字符串类型的"0"。此发布模式只有生产环境会用到,同时使用的频率极低,在SLB前期灰度过程中未触发此问题。 -
SLB 在balance_by_lua阶段,会将共享内存中保存的服务IP、Port、Weight 作为参数传给lua-resty-balancer模块用于选择upstream server,在节点 weight = "0" 时,balancer 模块中的 _gcd 函数收到的入参 b 可能为 "0"。
-
Lua 是动态类型语言,常用习惯里变量不需要定义类型,只需要为变量赋值即可。 -
Lua在对一个数字字符串进行算术操作时,会尝试将这个数字字符串转成一个数字。 -
在 Lua 语言中,如果执行数学运算 n % 0,则结果会变为 nan(Not A Number)。 -
_gcd函数对入参没有做类型校验,允许参数b传入:"0"。同时因为"0" != 0,所以此函数第一次执行后返回是 _gcd("0",nan)。如果传入的是int 0,则会触发[ if b == 0 ]分支逻辑判断,不会死循环。 -
_gcd("0",nan)函数再次执行时返回值是 _gcd(nan,nan),然后Nginx worker开始陷入死循环,进程 CPU 100%。
-
SLB团队:选择SLB机器、SLB机器初始化、SLB配置初始化 -
四层LB团队:SLB四层LB公网IP配置 -
CDN团队:CDN更新回源公网IP、CDN切量
-
机房与业务多活定位关系混乱。 -
CDN多机房流量调度不支持用户属性固定路由和分片。 -
业务多活架构不支持写,写功能当时未恢复。 -
部分存储组件多活同步和切换能力不足,无法实现多活。
-
哪个业务做了多活? -
业务是什么类型的多活,同城双活还是异地单元化? -
业务哪些URL规则支持多活,目前多活流量调度策略是什么? -
上述信息当时只能用文档临时维护,没有平台统一管理和编排。
-
多活切量依赖CDN同学执行,其他人员无权限,效率低。 -
无切量管理平台,整个切量过程不可视。 -
接入层、存储层切量分离,切量不可编排。 -
无业务多活元信息,切量准确率和容灾效果差。
-
优化多活基础组件的支持能力,如数据层同步组件优化、接入层支持基于用户分片,让业务的多活接入成本更低。 -
重新梳理各机房在多活架构下的定位,梳理Czone、Gzone、Rzone业务域。 -
推动不支持多活的核心业务和已实现多活但架构不规范的业务改造优化。
-
统一管控所有多活业务的元信息、路由规则,联动其他平台,成为多活的元数据中心。 -
支持多活接入层规则编排、数据层编排、预案编排、流量编排等,接入流程实现自动化和可视化。 -
抽象多活切量能力,对接CDN、存储等组件,实现一键全链路切量,提升效率和准确率。 -
支持多活切量时的前置能力预检,切量中风险巡检和核心指标的可观测。
-
故障前一个机房内一套SLB统一对外提供代理服务,导致故障域无法隔离。后续SLB需按业务部门拆分集群,核心业务部门独立SLB集群和公网IP。 -
跟CDN团队、四层LB&网络团队一起讨论确定SLB集群和公网IP隔离的管理方案。 -
明确SLB能力边界,非SLB必备能力,统一下沉到API Gateway,SLB组件和平台均不再支持,如动态权重的灰度能力。
-
SLB管理平台实现Lua代码版本化管理,平台支持版本升级和快速回滚。 -
SLB节点的环境和配置初始化托管到平台,联动四层LB的API,在SLB平台上实现四层LB申请、公网IP申请、节点上线等操作,做到全流程初始化5分钟以内。 -
SLB作为核心服务中的核心,在目前没有弹性扩容的能力下,30%的使用率较高,需要扩容把CPU降低到15%左右。 -
优化CDN回源超时时间,降低SLB在极端故障场景下连接数。同时对连接数做极限性能压测。
-
运维团队做项目有个弊端,开发完成自测没问题后就开始灰度上线,没有专业的测试团队介入。此组件太过核心,需要引入基础组件测试团队,对SLB输入参数做完整的异常测试。 -
跟社区一起,Review使用到的OpenResty核心开源库源代码,消除其他风险。基于Lua已有特性和缺陷,提升我们Lua代码的鲁棒性,比如变量类型判断、强制转换等。 -
招专业做LB的人。我们选择基于Lua开发是因为Lua简单易上手,社区有类似成功案例。团队并没有资深做Nginx组件开发的同学,也没有做C/C++开发的同学。
-
模拟CDN回源单机房故障,跟业务研发和测试一起,通过双端上的业务真实表现来验收多活业务的容灾效果,提前优化业务多活不符合预期的隐患。 -
灰度特定用户流量到演练的CDN节点,在CDN节点模拟源站故障,观察CDN和源站的容灾效果。 -
模拟单机房故障,通过多活管控平台,演练业务的多活切量止损预案。
-
优化故障响应制度,明确故障中故障指挥官、故障处理人的职责,分担故障处理人的压力。 -
事故发生时,故障处理人第一时间找backup作为故障指挥官,负责故障通报和故障协同。在团队里强制执行,让大家养成习惯。 -
建设易用的故障通告平台,负责故障摘要信息录入和故障中进展同步。
-
跟监控团队协作,建设平台控制面事件上报能力,推动更多核心平台接入。 -
SLB建设面向底层引擎的数据面事件变更上报和查询能力,比如服务注册信息变更时某个应用的IP更新、weight变化事件可在平台查询。 -
扩展事件查询分析能力,除面向应用外,建设面向不同用户、不同团队、不同平台的事件查询分析能力,协助快速定位故障诱因。
延伸阅读👇
延伸阅读《深入理解计算机系统》
刷刷视频👇
原文始发于微信公众号(大数据DT):2021.07.13 我们是这样崩的
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论