程序大面积出 core 可能会导致整个服务中断,本文分享了『通过控制服务的出core 行为』来避免这个问题,提升服务稳定性。
想象一下你在一个搜索公司,核心的索引查询、Rank排序、广告推荐服务,每个服务都有几千个实例,在一次赶进度的上线后,服务实例突然大面积出core 了, 作为运维,该怎么办?
全量回滚?已经在回滚,可是需要较长时间!
重启大法?不好意思, 程序还没吐完core!
为啥还没吐完?因为这个core 有1T那么大!
此时整个服务的实例大面积出core,即使有部分实例core完之后重启成功,也因为总体容量不足无法提供正常服务,最后只好祭出大招,切容灾 cache。
复盘
在这个case中,暴露出多方面的问题,研发、测试、运维都涉及,这里只讨论运维方面。
1、为什么实例会大面积出core?
集群中 /proc/sys/kernel/core_pattern 的设置是默认值,也就是当程序crash 时, 直接在程序运行的目录里生成core 文件, 所以程序有bug触发时,自然就大面积core了。
2、在回滚完成之前,为什么不能通过快速重启的办法让实例恢复,避免服务整体容量剧降?
因为业务程序很复杂,依赖大量的lib,运行时在内存中加载的数据量也很大,要完整的保留这些信息,生成的core 就会很大,超过1T,吐完core本身就需要很长时间。
3、能不能让程序不core,crash了直接重启以求快速恢复服务?
不行,研发需要 core 信息来排查定位问题,如果core 不完整生成,debug时会报错
可见,程序大面积core 属于代码层面的问题,对于运维来说属于『不可抗力』,所以我们要解决的问题是:
当程序出现大面积core时,如何保证在生成完整core 的前提下,避免所有实例都因为长耗时的生成core行为而无法快速重启?
思路&实现
在查阅linux core dump 相关资料后,我们找到了办法。
Linux 有一项特性: Piping core dumps to a program
翻译过来就是:
在 kernel 2.6.19以后,如果把
/proc/sys/kernel/core_pattern
设置成如下值,
"|/home/sre/pattern_handler.py %p %s %c"
那么程序出core时,系统会执行pattern_handler.py脚本,并且把 core dump内容作为标准输入。
这意味着,系统将core dump行为控制权交给了
pattern_handler.py。
有了控制权,解决问题的思路就有了:
引入 CoreController, 作为所有服务实例的仲裁者,维护一个计数器cored_num,
决定哪些实例能产生core,哪些不能,这样就可以控制少数实例生成core,其他实例不允许生成core,直接进入可重启状态。
整个过程示意如图所示,
效果
使用了这个方法后,程序大面积出core时,就会只生成指定数量的core,其他实例可以快速执行重启恢复,结合回滚手段,就可以避免开头描述的那种故障场景。
注释:文章内容来自微信公众号“曲行人”