读:那些年我 Oncall 学到的事
目录
yaoyue.org 上有一篇回顾 oncall 经历的文章。作者在 Twitter 负责分布式缓存 7.5 年(2010 年到 2017 年)。那不仅是 Twitter 吞吐量最高的服务(按每秒请求数算),也是事故频发的服务。他和 Dan Luu 一起做的缓存事故调查中,记录了至少十几起严重的全站级故障。可以说,是 oncall 把他塑造成了现在这个样子。
技术面的教训
不要看平均值,看尾部延迟
大多数监控面板显示的是平均响应时间,但平均值会平滑掉大量小数值,把真正影响用户体验的慢请求盖住。在大规模系统里, 尾部延迟 (tail latency,最慢的那一小部分请求的响应时间)比平均值更能反映真实状况。作者学到的第一课,平均延迟好看不顶用,用户实际感受到的是尾部的慢请求。
大多数时候快,不如大多数时候可预测
响应偶尔很快但不稳定,比稳定但稍慢更糟糕。因为你的下游服务和调用方依赖的是可预期的行为,如果系统有时 10ms 有时 5s,调用方只能按最坏情况做超时和重试,整体效率反而更低。稳定的慢不算大事,规划和容忍都没问题。不稳定的快才真要命。
简洁架构在危机时刻最值钱
故障发生时每一秒都珍贵。如果架构足够简洁,你扫一眼就能判断问题出在哪个环节,不用在多层抽象和间接引用里绕来绕去。教科书不会告诉你的那些设计取舍,像应用和环境的交互、服务之间的深层依赖,只有在线上故障的压力下才真正暴露出来。真到那时候,你有时间慢慢查吗?简洁架构的价值就是让你在最没时间思考的时候,能最快想清楚。
运维能力来自设计阶段
作者列了四个方面,全都是在设计阶段就得想好的事,不是上线前两周能补的,
- 可观测性 ,日志、指标、链路追踪的接入点要在代码结构里预留好,而不是出事后才到处加埋点
- 一致性配置 ,所有环境的配置走同一套模板和管理流程,而不是每个环境手改
- 自动化就绪 ,部署、扩容、回滚这些操作从一开始就设计成可脚本化的,不留只有某个老员工知道怎么操作的手工步骤
- 合理的默认值 ,连接池大小、超时时间、重试策略这些参数,默认值就应该适合生产环境,而不是拿开发环境的配置上线
这些在出事之前看起来都是可有可无的事,但等故障来了,你就会发现没有它们什么都干不了。作者的工程品味始终带着运维的视角,即使不再 oncall 了,这种眼光也一直没丢。
人际面的教训
认错是重建信任最快的方式
Twitter 早期把时间线存在 Memcached 里,这些对象长度不固定,随时间不断增长。定期重启 Memcached 释放内存是必要的维护操作,但重启本身也可能触发全站故障。有一次他的失误导致别人花了几小时救火。他没有找理由也没遮掩,直接承认是自己的问题。结果出乎他意料,没有指责、没有追责,同事反而更信任他了。他后来才明白,出了事大家都想知道发生了什么。坦诚认错等于告诉别人,「我知道了,不会再犯」,反而是重建信任最快的方式。
关键时刻建立的情谊最牢固
有些故障的根因落在自己不懂的领域,内核、BMC 这些,靠自己一辈子也搞不定。只能不断追踪、缩小范围,然后靠各基础设施团队帮忙。作者说关键时候培养的情谊是最牢固的。那些在故障中一起想办法的队友,帮他补盲点的同事、教他操作技巧的运维、主动分流流量的上游负责人、把他的模糊问题翻译成明明白白解释的内核工程师,大家忙完一起庆祝。这种战友情,日常工作中培养不出来。
新手期被肯定的价值
作者的第一个经理在他还是菜鸟的时候就肯定他,鼓励他往前走。这不是什么复杂的领导技巧,但就是那句「你做得不错,继续成长」让他在后来的团队管理中也学会了这样对待新人。
结语
Oncall 的价值不在于处理了多少告警。它让你不再活在纸面上了。代码一跑,一出事,所有假设都被打回原形,你才真正理解软件是怎么运作的。以及在这个过程中,结识那些跟你一起扛雷的人。