程序员10年成长记:第11篇:我的程序,我负责——从“出问题”到“解决问题”
第11篇:我的程序,我负责——从“出问题”到“解决问题”
引言
时间:2020年1月下旬,上海。
办公室里洋溢着一种奇怪的“节前”气氛。一方面,春运已经开始,大家都在抢“回家”的车票;另一方面,一个来自汉城的新型病毒,正从“传闻”变成“头条”。
启明科技“银河计划”的“星辰团购”业务,在经历了“长夜”血战(第10篇)后,性能趋于稳定。小葵作为product-service的负责人,正和团队规划着“春节不打烊”的促销活动。
没有人预料到,一场“风暴”即将来临。
1月23日,汉城宣布“封城”。
启明科技的“星辰团购”,作为少数能提供“在线买菜”和“生活必需品”的电商平台,一夜之间,流量从“高峰”变成了“珠穆朗玛峰”。
订单量,激增 100倍。
小故事:“消失”的订单(The Case of the Lost Orders)
第一幕:P0 警报(The War Room)
1月25日,大年初一,晚上8点。
本应是看春晚的时刻,启明科技SRE(网站可靠性工程)团队的on-call群“炸”了。
“P0级警报:大量用户反馈‘支付成功’,但订单列表‘查无此单’!”
CTO在1分钟内拉起了“作战室”(War Room)语音频道,所有核心研发(包括刚回到老家过年的小葵和张三)全部被紧急召回。
“‘消失’的订单正在指数级增长!客服电话被打爆了!这是资损!资损!!” CEO的咆哮声穿透了所有人的耳机。
第二幕:众生相(The Blamer, The Fixer, The Owner)
恐慌在作战室里蔓V延。
-
小健(The Blamer - 甩锅者)
-
小健(没错,他也调来了上海,负责一个新上线的、非核心的“订单标签服务order-tagging-service”)第一个跳出来:
-
“CTO,我查了我的服务!order-tagging-service所有监控全部200 OK!日志干净!绝对不是我的问题!肯定是‘订单服务’(order-service)的核心逻辑崩了!”
-
张三(The Fixer - 症状修复者)
-
张三在北京,他迅速登录了数据库。
-
“我看到了!有几千笔订单,payment_status(支付状态)是‘PAID’(已支付),但order_status(订单状态)还是‘PENDING’(待处理)!它们‘卡’住了!”
-
“CTO,别慌!我马上写个UPDATE脚本,把这些‘PENDING’的单子改成‘PAID’,先让物流动起来!我每10分钟跑一次,保证订单不丢失!”
-
小葵(The Owner - 主人翁)
-
小葵(作为“银河”技术委员会SRE小组的轮值组长)立刻制止了张三:
-
“张三,STOP!立刻停止所有‘手动改库’操作!”
-
“在‘黑匣子’里手动‘捞数据’,你是在‘制造’更多的数据不一致!我们现在是‘飞行员’,不是‘修理工’!我们必须相信仪表盘!”
-
她转向CTO:“CTO,给我5分钟,我需要一个‘全链路’的TraceID。小健,把你所谓的‘200 OK’的日志,随便给我一个TraceID!”
第三幕:日志中的“魔鬼”(The Devil in the Details)
小健不情愿地丢过来一个TraceID。
小葵立刻跳进公司的分布式链路追踪系统(如SkyWalking/Jaeger)。
这张“X光片”清晰地显示了“订单P-10086”的“旅程”:
sequenceDiagram
participant User as 用户 APP
participant OrderSvc as 订单服务 order-service
participant PaySvc as 支付服务 payment-service
participant TagSvc as 标签服务 order-tagging-service
participant DB as 订单库 MySQL
Note over User, DB: 订单P-10086 创建...
User ->>+ OrderSvc: 1. 创建订单 POST /order
OrderSvc ->>+ DB: 2. 写入订单 Status: PENDING
DB -->>- OrderSvc: 2.1 OK
OrderSvc ->>+ PaySvc: 3. 调用支付
PaySvc -->>- OrderSvc: 3.1 支付成功 Callback
Note right of OrderSvc: 收到支付回调,开始更新订单...
OrderSvc ->>+ DB: 4. 开启事务 TX.Begin
OrderSvc ->>+ DB: 5. 更新支付状态=PAID
DB -->>- OrderSvc: 5.1 OK
OrderSvc ->>+ TagSvc: 6. 同步调用:'打标签'
Note right of TagSvc: 小健的服务
loop 5秒钟
TagSvc -->> TagSvc:
end
TagSvc -->>- OrderSvc: 6.1 5000ms 返回: 200 OK, Tags:[...]
Note over OrderSvc: `order-service`的RPC超时设为 3000ms
OrderSvc -->>- OrderSvc: 6.2 3001ms <b>RPC Timeout! 失败!</b>
OrderSvc ->>+ DB: 7. <b>事务回滚 TX.Rollback</b>
Note over DB: 支付状态被回滚
OrderSvc -->>- User: 8. 返回错误 但APP未处理
Note over DB: 最终数据库状态:<br/> payment_status: NULL<br/> order_status: PENDING
Note over PaySvc: 支付服务状态:<br/> payment_status: PAID
小葵倒吸一口冷气。
“CTO,找到根因了!”
-
“支付”和“订单”是两个系统。支付服务(
PaySvc)记录了“PAID”,而订单服务(OrderSvc)的本地事务(第4步)失败了! -
为什么失败? 因为
OrderSvc在事务中,去同步调用了小健的TagSvc(第6步)。 -
小健为什么骗人? 他的服务
TagSvc确实返回了“200 OK”,但他花了5秒钟! -
5秒钟干了什么? 小葵点开TagSvc的下一层Span…
-
“小健!你是不是调用了‘第三方’的API?!这个ai-tagging.com是什么?!”
小健的脸瞬间白了。
原来,为了实现“智能标签”(比如识别订单是不是“医院”的、“口罩”的),他没有自己实现,而是偷偷调用了一个“免费”的第三方AI创业公司API。
在全国流量洪峰下,这个“小作坊”API,垮了。
最终“根因”: OrderSvc的RPC超时是3秒。TagSvc的响应是5秒。OrderSvc判定TagSvc“失败”,导致整个订单更新事务回滚(第7步)。
但PaySvc的“支付”是无法回滚的。
钱扣了,订单“消失”了。
第四幕:Owner的担当(The Resolution)
“作战室”里死一般的寂静。张三的“手动改库”,只会让数据“彻底错乱”。
小葵迅速下达指令:
“1. 遏制(Containment): 小健,立刻修改TagSvc代码,熔断(Circuit Break)对第三方API的调用!所有请求,立刻返回‘默认标签’!5分钟内上线!”
“2. 修复(Remediation): 张三,停止你的脚本。我会提供给你一个‘支付成功’且‘订单PENDING’的订单ID列表。你只负责‘重试’这些订单的‘更新事务’(从第4步开始),而不是‘修改’它们的状态!”
“3. 长期(Prevention): CTO,这是一个架构级的P0事故。我们把‘非核心’功能(打标签),做成了‘核心链路’的‘同步’依赖!”
小葵在白板上画出了“未来”的架构:
“核心链路,必须‘快’且‘可靠’!” 小葵说,“订单服务(OrderSvc)在支付成功后,只做两件事:1. 更新数据库核心状态。2. 把‘订单已支付’事件,扔进MQ(消息队列)。”
“打标签(TagSvc)、发短信、送积分… 所有‘非核心’业务,都必须是MQ的‘异步消费者’! 就算TagSvc宕机一个月,也绝不允许影响用户‘下单’!”
结语:
当晚,小葵的“熔断”方案让系统在10分钟内恢复。
张三用“重试”代替“修改”,救回了所有“消失”的订单。
小健因为“隐瞒外部依赖”和“缺乏Owner意识”,受到了CTO的严厉批评。
这场“春节P0事故”,成为了启明科技“SRE文化”诞生的“D-Day”。小葵,是那个“定义”文化的人。
核心要点:Ownership(主人翁精神)——区分资深与初级的关键
“Ownership”是一个被用烂的词,但它极其重要。它是从“我实现功能”到“我保障服务”的“心态”切换。
-
初级 (Xiao Jian):
-
心态: “我的代码没错。”
-
边界: “我的服务(Pod)。”
-
行为: 撇清关系 (Blame)。
-
-
中级 (Zhang San):
-
心态: “我能解决问题。”
-
边界: “我看到的症状(DB)。”
-
行为: 修复症状 (Fix)。
-
-
资深 (Xiao Kui):
-
心态: “我必须对‘用户价值’(订单成功)负责。”
-
边界: “端到端的‘全链路’(User to DB)。”
-
行为: 拥有问题 (Own),遏制问题,修复根因,预防未来。
-
Ownership = 责任心 + 能力。 只有责任心(“我想解决”)但没能力(看不懂链路),是“有心无力”。只有能力(“我能解决”)但没责任心(“不归我管”),是“技术油条”。
理论基础:SRE(网站可靠性工程)核心理念
Google SRE是“Ownership”的“工程化”和“制度化”。它的核心思想是:“用‘软件工程’的手段,来解决‘运维’问题。”
-
SLA, SLO, SLI (服务三兄弟):
-
SLI (Service Level Indicator): 指标。你用什么“衡量”服务?(如:
order-service的HTTP 200响应比例、P99响应延迟) -
SLO (Service Level Objective): 目标。你承诺“指标”达到多少?(如:
order-service99.9%的请求在100ms内返回) -
SLA (Service Level Agreement): 协议。如果“目标”(SLO)没达到,你要“赔钱”吗?(这是“法务”和“商务”概念)
-
Ownership的体现: 资深工程师,会主动为自己的服务定义“SLO”,并为“SLO”负责。
-
-
错误预算 (Error Budget):
-
定义: 100% - SLO = 错误预算。
-
例子: 如果SLO是99.9%的可用性,一个月(30天)的“错误预算” = 0.1% * 30 * 24 * 60 = 43.2分钟。
-
意义: SRE的“神来之笔”。
-
“错误预算”是“允许你犯错”的时间。
-
预算充足时: 团队可以“大胆”发布新功能,快速迭代。
-
预算耗尽时(像这次P0事故): 立刻“冻结”所有新功能发布! 全团队必须“All In”解决稳定性问题,直到“预算”重新积累。
-
-
Ownership的体现: 用“数据”(错误预算)来驱动“开发”与“稳定”的平衡,而不是靠“老板”拍板。
-
-
消除琐事 (Toil):
-
定义: 手动的、重复的、无聊的、缺乏长期价值的工作。(比如张三的“手动捞数据”脚本)。
-
SRE铁律: SRE工程师(或有Owner精神的开发)的KPI,就是“消灭”这类工作,把它们“自动化”。
-
关键技能:从“救火”到“防火”
1. 日志分析与分布式追踪 (SOP-1: Triage)
-
“平庸”的工程师看“日志”(Logs)。
-
“优秀”的工程师看“指标”(Metrics)。
-
“卓越”的工程师看“链路”(Traces)。
-
日志(Logs):
order-service的ERROR: RPC Timeout。 -
指标(Metrics):
tag-service的P99 Latency = 5000ms。 -
链路(Traces): (见小故事中的Mermaid图)它把“日志”和“指标”串联起来,是诊断“微服务”问题的“唯一”利器。
- 线上问题应急SOP (SOP-2: Containment)
当P0事故发生时,你的大脑必须像“CPU”一样执行SOP(标准作业程序)。
-
张三的错误: 他跳过了
D(遏制),直接去做F(修复),而且用的是“错误”的修复手段(手动改库)。 -
小葵的正确: 严格执行
D -> E -> F。先“熔断”(D),再“诊断”(E),最后“修复”(F)。
3. 根因分析 (RCA) 与 5-Why (SOP-3: Diagnose)
-
目的: 找到“系统性”根因,而不是“表面”根因。
-
实战(应用到“消失的订单”):
-
Why 1? 为什么订单“消失”了?
- 答:因为
OrderSvc的更新事务“回滚”了。
- 答:因为
-
Why 2? 为什么事务“回滚”了?
- 答:因为
OrderSvc调用TagSvc时“RPC超时”了。
- 答:因为
-
Why 3? 为什么
TagSvc“超时”了?- 答:因为它在“同步”调用一个“第三方”API,而这个API在洪峰下“雪崩”了(5秒才返回)。
-
Why 4? 为什么“雪崩”会“回滚”事务?
- 答:因为
OrderSvc没有对TagSvc做“熔断”和“降级”处理。
- 答:因为
-
Why 5? (The Root Cause) 为什么一个“打标签”的非核心服务,有“权力”回滚“订单”这个核心事务?
- 根因: 我们在“架构设计”上,犯了“同步依赖”的错误,把“非核心”功能(打标签)和“核心”功能(订单状态)“强耦合”在了一起。
-
实战要点:编写一份“专业”的故障报告(Postmortem)
复盘(第8篇)的精髓,就是“Postmortem”。它绝不是“事故检讨”或“甩锅大会”。
SRE的核心原则:Blameless Postmortems (无可指责的复盘)
-
信念: “我们假设每个人(包括小健)在当时都已尽力。”
-
目标: 改进“系统”和“流程”,而不是“惩罚”个人。
一个高质量的Postmortem模板:
-
标题:
[P0] 2020-01-25 "消失的订单" 故障报告 -
概要 (Summary):
- 2020年1月25日 20:00-20:15(15分钟),
OrderSvc因TagSvc超时,导致约5000笔订单支付成功后事务回滚。故障通过“熔断TagSvc”恢复。
- 2020年1月25日 20:00-20:15(15分钟),
-
影响 (Impact):
-
用户: 约5000名用户支付成功但订单未创建,引发大量客诉。
-
业务: 资损XX万(已追回),平台声誉受损。
-
SLO: “订单成功率”SLO(99.9%)跌至95%,“错误预算”耗尽。
-
-
时间线 (Timeline of Events):
-
20:00- SRE收到“订单失败率”警报。 -
20:01- 作战室成立。 -
20:05- 小葵通过TraceID定位到TagSvc超时。 -
20:06- 发现TagSvc的第三方API依赖。 -
20:10-TagSvc熔断方案上线。 -
20:15- “订单失败率”恢复正常。 -
21:00- 滞留订单修复完毕。
-
-
根因分析 (RCA - 5 Whys):
-
(见上一章节的5-Why分析)
-
直接原因:
TagSvc第三方依赖超时。 -
根本原因: “核心链路”对“非核心服务”的“同步强耦合”架构设计缺陷。
-
-
行动项 (Action Items - 最重要的部分):
-
必须 有Owner和DDL(截止日期)!
-
[P0] [架构]
OrderSvc与TagSvc解耦,改为MQ异步。Owner: 小葵. DDL: 2/15. -
[P1] [SRE] 为所有“第三方API”调用,全面加装“熔断器”(Sentinel)。Owner: SRE组. DDL: 3/1.
-
[P1] [流程] 所有“新服务”上线,必须“强制”声明“所有外部依赖”。Owner: 架构组. DLD: 2/1.
-
[P2] [监控] 增加“第三方API P99延迟”的“黄金指标”监控。Owner: 小健. DDL: 2/10.
-
推荐书籍
《Google SRE:网站可靠性工程》 (Site Reliability Engineering: How Google Runs Production Systems) - Betsy Beyer, Chris Jones, 等
-
核心内容与思想:
-
SRE = 用软件工程解决运维问题: 这是全书的“灵魂”。SRE不是“会写代码的运维”,他们是“懂运维的软件工程师”。他们憎恶“琐事”(Toil),他们的使命是“自动化”一切。
-
拥抱风险 (Embracing Risk): Google不清教徒式地追求“100%可用性”。相反,他们发明了“错误预算”(Error Budget)。这个“预算”给了SRE“权力”:当开发团队(Dev)“发布”了不稳定的功能,“烧光”了预算,SRE有权“按停(Halt)”Dev的发布,逼迫Dev去修复稳定性。
-
服务等级目标 (SLOs): SRE不关心“CPU使用率”,他们只关心“面向用户”的“SLI”和“SLO”。这是驱动SRE工作的“唯一”指挥棒。
-
无可指责的复盘 (Blameless Postmortems): 这是SRE的“文化核心”。Google坚信,事故是“系统”的错,不是“人”的错。复盘的目的是“修复系统”,而不是“找到替罪羊”(如小健)。
-
结语
这场“春节P0事故”,是小葵职业生涯中一次“残酷”的成人礼。
她终于深刻地理解了“资深”的含义:
-
不是你能写出多“炫”的算法。
-
不是你能用上多“新”的框架。
-
而是当“P0警报”在凌晨3点响起时,你能否压住内心的恐慌,冷静地打开“链路追踪”,条理清晰地执行“SOP”,在“止血”(遏制)和“治病”(根因)之间做出最快、最准的判断,并最终用“架构”和“流程”的力量,确保“下一次”它不会再发生。
这,就是Ownership。


被折叠的 条评论
为什么被折叠?



