您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    Go 效劳乱码引发的线上事故
    时间:2020-05-07 12:15 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

    Go 效劳乱码引发的线上事故

    最近遇到了一同依赖晋级 + 异常数据引发的线上事故,经验惨痛,本文对此停止回故和总结。

    背景

    原因是我们运用的效劳框架版本比较老,GC 次数的 metrics 打点不断为 0,咨询了相关同窗后,决议晋级框架。晋级的进程中,出现了 u搜索引擎优化finternalpackagexxxnotallowed 的报错,又咨询了一下相关同窗后,尝试运用 go mod 处置。

    从 go vendor 到 go mod 的晋级的进程也不太顺利,这里按下不表,最终是晋级成功了。一同晋级的还有 Go 版本,从 1.11 晋级到 1.13。

    周四上完线后,一切都看似很不错:内存占用、GC 消耗的 CPU 有了优化,GC 次数的监控也有了。由于触及到公司外部数据,图我就不放了。

    周五、周六都安全渡过,周日出成绩了,小组的同窗从下午 12 点左右不断肝到清晨 12 点,才松了一口吻。不幸我们来之不易的一个周日!

    现象

    周日 11 点 45 左右,端口的调用失败率报警,同时有业务方反应调用接口报错。

    同志们,关键时辰,完善的报警能给事故的处置和恢复博得时间啊!

    By case 排查,发现效劳 shard3 集群的机器报 i/o timeout 错误。效劳共有 4 个分片集群(依据 ID hash 到对应分片),其他 3 个集群完全正常。接着发现 shard3 集群的机器内存正常、端口还在,但 in/out 流量全部掉到几十 KB/s,看日志也没有发现任何异常。

    重启 shard3 集群的效劳,重启后的效劳恢复正常,拜访 debug 端口,也是正常的。但是,十几分钟后,恢复的效劳再次出现异常:in/out 流量再次掉到几十 KB/s,拜访 debug 端口也没有任何照应,末尾慌了。

    处置

    上线出成绩,第一时间回滚!

    波动性外面很重要的一条就是:有成绩,先回滚。先止损,将事故影响降到最低,预先再来清查根因,总结复盘。

    于是末尾操作回滚, reset 到周四上线之前的一个 commit,重新打包,上线 shard3 集群。之后,对外接口完全恢复,操作回滚其他集群。

    效劳启动之前,需求先加载几十个 G 左右的数据,启动进程长达 10+ min。我央求了一台线上成绩机器的 root 权限,执行了 strace-p 命令:

    发现效劳卡在 futex 系统调用上,这很清楚是一个 timer,但是 timer 为何会卡住?正常状况下,会有各种像 write,read 的系统调用,至少打日志、上报 mertrics 打点数据都会有 write 系统调用吧,哈?再执行 perf top 命令:

    相关的只要 codec 函数,再看效劳进程:

    看 perf 输入的结果,全部聚焦到 codec 这个第三方库上,主要的两个函数居然是 codec.quoteStr 和 utf8.DecodeRuneInString。而我们用 codec 的中央是在顺序启动时加载数据文件以及定时的 dump 文件到本地。如今顺序曾经启动了,只能够是 dump 文件出成绩了。查看相关日志,果真有末尾 dump 文件的日志记载,却不断没有 dump 成功的记载。

    清查

    预先清查阶段尝试在 test 集群上重现缺点,由于只要单个分片出成绩,阐明此缺点和特定数据有关,是 hash 到分片 3 的数据惹起的成绩。

    又由于 test 集群并没有分片,所以强行(改代码 && 改环境变量)将其伪装成 shard3 集群,然则并没有复现,猜测能够是方案下线了。

    周二的时分,终于在 test 集群上模拟分片 1 时重现了线上缺点。

    比照 codec 的版本成绩,果真有成绩:周四上线前, vendor.json 里的版本是 v1.1.7,上线后,晋级到了 v1.1.8,看来找到成绩了!修正 codec 的版本,重新编译、部署,成绩依然存在!

    这时,组里其他同窗反应 2018 年的时分也出过 codec 的成绩,事先也是出现了异常数据招致重启时加载文件不成功。于是我直接将周四上线前 vendor 文件夹里 codec.quoteStr 函数的代码和 codec 的 v1.1.7 代码停止比照,并不相反!vendor.json 里的版本并没有正确反响 vendor 里实践的 codec 版本!!!

    进一步查看提交记载,发如今 2017 年 11 月份的时分有一次提交,修正了 vendor 文件夹里的代码,但这时 vendor.json 并没有 codec 记载。而在 2019 年 11 月的一次提交,则只在 vendor.json 里添加了一条 codec 记载,vendor 文件夹里的代码并没有更改:

    "checksumSHA1""wfboMqCTVImg0gW31jvyvCymJPE="

    "path""github.com/ugorji/go/codec"

    "revision""e118e2d506a6b252f6b85f2e2f2ac1bfed82f1b8"

    "revisionTime""2019-07-23T09:17:30Z"

    "tree"true 

    细心比对代码,主要差异在这:

    Go 效劳乱码引发的线上事故

    从现象及源码看,大约率是在 codec.quoteStr 里死循环了!由于 Go 1.14 前都无法抢占正在执行有限循环且没有任何函数调用的 goroutine,因此一旦出现死循环,将要停止 GC 的时分,其他一切 goroutine 都会中止,并且都在等着有限循环的 goroutine 停上去,遗憾的是,由于 for{} 循环里没有停止函数调用,无法插入抢占标记并停止抢占。于是,就出现了这样一幕:

    (责任编辑:admin)