记一次生产环境事故

记一次生产环境事故
Page content

0x00 序

昨天吃过晚饭,我正躺在床上玩手机。

突然领导微信甩来一张截图:

怎么回事?线上系统无法登录?

我心里一登,意识到生产环境有情况!立马坐起来,赶紧远程到公司电脑,再通过 ssh 登录生产服务器。操作刚落,领导补充一句:

很多用户都反馈过来有这个问题

我再心想,不好,问题覆盖面很广。立刻回复领导:

是接口错误,我在紧急排查,请安抚一下用户

果然不一会,各个用户群消息此起彼伏起来。

首先查看报错信息,是 Redis 无法写入磁盘,立刻执行 df -h 查看剩余空间。果然!Use% 一列为 100%!好家伙,一点都没给我剩啊。

于是我需要排查究竟是什么东西占满了磁盘空间,输入命令 ncdu /var 查看大文件,目标锁定到一个 docker 容器的 json 日志,竟有 14G!龟龟,居然这么大,立刻删除,重启容器。再次检查剩余空间,这下终于可以了,翻看业务系统日志,已没有报错信息,用户可以正常登录。

抢修过程花费不到 5 分钟,还算及时。也还好该业务不涉及支付,并没有给用户和公司带来经济上的损失,实在万幸。

0x01 问题深挖

那么,我的疑问是,上线仅4个月,业务量不大的系统,怎么会有这么多的日志?

在紧急释放了空间后,我立刻追踪了该 docker 容器的日志:

1$ docker logs -f CONTAINER_NAME

一看,每秒都有 定时任务 在跑,还把跑的情况写日志了,这肯定是不行的啊!那么,为什么这个情况会存在于生产环境呢? 我询问了开发这部分功能的同事,他这么回答我:

当时需要调试,就打日志了,上线之后并不清楚会写到 docker 文件,以为是控制台日志不会留存。

而实际上,docker 的 json 文件日志就是业务系统的控制台日志。

这个时候,我突然记起,我在安装 docker 时,有配置过 日志大小限制 呀,怎么没有生效?我查看容器状况:

1$ docker inspect CONTAINER_NAME

看到 LogConfig 一项如下:

1{
2    "LogConfig": {
3        "Type": "json-file",
4        "Config": {}
5    }
6}

咋回事?我再查看全局配置: cat /etc/docker/daemon.json

1{
2    "log-opts": {
3        "max-size": "200m",
4        "max-file": "3"
5    }
6}

这不是有么?我蒙圈了。难道是没有生效?运行命令:

1$ systemctl daemon-reload
2$ systemctl restart docker

再次查看容器状况,还是没有。这真是奇了怪了。 于是我瞪着屏幕大概 10 分钟,终于发现端倪:我把 daemon.json 写成了 deamon.json

0x02 事后总结

这次生产事故反映出我司在下面 3 个方面仍有不足:

  1. 日志记录没有章法。在开发中,调试日志应用 Logger.LogDebug() 记录,这样,在生产环境按日志级别过滤不应记录的日志时,可以直接设置为 Warn 级别;另外,后台任务这样的日志,也不应打印出来,容易淹没重要日志。
  2. 运维操作手动可耻。正因为我司仍没有自动化运维,生产环境初始化配置这一操作依旧手动,daemon.json 这样的低级拼写错误是不应出现的。
  3. 生产环境监控与告警设施不完善。如果前两条都没有做到,但有正儿八经的监控告警,那么至少在剩余 20% 空间时,就应该通知到运维人员,这样就有足够时间进行情况处理,甚至是扩容。而不是等到用户投诉、领导反馈,再大难临头。

解决方案当然是有的:

  1. 加强 Code Review。对于日志记录的策略,实际上是对于代码的管控与审查。写代码随心所欲,导致发布到生产环境时没有和运维人员完全交底(因为自己都忘了这么写过),就会让这些潜在问题突然爆发。良好的代码审查,每次提交代码,都至少要过一遍代码是否合理,这里的合理,主要是指是否 按照编码规范编写,而审查是否会有内存泄漏这种不好看出来问题。
  2. 推进自动化运维。虽然在我的努力下,已经从刀耕火种的手动复制 Release 文件到服务器上的原始时代,过渡到 Git 提交触发 Jenkins 自动 CI 发布的近现代。但是在服务器运维上,仍然缺少自动化工具。这一块其实我司并没有经验,而且我也没有精力去搞,还在忙着做业务。
  3. 推进基础设施监控与告警Prometheus + Grafana 这一套其实已经足够,但说回来还是受限于人力,没有相关精力搞。

0x03 思考

生产环境紧急情况处理,是每个工程师都要面临的考验,而且对于不同情况的分析、处理,很多都是靠经验,在这件事情上,非常能甄别出经验丰富的工程师。 一个能 Hold 住突发情况的工程师,可以说是公司的救火队员,是救公司业务于危难时刻的关键人物。

曾经带我入行的师傅告诉我,遇到这样的情况,只给你 10 分钟分析问题,10 分钟内不能解决,必须 立刻 恢复生产系统正常运行,放弃事故现场,不要恋战。要成为对公司有价值的员工,什么是有价值?保障了公司业务正常运行不出错就是有价值。对于个人成长而言,你也从一个只会按照需求做业务功能的工程师,逐步成长为可以独当一面的工程师,你的临场分析判断力、临危不乱,是一种真正的个人能力。

实际上,谁都不希望出生产事故,这也是我们为什么要花力气去建设基础设施,做好监控告警,做好自动化,做好研发流程管控。未雨绸缪罢了。