ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

代码之外06:我早就预警过,出事后却成了我的责任

2026/8/10 10:32:08 拓冰建站 浏览量
代码之外06:我早就预警过,出事后却成了我的责任 《代码之外程序员重启人生》· 第06篇上一世他提前三个月指出数据库存在单点风险。系统崩溃后所有人却只问了一句话“你既然早就知道为什么没有坚持”周三上午十点二十六分。林川正在做代码评审右下角突然弹出一条监控告警。订单数据库磁盘使用率达到82%。黄色告警。还没有影响业务。群里也没人说话。林川点开监控面板看了一眼过去三个月的曲线。磁盘使用率从61%缓慢上升到82%。日均增长大约0.24%。按照当前速度再过五十天左右就会达到危险区间。真正让他在意的不是磁盘空间。而是这台数据库服务器本身。会员系统、订单系统和积分商城的核心交易数据都运行在同一个MySQL主实例上。没有自动故障转移。没有可随时切换的备用节点。每天凌晨只有一次全量备份。binlog虽然开启了但从未做过完整恢复演练。如果主实例出现硬件故障恢复时间无法确定。更麻烦的是这台服务器已经运行了四年。上一世林川第一次看到这个告警时也做过提醒。他在技术群里发了一句话订单数据库是单实例建议尽快补高可用磁盘也需要扩容。项目经理周凯回复收到后面统一规划。运维同事说目前运行挺稳定短期应该没问题。业务还在催新功能。研发排期也很满。这件事很快就沉了下去。一个月后林川又在周会上提了一次。周凯说先把当前版本上线高可用改造放到技术债里。两个月后他在私聊中再次提醒这台数据库一旦故障订单和积分都会受影响恢复时间不可控。周凯回复我知道但现在没有资源。你们技术侧先想办法兜底。三个月后的凌晨两点十七分。订单系统全面瘫痪。数据库服务器的一块磁盘出现故障实例无法启动。会员查询失败。订单无法创建。积分无法兑换。客服群里不断有人反馈用户投诉。所有人连夜赶到公司。恢复持续了五个小时。最后从备份和binlog中找回了大部分数据但仍有十七分钟的交易需要人工核对。第二天的事故复盘会上部门负责人问林川“你不是早就知道数据库有单点风险吗”林川回答“我之前提过几次。”对方皱着眉。“既然你知道风险这么大为什么没有坚持推动解决”林川一时不知道怎么回答。他提过。周会上提过。群里说过。私聊也提醒过。可那些提醒散落在三个月的聊天记录里。没有明确风险等级。没有量化业务影响。没有责任人。没有截止时间。也没有任何人正式作出“暂不处理”的决定。因此事故发生后所有人都可以说我不知道问题这么严重。而那个最了解风险的人反而成了最适合承担责任的人。因为大家会认为你懂所以你应该负责到底。上一世的事故复盘结论最终写着技术团队风险意识不足未能持续推动基础设施隐患整改。林川看过那句话很多次。他不明白风险明明被发现了。为什么最后仍然变成了他风险意识不足直到重新活过一次他才明白说过不等于预警过。别人听见了也不等于组织接受了风险。这一世同样的黄色告警再次出现在屏幕上。林川没有在群里简单发一句建议扩容。他打开风险登记表。新建了一条记录。一、程序员说“有风险”管理者听到的可能只是“以后再看看”林川把风险编号写成R-017核心订单数据库单实例故障风险风险描述当前会员、订单及积分业务共用单一MySQL主实例无自动故障切换能力。主实例发生硬件、文件系统或数据库故障时相关业务将整体不可用。发生概率中。影响程度极高。可能影响新订单无法创建积分和优惠券无法发放会员权益查询失败已提交请求可能出现状态不一致故障期间产生的交易需要人工核对恢复时间无法保证当前控制措施每日一次全量备份binlog持续保留基础数据库监控控制措施缺口无实时从库无自动或手工切换方案未完成恢复演练没有明确RTO和RPO多个核心业务共用同一故障域林川又补充了两个指标。预计恢复时间RTO无法承诺理想情况下4—8小时。潜在数据丢失RPO取决于binlog完整性和恢复结果无法保证为0。过去他只会说数据库存在单点。这句话对技术人员来说已经足够严重。但对其他角色来说“单点”只是一个技术词。它没有告诉业务出问题后会停多久。会影响多少用户。会不会丢数据。要付出什么代价。技术人员经常默认别人应该理解专业风险。可组织中的大多数决策不是根据风险名称完成的。而是根据风险影响完成的。“数据库是单点”可以放进技术债。“发生故障后订单业务可能中断4—8小时并存在交易数据人工核对风险”就不能轻易忽视。林川把整改方案拆成了三档。方案一立即完成数据库高可用改造包括新增备用实例建立实时数据同步配置故障切换流程拆分核心业务故障域完成恢复与切换演练预计投入1名数据库工程师2名后端开发1名测试5—7个工作日新增服务器或云资源成本风险实施期间需要变更窗口数据同步和切换需要充分验证方案二两周内完成最低限度的风险缓解包括扩容磁盘增加一台只读从库验证binlog恢复流程制定人工切换和数据核对方案完成一次故障恢复演练不能彻底消除单点但可以明显降低恢复时间。方案三暂不改造接受当前风险前提是明确由谁接受风险记录暂缓原因确认下一次评审时间保留应急恢复人员业务接受最长8小时不可用的可能性林川不再只提出问题。也不再只说“必须整改”。他把三种选择的成本和后果全部放在同一张表里。然后发起了一场风险评审会。二、“暂时不会出问题”是最廉价也最昂贵的判断周五下午。技术负责人、项目经理、运维、产品和业务负责人都参加了会议。林川介绍完现状后周凯第一个问“这台数据库已经稳定运行几年了为什么现在突然说风险很高”林川回答“风险不是今天突然出现的。”“只是磁盘告警让我们再次看到了它。”“它过去没有出问题不能证明未来不会出问题。”运维同事说“硬盘状态目前正常监控也没有发现明显异常。”林川点头。“单点风险不是说设备现在一定会坏。”“而是任何一次故障都可能直接影响全部业务并且没有快速恢复手段。”周凯问“概率到底有多高”“无法精确计算。”“那是不是也可能几年都不出问题”“可能。”“既然这样现在投入一周时间改造是否有必要”这是技术风险讨论中最常见的困境。如果一个问题已经发生大家会认为你为什么没有提前解决。如果一个问题还没有发生大家又会问为什么要为一个可能永远不会发生的问题投入资源林川没有试图证明服务器明天一定会坏。那是无法证明的。他换了一个问题。“我们可以暂时不改造。”“但需要确认一件事。”“如果明天主库故障业务是否可以接受订单、积分和会员服务中断4—8小时”业务负责人立刻说道“当然不能接受。”“那目前的系统能力无法满足业务预期。”“如果业务不能接受这个影响就需要投入资源降低风险。”业务负责人看向周凯。“最少要做什么”林川打开第二个方案。“最低限度是建立从库、扩容磁盘并完成一次恢复演练。”“这样仍然不是完整高可用但至少发生故障后我们知道如何恢复也能把时间从不可控缩短到大约一小时。”周凯问“能不能先只扩磁盘”“扩磁盘只能解决容量问题。”“不能解决服务器、文件系统和数据库实例故障。”“当前风险不是磁盘满了这么简单。”运维同事补充道“建立从库确实更稳但我们最近还有其他部署任务。”周凯说“研发这边也在赶新版本。”所有人都看到了风险。但每个人也都有不处理风险的理由。这就是技术债最真实的状态。它不是没人发现。而是它的收益发生在未来成本却必须今天支付。如果什么都不发生投入看起来像浪费。只有事故真的到来过去没有投入才会显得昂贵。周凯沉默了一会儿。“这样吧磁盘先扩容从库下个版本再做。”林川没有马上答应。他问“下个版本具体是什么时间”“预计一个月后。”“谁负责推动”“技术侧先规划。”“资源由谁协调”“到时再定。”林川看着屏幕上的记录。上一世的“后面统一规划”就是这样开始的。一个没有日期、没有负责人、没有资源的计划本质上等于没有计划。他说“如果决定暂缓从库建设需要明确风险接受人和下次评审日期。”周凯皱起眉。“有必要写得这么正式吗”林川回答“这是可能导致核心业务中断的高风险事项。”“如果不正式记录事故发生后大家会对今天的结论产生不同记忆。”会议室里安静了几秒。业务负责人说道“那就记录。”“磁盘本周完成扩容两周内建立从库并做恢复演练。”周凯问“两周会不会太紧”业务负责人看向他。“你刚才也听到了。”“如果故障后业务要停几个小时我不能接受。”最终会议结论写进了风险记录决策结果采用方案二两周内完成最低限度风险缓解。风险接受人项目经理周凯、业务负责人共同确认。技术负责人林川。运维负责人陈磊。截止日期本月20日。若截止日期前无法完成需重新评审上线计划和风险等级。林川看着这段文字。他并不觉得自己赢了。他只是第一次让一句“后面再处理”变成了一个真正的项目任务。三、真正的风险管理不是为了给自己留证据会议结束后赵明走到林川旁边。“你现在连风险接受人都写真准备以后出事拿出来甩锅”林川摇头。“不是为了甩锅。”“那为了什么”“为了让风险真的被处理。”赵明笑道“可你刚才明显是在逼周凯签字。”“如果没有人愿意对暂缓决定负责说明这个决定本身就有问题。”赵明想了想。“万一他们还是不处理呢”“那至少组织需要明确接受后果。”“你不是还在保护自己”“保护自己没有错。”林川说道。“但风险记录最重要的目的不是证明事故和我无关。”“而是让风险从一个技术人员的担忧变成组织必须处理的事项。”很多程序员经历过这样的场景。发现风险以后在群里说一句这里以后可能有问题。没人回应。过几天又提醒一次。仍然没有结果。最后问题真的发生程序员翻出聊天记录你看我早就说过。这句话能够证明他不是完全没有意识到问题。却不能证明他真正完成了风险管理。因为有效预警至少应该包含风险是什么会造成什么影响发生概率如何有哪些解决方案各方案成本是什么谁负责处理谁决定接受什么时间必须完成未完成时如何升级只有一句“有风险”更像是提醒。不是闭环。林川不想只做那个事故发生后能证明自己说过的人。他想让事故尽量不发生。即使无法彻底避免也要把影响控制在最低。四、计划刚开始所有“更重要的事情”就出现了数据库整改启动后的第三天。运维已经完成磁盘扩容。从库服务器也申请到位。林川和陈磊开始配置数据同步。这时产品经理突然在群里通知业务希望本周提前上线会员权益转赠功能请研发评估。周凯很快找到林川。“数据库从库能不能先放两天”“转赠功能领导比较关注。”林川问“数据库整改的截止时间是否调整”“先不调整后面追一下。”“由谁追”“你们技术团队想办法。”又是一句熟悉的话。外部目标增加。原任务不减少。时间也不变化。差额默认由执行人员加班承担。上一世林川会接受。因为新功能看起来更接近业务价值。基础设施改造则不容易被看见。项目经理也更愿意向上汇报权益转赠按时上线。而不是数据库从库配置完成。可系统稳定性就是在这种一次又一次的优先级让步中被拖到事故发生的那一天。林川打开风险记录。“从库建设属于已经确认的高风险整改任务。”“如果暂停两天将无法在原定时间完成演练。”周凯说“只是可能延期不一定。”“那请调整计划明确哪个任务优先。”“转赠功能肯定优先。”“好。”林川回答。“我会在项目群同步数据库风险整改顺延两天新的完成时间为22日。”周凯立刻说道“先别在群里说顺延。”“为什么”“业务会觉得我们技术资源安排有问题。”林川平静地问“如果不记录顺延22日未完成时是否会被认为是技术执行延期”周凯没有回答。林川继续说“优先级可以调整。”“但调整产生的影响不能隐藏。”“如果转赠功能更重要就应该让所有相关方知道它替代了什么工作。”周凯脸色不太好看。“你现在做事为什么这么机械”“任务和排期必须保持一致这不是机械。”“是项目管理。”周凯沉默了一会儿。最后说“从库不能延期。”“转赠功能再加一个后端处理。”事情就这样解决了。项目并不是没有资源。只是在执行人员没有明确提出成本之前增加资源从来不是默认选项。最便宜的选择永远是让原来的人多做一点。只有当“多做一点”无法继续被隐藏时真正的资源决策才会发生。五、恢复演练时所有人第一次看到风险真正的样子两周后。从库同步完成。林川组织了一次数据库恢复演练。演练场景是主实例突然不可用需要使用备份实例恢复核心业务。为了不影响生产团队在隔离环境中复刻数据和配置。演练开始前周凯明显没有太大兴趣。“这个过程需要多久”“目前不知道。”“不是已经有从库了吗”“有从库不等于一定能切换成功。”“为什么”“权限、连接配置、应用连接池、任务调度和数据一致性都需要验证。”周凯看了看时间。“尽量快一点我下午还有会。”演练开始。第一个问题很快出现。从库虽然持续同步但应用配置里写死了主库地址。无法动态切换。第二个问题定时任务在备用环境启动后可能重复执行积分过期任务。第三个问题部分内部服务使用了不同数据库账号备用实例中缺少对应权限。第四个问题切换后消息队列里还有未消费订单需要确认是否会重复写入。整个恢复过程持续了两个小时四十分钟。期间发现了十一项问题。如果这些问题第一次出现是在生产事故现场恢复时间至少会再增加数小时。周凯看着问题清单脸色逐渐严肃起来。“为什么以前没人发现”陈磊说“因为以前从来没有真正切换过。”林川补充“备份存在不代表恢复能力存在。”“从库运行正常也不代表业务可以正常切换。”“只有演练过才能知道实际恢复时间。”业务负责人问“现在如果主库故障需要多久恢复”“完成问题整改后目标是三十分钟内完成切换。”“数据会丢吗”“正常同步情况下数据损失可以控制在分钟级以内。”“能不能做到完全不丢”“需要进一步升级架构和自动化切换能力。”“但相比之前无法评估风险已经明显降低。”演练结束后周凯没有再说这是一个可以“后面再规划”的问题。因为抽象的风险终于变成了具体的两小时四十分钟和十一项故障点。很多技术问题不是管理者故意忽视。而是只要系统仍然正常运行风险就很难被感知。程序员需要做的不是反复用更严重的语气说真的很危险。而是把风险转换成其他人能够理解的结果会停多久会影响什么当前恢复需要几小时哪些问题会阻塞业务需要投入什么资源才能降低风险风险越具体越难被一句“以后再说”带过。六、事故还是发生了但这一次只持续了二十七分钟从库改造完成后的第九天。凌晨两点十四分。订单数据库主实例突然失联。监控系统连续触发告警。应用日志中出现大量连接超时。值班电话很快打到林川手机上。他睁开眼时心跳依然不受控制地加快。虽然重新活过一次但身体仍然记得上一世那个凌晨。五小时的恢复。混乱的群消息。不断上涨的投诉。以及第二天那句你为什么没有坚持林川打开电脑。运维确认主服务器文件系统异常数据库短时间内无法恢复。林川没有再花时间尝试抢救主实例。按照演练流程他在事故群里发出指令启动数据库切换预案。第一步停止可能重复执行的定时任务。第二步确认备用库复制状态。第三步停止写入流量。第四步切换应用数据库连接。第五步执行核心交易校验。第六步逐步恢复流量。凌晨两点四十一分。订单服务恢复。整个中断持续二十七分钟。业务受到影响。但没有出现大面积数据丢失。也不需要人工核对几个小时的交易。事故群里周凯问主库为什么会突然故障陈磊回复文件系统异常具体原因需要等待硬件检查。周凯又问有没有数据风险林川回答已完成关键表数据校验目前未发现明确丢失。备用库最后同步时间与故障时间相差约十秒正在核对这一区间请求。凌晨三点十分。核心交易核对完毕。有三笔请求处于结果不确定状态。经过消息日志和支付记录比对最终全部完成修复。林川靠在椅背上。上一世的事故持续了五个小时。这一世二十七分钟恢复业务五十六分钟完成数据核对。风险没有因为写进表格而消失。硬件也没有因为会议纪要而永远不坏。但提前做出的每一项准备都在事故真正到来时转化成了恢复速度。七、复盘会上那个熟悉的问题还是出现了第二天下午事故复盘会开始。部门负责人坐在会议室最前面。“这次数据库故障造成订单业务中断二十七分钟。”“虽然恢复比较快但影响仍然比较严重。”他看向林川。“数据库单点风险以前是不是就存在”林川点头。“是。”负责人继续问“既然知道存在风险为什么没有彻底解决”会议室里安静下来。林川听到这个问题竟然有些想笑。上一世的问题是你既然知道为什么没有坚持这一世他们已经建立从库做过演练也将恢复时间从数小时压缩到二十七分钟。但事故发生后人们仍然希望找到一个可以彻底避免事故的人。仿佛只要某个技术人员足够负责所有硬件都不会故障所有系统都可以零风险运行。林川没有情绪化反驳。他打开风险记录。“这个风险在本月5日完成正式评审。”“当时提供了三个方案。”“最终选择的是最低限度风险缓解方案包括磁盘扩容、从库建设和恢复演练。”“完整高可用和自动切换因为资源和实施周期原因暂未建设。”屏幕上清楚显示着决策人业务负责人、项目经理。技术执行人林川、陈磊。决策内容接受人工切换及分钟级数据延迟风险。林川继续说道“这次事故证明最低限度方案发挥了作用。”“但人工切换仍然造成二十七分钟中断。”“如果业务要求故障中断控制在五分钟以内需要进入完整高可用改造。”负责人看着记录没有再问为什么没有坚持。因为“为什么没做”已经有了明确答案。不是技术没有发现。也不是没人推动。而是组织在成本、时间和风险之间选择了一个有限方案。任何选择都不可能同时获得全部收益。周凯说道“当时确实是考虑资源先做了基础改造。”业务负责人也点头。“如果没有这次改造影响会更大。”事故复盘的方向终于从谁没有尽到责任变成了当前方案还缺少什么能力最终改进事项包括建设自动故障切换能力拆分订单和会员数据库故障域增加连接配置动态切换将恢复演练纳入季度制度补充业务降级方案建立数据库容量趋势预警没有人被公开批评。也没有人通过聊天截图互相证明自己早就说过。因为风险、选择和责任早已进入正式记录。八、他没有用记录打脸任何人却让所有人都无法改写事实会议结束后赵明跟着林川走回工位。“刚才把风险记录拿出来的时候爽不爽”林川摇头。“没什么好爽的。”“周凯当时同意暂缓完整改造现在谁也怪不到你。”“如果目的只是证明怪不到我那这套记录的价值太小了。”赵明问“那你觉得价值是什么”“它让大家承认事故不是一个程序员态度不够坚决造成的。”“而是组织在资源有限时作出的风险选择。”“只有承认这一点才会真正改进系统。”如果林川只是想自保他完全可以在风险提出后什么也不做。等事故发生再翻出聊天记录。可那样的胜利毫无意义。系统仍然会崩溃。用户仍然会受影响。团队仍然要熬夜恢复。真正成熟的自我保护不是与项目结果切割。而是让自己在承担技术责任的同时不再替不属于自己的决策责任背锅。他负责发现风险。分析影响。提出方案。推动闭环。执行已经确认的技术措施。但最终投入多少资源、接受多大风险是组织决策。程序员可以对专业判断负责。却不可能在没有预算、资源和决策权的情况下对所有结果负责。九、“我早就说过”为什么通常没有用很多程序员遇到事故时最委屈的一句话是我早就说过这里有问题。这句话可能是真的。但它通常解决不了任何事情。因为对方接下来会问你在哪里说的当时说得有多严重有没有明确影响提了什么解决方案谁决定不做为什么没有继续升级如果这些问题没有答案“我说过”很容易被理解为你随口提醒过但没有真正推动。这并不完全公平。一个普通开发人员不可能拥有无限推动能力。但在现实职场里只要你比别人更了解风险就需要采用更完整的表达方式。不要只写数据库有单点建议处理。可以改成当前核心订单数据库为单实例。发生实例或服务器故障时订单、会员和积分业务将整体不可用预计恢复时间4—8小时并存在交易数据人工核对风险。建议两周内完成从库建设和恢复演练。若暂不处理需要由项目负责人确认接受上述风险并确定下一次评审时间。这段话没有夸大。没有威胁。也没有预先甩锅。它只是让风险获得四样东西清晰影响解决方案责任归属决策结果从这一刻开始风险不再只属于发现它的程序员。而成为整个项目共同面对的问题。十、预警不是把责任推出去而是把决策抬上来程序员经常承担一种隐形责任你发现了问题就默认应该把问题彻底解决。可现实中很多问题不是纯技术问题。数据库高可用需要成本。系统重构需要排期。安全整改需要业务配合。技术债治理会影响新功能开发。当这些问题涉及资源和取舍时就已经超出单个程序员能够决定的范围。你能做的不是无限坚持直到所有人听从你。而是把风险描述清楚。把业务影响量化。提供不同成本的方案。找到真正有权决策的人。记录最终选择。按选择执行并持续复查。这不是官僚主义。而是让权力和责任重新匹配。没有决策权的人不应该承担完整的决策后果。有决策权的人也不能在结果不理想时假装自己从未作出选择。真正可靠的组织不会依赖某个程序员用个人意志“坚持到底”。它会建立一套机制让风险被发现、被评估、被接受或被处理。写在最后技术人员最怕的不是系统出问题。因为没有系统能够永远不出问题。真正令人无力的是问题发生前所有人都认为风险不紧急。问题发生后所有人又认为技术人员早就应该解决。你提出改造别人问有必要吗你没有强行推动事故后别人又问为什么不坚持这是一场技术人员很难赢的游戏。除非你停止只用口头提醒参与它。让风险进入正式记录。让方案显示真实成本。让有权力的人作出明确选择。让每一个暂缓处理都同时留下下一次评审时间和风险接受人。不是为了在事故发生后把文档甩到桌上说看我没责任。而是为了在事故发生之前让所有人知道我们现在正在选择什么又愿意承担什么后果。林川的重启仍在继续。下一次他将面对一次更加危险的局面。线上事故发生后项目经理在群里第一时间问“这是谁改的代码”上一世所有人忙着证明问题不属于自己。错过了最佳止损时间。这一世林川决定先关掉追责的声音。因为系统正在流血时最没用的问题就是谁先开的第一枪本篇留一句话口头说过不叫风险闭环只有影响被看见、方案被选择、责任被确认风险才真正进入了组织。