尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
关于我如何用一个bug让自己加班到凌晨三点这件事
这事儿得从昨天下午说起。周五下午四点半我已经在收拾东西准备跑路了。测试那边丢过来一个issue说生产环境有个接口偶尔超时让我看一眼。偶尔超时这种词儿在程序员字典里基本等于大概率是你的问题但我懒得查日志。我打开skywalking看了下调用链没毛病啊响应时间平均120ms挺正常的。又翻了翻nginx日志也没有明显慢请求。我就回了一句这边看正常再观察一下。然后测试就炸了。他贴了张截图请求时间15:47:23响应时间3.2秒。我一看这个时间点心里咯噔一下——那个时间我刚发完一个版本重启了服务。你以为的bug其实是feature接下来就是一个小时的血泪排查。先怀疑是缓存失效导致回源DB查了redis命中率99.8%正常。再怀疑是日志打印太多把IO堵了看了下logback的异步队列积压为0正常。怀疑是GC问题看了眼GC日志频率正常单次耗时也都在50ms以内。然后我注意到一个细节这个超时请求里带了一个特殊的headerx-request-id的格式是abc-123-def这种但正常我们内部生成的格式是UUID.randomUUID().toString()全是横杠分段的那种。我就顺着这个header往上查发现这个请求经过了一个网关服务而网关里有个拦截器会对这个header做一次MD5计算然后塞到MDC里用于链路追踪。MD5计算本身不慢但这个拦截器的实现是这样的String requestId request.getHeader(x-request-id); if (StringUtils.isNotBlank(requestId)) { // 为了兼容旧版本对非标准格式的requestId做一次摘要 if (!requestId.matches(^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$)) { requestId DigestUtils.md5DigestAsHex(requestId.getBytes()); } }这个正则每次请求进来都要执行一次。大部分请求的requestId都是标准UUID匹配很快。但那个特殊请求的requestId是不带横杠的短格式正则引擎在做回溯匹配的时候复杂度直接起飞了。再加上那个时间点服务刚重启JIT还没热身解释执行模式下这个正则匹配的耗时从纳秒级飙升到了秒级。问题找到了改法很简单把正则匹配改成尝试按UUID格式解析抛异常就说明不是标准格式再做MD5。try { UUID.fromString(requestId); } catch (IllegalArgumentException e) { requestId DigestUtils.md5DigestAsHex(requestId.getBytes()); }三行代码改完测试环境验证通过预发布验证通过准备发生产。有时候顺风顺水反而让人害怕发生产的流程走了半个多小时——code review、merge、构建镜像、滚动更新。整个过程异常顺利顺到我心里有点发毛。果然上线后五分钟监控突然弹出一堆告警错误率飙到15%全是NullPointerException。我当时整个人是懵的。改的就是一个拦截器里的小逻辑怎么干出NPE了赶紧回滚。回滚后服务恢复然后我开始看错误日志。堆栈指向的代码行是String traceId MDC.get(traceId); Span span tracer.buildSpan(traceId).start();traceId是null所以buildSpan的时候抛了NPE。那traceId为什么是null呢因为设置traceId的逻辑就在我改的那个拦截器里在requestId的基础上又加了一层处理。我改完之后对于非标准格式的requestId走MD5分支这个没问题。但问题是我改代码的时候把一个前置的判断条件顺手优化掉了。原来的代码是if (StringUtils.isNotBlank(requestId)) { // 设置traceId MDC.put(traceId, generateTraceId(requestId)); }我重构的时候觉得isNotBlank这个判断跟后面正则匹配的逻辑有重叠就给合并了变成了javaif (requestId ! null requestId.matches(...)) { // 只对标准格式处理 }这样非标准格式的requestId就直接跳过了整个逻辑连MDC都没设置。更隐蔽的是之前那个拦截器的逻辑里即使requestId是空也会用UUID.randomUUID()生成一个兜底的traceId。我重构的时候把这个兜底逻辑挪到了一个我认为更合适的位置但那个位置在某些异常路径下根本执行不到。所以结果就是部分请求的traceId没设置下游服务拿不到traceId就崩了。凌晨两点的感悟问题最终在凌晨两点修复了。改回去三行加了三行注释发版观察了二十分钟一切正常。回家路上我在想一个问题我为什么会在周五下午去动一个看起来可以优化但已经在线上跑了两年的代码答案其实挺简单的——我看到那段正则匹配的时候就难受职业病犯了。总觉得这种写法不优雅性能有隐患应该重构一下。但事实上那个接口的QPS也就200多那个正则匹配即使是最差情况对整个系统的影响也微乎其微。我花了一个小时定位了一个非关键问题然后用一个不那么稳妥的方案修复了它最后引入了一个更严重的bug。你说这事儿怪谁怪测试没覆盖全怪CR没看出来说到底还是怪我自己没守住线上代码能不动就不动这条底线尤其是周五下午四点半这个死亡时间点。写这段文字的时候已经是周六了。我给自己立了个规矩以后周五下午三点之后除了紧急故障任何代码变更都不做。优化代码这种事儿留给周三上午脑子最清醒的时候干。别学我。
RELATED

相关推荐

第六节:Pinia 状态管理搭建

第六节:Pinia 状态管理搭建

第六节:Pinia 状态管理搭建目标:搭建 pinia,实现用户信息存储(token、用户名),替代 Vuex,全部使用 setup 语法。 新建两个 store: user.js 用户模块:token、用户信息、登…

📅 2026/10/7 12:42:49
京东2016系统测试工程师笔试真题解析:核心考点与答题思路

京东2016系统测试工程师笔试真题解析:核心考点与答题思路

真题这种东西,放在平时看是几道选择题,放在面试前看就是一份押题宝典。京东2016年这套系统测试工程师的笔试真题,我前前后后给好几个准备校招的朋友讲过,每次讲完都觉得,这套题的价值远不止“刷一遍对答案”这么简单。…

📅 2026/10/25 13:11:03
Keil + STM32CubeProgrammer:解决下载失败、读保护与批量烧录

Keil + STM32CubeProgrammer:解决下载失败、读保护与批量烧录

先说个我印象特别深的场景。有次在客户现场调板子,程序改完点LOAD下载,Keil直接弹了一行红字:RDDI-DAP Error。试过重新插拔ST-LINK、换USB口、换电脑,全都没用。那时候我还没正经研究过“读保护”这回事,最后被逼得翻…

📅 2026/10/8 10:54:44
MORE NEWS

更多资讯

📰

【IEEE出版 | 高届数会议 | 马来西亚理工大学主办 | 广州线下主会场 + 线上参会可选】第八届国际科技创新学术交流大会暨第七届信息科学与教育国际学术会议(ICISE-IE 2026)

第八届国际科技创新学术交流大会暨第七届信息科学与教育国际学术会议(ICISE-IE 2026) 2026 8th International Academic Exchange Conference on Science and Technology Innovation&2026 7th International Conference on Information Science an…

📰

【经济学、管理学、人工智能、大数据、模型计算机相关交叉主题均为本届会议征稿范围 | 中国-广州】第八届国际科技创新学术交流大会暨经济管理与模型工程国际学术会议(ICEMME 2026)

第八届国际科技创新学术交流大会暨经济管理与模型工程国际学术会议(ICEMME 2026) The 8th International Conference on Economic Management and Model Engineering 随着全球化和信息化的不断深入,经济管理、模型工程之间的关系变得更加紧…

📰

龙格现象:采样点误差为零,插值曲线却给出了不可能的值

一、问题的提法:不比误差,比值域 用一条高次多项式精确穿过一排等间距的采样点,点越多,曲线在两端甩得越厉害。 这是龙格现象(Runges phenomenon)的一句话版本。但要把它变成一条能写进代码评审的判据,还差一步。 常见的讨论方式是「误差有多大」——误差 1.9 听起来…

📰

相机手感为什么总差一点:导数视角下的跟随、样条与弧长参数化

一、三个症状,同一个底层概念 先摆三个你大概率都遇到过的场景: 你给相机写了个跟随逻辑,在自己机器上试手感很好,交给同事试,对方说「有点飘」。你们俩跑的是同一份代码。 你给相机画了条样条路径让它平滑飞过,曲线画得很漂亮,跑起来相机却忽快忽慢。 你把路径上的控制…

📰

操作码与指令编码:从字节码虚拟机到 x86、ARM 与 RISC-V 的真实取指链路

一、CPU 只认数字:操作码到底是什么 1.1 先把话说死 你写的代码,不管是 C 还是 C#,CPU 都看不懂。 CPU 能读的只有内存里的一串数字。所以编译器要做的事,就是把你的代码翻译成一串数字: 你写的: a = b + c变成数字: 3, 1, 2, 5问题来了:CPU 看到 3, 1, …

📰

农业物联网与遥感技术在苗情灾情监控系统中的应用

1. 苗情灾情监控系统概述在现代农业生产中,及时掌握作物生长状况和灾害发生情况是提高农业生产效率的关键。苗情灾情监控系统通过整合物联网、遥感技术和数据分析手段,为农业生产者提供从田间到决策的全链条支持。这套系统能够实时监测作物生长参数、识别…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬