程序员10年成长记:第11篇:我的程序,我负责——从“出问题”到“解决问题”

程序员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,找到根因了!”

  1. “支付”和“订单”是两个系统。支付服务(PaySvc)记录了“PAID”,而订单服务(OrderSvc)的本地事务(第4步)失败了!

  2. 为什么失败? 因为OrderSvc在事务中,去同步调用了小健的TagSvc(第6步)。

  3. 小健为什么骗人? 他的服务TagSvc确实返回了“200 OK”,但他花了5秒钟

  4. 5秒钟干了什么? 小葵点开TagSvc的下一层Span…

  5. “小健!你是不是调用了‘第三方’的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事故。我们把‘非核心’功能(打标签),做成了‘核心链路’的‘同步’依赖!”

小葵在白板上画出了“未来”的架构:

辅助链路 异步
核心链路 同步
1. 写入DB
2. 写入MQ
Event: Order_Paid
Tagging Service
3rd-party API
Update Tags in DB
MySQL
OrderSvc: 更新订单
RocketMQ

核心链路,必须‘快’且‘可靠’!” 小葵说,“订单服务(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”的“工程化”和“制度化”。它的核心思想是:“用‘软件工程’的手段,来解决‘运维’问题。”

  1. SLA, SLO, SLI (服务三兄弟):

    1. SLI (Service Level Indicator): 指标。你用什么“衡量”服务?(如:order-service的HTTP 200响应比例、P99响应延迟)

    2. SLO (Service Level Objective): 目标。你承诺“指标”达到多少?(如:order-service 99.9%的请求在100ms内返回)

    3. SLA (Service Level Agreement): 协议。如果“目标”(SLO)没达到,你要“赔钱”吗?(这是“法务”和“商务”概念)

    4. Ownership的体现: 资深工程师,会主动为自己的服务定义“SLO”,并为“SLO”负责。

  2. 错误预算 (Error Budget):

    1. 定义: 100% - SLO = 错误预算。

    2. 例子: 如果SLO是99.9%的可用性,一个月(30天)的“错误预算” = 0.1% * 30 * 24 * 60 = 43.2分钟。

    3. 意义: SRE的“神来之笔”。

      • “错误预算”是“允许你犯错”的时间。

      • 预算充足时: 团队可以“大胆”发布新功能,快速迭代。

      • 预算耗尽时(像这次P0事故): 立刻“冻结”所有新功能发布! 全团队必须“All In”解决稳定性问题,直到“预算”重新积累。

    4. Ownership的体现: 用“数据”(错误预算)来驱动“开发”与“稳定”的平衡,而不是靠“老板”拍板。

  3. 消除琐事 (Toil):

    1. 定义: 手动的、重复的、无聊的、缺乏长期价值的工作。(比如张三的“手动捞数据”脚本)。

    2. SRE铁律: SRE工程师(或有Owner精神的开发)的KPI,就是“消灭”这类工作,把它们“自动化”。

关键技能:从“救火”到“防火”

1. 日志分析与分布式追踪 (SOP-1: Triage)

  • “平庸”的工程师看“日志”(Logs)。

  • “优秀”的工程师看“指标”(Metrics)。

  • “卓越”的工程师看“链路”(Traces)。

  • 日志(Logs): order-serviceERROR: RPC Timeout

  • 指标(Metrics): tag-serviceP99 Latency = 5000ms

  • 链路(Traces): (见小故事中的Mermaid图)它把“日志”和“指标”串联起来,是诊断“微服务”问题的“唯一”利器

  1. 线上问题应急SOP (SOP-2: Containment)

当P0事故发生时,你的大脑必须像“CPU”一样执行SOP(标准作业程序)。

是 (Yes)
否 (No)
Detect
警报响起!
Triage
分诊: P0? P1?
是P0吗?
Containment - 遏制!
第一要务: 止血!
如: 熔断, 降级, 回滚
Diagnose
诊断: 5-Why/RCA
Remediation
修复: 发布Hotfix
Prevention
预防: 写Postmortem
异步/MQ改造
Diagnose
诊断: 正常排期
  • 张三的错误: 他跳过了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模板:

  1. 标题: [P0] 2020-01-25 "消失的订单" 故障报告

  2. 概要 (Summary):

    1. 2020年1月25日 20:00-20:15(15分钟),OrderSvcTagSvc超时,导致约5000笔订单支付成功后事务回滚。故障通过“熔断TagSvc”恢复。
  3. 影响 (Impact):

    1. 用户: 约5000名用户支付成功但订单未创建,引发大量客诉。

    2. 业务: 资损XX万(已追回),平台声誉受损。

    3. SLO: “订单成功率”SLO(99.9%)跌至95%,“错误预算”耗尽。

  4. 时间线 (Timeline of Events):

    1. 20:00 - SRE收到“订单失败率”警报。

    2. 20:01 - 作战室成立。

    3. 20:05 - 小葵通过TraceID定位到TagSvc超时。

    4. 20:06 - 发现TagSvc的第三方API依赖。

    5. 20:10 - TagSvc熔断方案上线。

    6. 20:15 - “订单失败率”恢复正常。

    7. 21:00 - 滞留订单修复完毕。

  5. 根因分析 (RCA - 5 Whys):

    1. (见上一章节的5-Why分析)

    2. 直接原因: TagSvc第三方依赖超时。

    3. 根本原因: “核心链路”对“非核心服务”的“同步强耦合”架构设计缺陷。

  6. 行动项 (Action Items - 最重要的部分):

    1. 必须 有Owner和DDL(截止日期)!

    2. [P0] [架构] OrderSvcTagSvc解耦,改为MQ异步。Owner: 小葵. DDL: 2/15.

    3. [P1] [SRE] 为所有“第三方API”调用,全面加装“熔断器”(Sentinel)。Owner: SRE组. DDL: 3/1.

    4. [P1] [流程] 所有“新服务”上线,必须“强制”声明“所有外部依赖”。Owner: 架构组. DLD: 2/1.

    5. [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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值