当前位置: 首页 > 科技观察

官方自爆了!去年今天的B站原来是这样崩溃的……

时间:2023-03-23 09:56:40 科技观察

官方炸了!去年哔哩哔哩就这样崩溃了,今天……676.997px;height:401px;"data-type="inline">Lua是一门动态类型语言。在通常的习惯中,变量不需要定义类型,只需要给变量赋值即可。当Lua对a进行算术运算时digitalstring,会尝试将这个数字字符串转换成数字。在Lua语言中,如果进行数学运算n%0,结果会变成nan(NotANumber)。_gcd函数不对数字进行类型校验输入参数,允许参数b传入:"0"。同时,因为"0"!=0,所以这个函数第一次执行后的返回是_gcd("0",nan)。如果传入in为int0,会触发[ifb==0]分支逻辑判断,不会死循环,再次执行_gcd("0",nan)函数时,返回值为_gcd(nan,nan),并且然后Nginxworker开始陷入死循环,进程CPU为100%6.问题分析1.故障刚刚发生,为什么登录不了内网后台笔?后来发现当用户登录内网认证系统时,认证系统会跳转到多个域名下的登录cookie,其中A域名被故障SLB代理。受SLB故障影响,该域名当时无法处理请求,导致用户登录失败。流程如下:随后,我们对办公网络系统的访问链路进行了梳理,并与用户链路进行了隔离。该链接不再依赖于用户对该链接的访问。2、为什么多活SLB在故障开始时不可用?当多活SLB故障时,由于CDN流量回源重试和用户重试,多活SLB流量增加4倍以上。数据突然暴增100倍到1000W级别,导致这组SLB超载。后来由于流量掉线重启,才逐渐恢复。该SLB集群每日晚间峰值CPU占用率在30%左右,剩余buffer不到两倍。如果多活SLB容量足够,理论上可以承受突如其来的流量,多活业务可以立即恢复正常。这里也可以看出,在机房层面发生故障时,多活是业务容灾止损最快的方案。集中治理一个方向。3、为什么在SLB变更回滚无效后选择创建新的源站点切入,而不是并行?我们SLB团队很小,当时只有一个平台开发人员和一个组件运维人员。当出现故障时,虽然有其他同学协助,但是SLB组件的核心变更需要由组件运维同学来执行或者review,所以无法并行。4、为什么新建一个源站需要这么长时间?我们的公网架构如下:这里涉及三个团队:SLB团队:SLB机器选择、SLB机器初始化、SLB配置初始化四层LB团队:SLB四层LB公网IP配置CDN团队:CDN更新回传源公网在IP和CDN分离SLB方案中,只演练了SLB机器初始化和配置初始化,但是与四层LB公网IP配置和CDN的配合还没有演练全链路,以及元信息在平台之间也不可用。没有联动,比如四层LB的RealServer的信息提供,公网运营商的线路,CDN回源IP的更新等。所以一个完整的新源站需要很长一段时间。事故发生后这片区域的联动和自动化也是我们重点优化的方向。目前一个新集群的创建、初始化、四层LB公网IP配置可以优化到5分钟以内。5)后来的根因分析证明关闭JIT编译并没有解决问题,那当晚故障的SLB是如何恢复的呢?当晚定位原因是某容器IP的weight="0"。本应用1点45分发布,weight="0"的激励已经取消。因此,虽然后续关闭jit无效,但由于激励消失,重启SLB后又会恢复正常。如果当时原因没有消失,关闭jit编译后SLB没有恢复,根据定位到的原因信息:某容器IP的weight=0,也可以定位到服务及其发布方式,可以快速找到根本原因。七、优化改进本次事故无论是在技术方面还是在管理方面都有很多优化和改进。这里只列出当时制定的技术方面的核心优化和改进方向。1.23时23分,多活业务核心功能基本恢复正常,APP推荐、APP播放、评论&弹幕拉取、新闻、关注、视频等。故障期间直播业务也进行了多活,但之所以当晚没有及时恢复,是因为直播移动端首页界面虽然实现了多活,但没有配置多机房调度。遗憾的是,在主播房间SLB不可用的情况下,直播APP的首页打不开。通过这次事故,我们发现了多活架构存在的一些严重问题:1)多活基础框架容量不足机房与业务多活定位的关系比较混乱。CDN多机房流量调度不支持用户属性固定路由和分片。业务多活架构不支持写,当时还没有恢复写功能。部分存储组件多活同步和切换能力不足,无法实现多活。2)业务多活动元数据缺乏平台管理,哪些业务做了多活动?什么类型的多活业务,同城双活还是异地单位?业务的哪些URL规则支持多活,目前多活的流量调度策略是什么?以上信息当时只能暂时保存在文档中,没有统一管理和整理的平台。3)多活切割容灾能力弱。多activity裁剪依赖CDN同学执行。其他人员没有权限,效率低,没有切割管理平台,整个切割过程是看不见的。存取层和存储层分离,切面不能编程。没有业务多活动元信息,切割准确率和容灾效果差。我们之前的多活切经常出现这样的场景:业务A失败,我们不得不切到多活机房。与研发沟通后,SRE确认需要对域名A+URLA进行切割,并通知CDN运维。CDN运维切开后,研发发现还有一个URL没有切开,重复上述过程,导致效率极低,容灾效果差。因此,我们多活建设的主要方向:4)多活基础设施能力建设,优化多活基础组件的支撑能力,如数据层同步组件优化,基于用户分片的接入层支持,使得业务多活接入成本更低。重新梳理多活架构下各机房定位,梳理Czone、Gzone、Rzone业务域。推动不支持多活的核心业务和已实现多活但结构不规范的业务转型优化。5)多活管控能力增强对所有多活业务的元数据和路由规则进行统一管控,与其他平台联动,成为多活元数据中心。支持多活接入层规则编排、数据层编排、计划编排、流量编排等,接入流程自动化可视化。抽象多主动切割能力,连接CDN、存储等组件,实现一键式全链路切割,提高效率和准确性。支持多次活切时预能力预检、切中风险检查、核心指标可观测性。2.SLB治理1)架构治理故障前机房内的一组SLB对外提供统一的代理服务,导致故障域无法隔离。后续SLB需要按业务部门拆分集群,核心业务部门有独立的SLB集群和公网IP。与CDN团队、四层LB&网络团队讨论,确定SLB集群和公网IP隔离的管理方案。明确SLB能力边界,SLB非必须能力,统一下沉到APIGateway,不再支持SLB组件和平台,比如动态权重的灰度能力。2)运维能力SLB管理平台实现Lua代码版本管理,平台支持版本升级和快速回滚。SLB节点的环境和配置初始化托管在平台上,链接四层LB的API,实现SLB平台上的四层LB应用、公网IP申请、节点上线等操作,整个过程初始化不到5分钟。SLB作为核心服务的核心,使用率高达30%,目前不具备弹性扩展能力,需要通过扩容将CPU降低到15%左右。优化CDN回源超时时间,减少极端故障场景下SLB连接数。同时对连接数进行极限性能压力测试。3)自研运维团队在项目上的劣势。开发完成,自测没问题后,开始灰度上线,无需专业测试团队参与。这个组件太核心了,需要引入基础组件测试团队对SLB入参做完整的异常测试。Review与社区一起使用OpenResty核心开源库的源代码来消除其他风险。基于Lua现有的特点和缺陷,提高我们Lua代码的健壮性,比如变量类型判断,强制转换等。招聘专业的LB人员。我们选择基于Lua开发,是因为Lua简单易用,社区也有类似的成功案例。团队没有做Nginx组件开发的学长,也没有做C/C++开发的同学。3.故障演练本次事故中,业务的多主流量调度、新源站速度、CDN切入速度、回源超时机制均未达到预期。因此,后续需要探索机房层面的故障演练方案:模拟CDN回源单机房故障,并结合业务研发和测试,验收通过对两端业务的真实表现,了解多活业务的容灾效果,提前优化业务。预料之中的隐患。灰度特定用户流量到CDN节点进行演练,在CDN节点模拟源站故障,观察CDN和源站的容灾效果。模拟单个机房故障,通过多活动管控平台实践业务多活动切量止损方案。4.应急响应B站一直没有NOC/技术支持团队。当突发事件发生时,故障响应、故障通知、故障协调均由负责故障处理的SRE学员承担。如果是普通事故还好,如果是重大事故,信息同步就来不及了。因此,必须优化事故应急机制:优化故障响应体系,明确故障指挥员和故障处理人员在故障发生过程中的职责,分担故障处理人员的压力。当事故发生时,故障处理人员立即寻找后援作为故障指挥官,负责故障通知和故障协调。在团队中强制执行,让每个人都养成习惯。搭建简单易用的故障通知平台,负责故障汇总信息录入和故障进度同步。失败的原因是某个服务是由特殊的发布方式触发的。我们的事件分析平台目前只提供面向应用的事件查询能力,缺乏面向用户、面向平台、面向组件的事件分析能力:配合监控团队打造平台控制面事件上报能力,推动更多核心平台使用权。SLB为底层引擎构建数据平面事件变化上报和查询能力。例如,当服务注册信息发生变化时,可以在平台上查询应用的IP更新和权重变化事件。拓展事件查询分析能力,在面向应用的基础上,构建针对不同用户、不同团队、不同平台的事件查询分析能力,辅助快速定位故障原因。8.总结事故发生后,哔哩哔哩挂了,迅速登上了全网热搜。作为技术人员,身体承受的压力可想而知。事故已经发生了。我们能做的就是深刻反省,吸取教训,总结经验,砥砺前行。本文作为“713事故”系列的第一篇,简要介绍了故障发生的原因、根源、处理过程、优化改进等。后续文章会详细介绍我们在“713事件”后是如何进行优化的,敬请期待。最后想说一句:多活高可用容灾架构确实生效了。