-
共享 SimpleDateFormat 偶发出错:Java 线程安全避坑
有个 Java 服务要频繁把日期字符串解析成 Date、或把 Date 格式化成字符串,为了复用省得每次 new,我图省事定义了一个 static final SimpleDateFormat 全局共享,到处拿它来 parse 和 format,低并发时一切正常跑了很久都没事。可流量一上来诡异现象就冒出来:日志里偶发出现解析错误,有时把日期解析成莫名其妙的值、有时直接抛出 NumberFormat…- 3
- 0
-
返回 nil 却判定非 nil:Go nil 接口陷阱避坑
有个 Go 服务某接口偶发返回处理失败,可日志里找不到任何真正的错误——业务逻辑明明跑成功了数据也对,它就是固执地走进出错分支。我盯着那段再标准不过的代码看半天:err := doSomething(); if err != nil { return err },逻辑清清楚楚、doSomething 内部确认成功返回的是 nil,可那个 if err != nil 偏偏判定为真。一个等于 nil …- 4
- 0
-
事件订阅没退订:C# 内存缓慢泄漏避坑复盘
有个长期运行的 C# 服务跑着跑着内存就缓慢不可逆地往上涨,几天就逼近上限不得不重启,不像一下子爆掉而是温水煮青蛙式一点一点涨极难察觉,直到监控曲线连成一条只升不降的斜线。抓内存快照分析发现堆里积压了海量本该回收的对象——一类视图模型对象明明业务早结束、外部也不再引用,却像幽灵赖在内存里死活不被 GC 回收。顺引用链往上追真凶浮出水面:它们都被一个事件牵住了。原来这些短命视图模型创建时订阅了某个长…- 0
- 0
-
偶发 connection reset:连接池复用死连接避坑
有个服务调用下游接口平时好好的,可总会偶发地毫无规律报一个错:Connection reset by peer——连接被对端重置了,频率不高几百次请求一两次、重试又能成功,起初没太当回事,可流量增长后积累的失败量越来越扎眼。这个错最磨人的就是随机性:同样的代码同样的接口绝大多数都好好的偏偏隔一阵冒一个失败。抓了好久包对了好久日志才慢慢拼出真相,藏在一个我从没留意的细节里:这些失败几乎都发生在一段时…- 7
- 0
-
数据库很闲却拿不到连接:连接池耗尽避坑复盘
有个服务平时跑得好好的,可一到流量高峰就突然集体卡死:大量请求超时,日志清一色报 Connection is not available, request timed out after 30000ms——等了 30 秒都没从连接池拿到一个数据库连接。诡异的是数据库本身一点不忙,CPU 内存都很闲、慢查询日志干干净净,明明数据库很空闲我的服务却拿不到连接,问题显然不在数据库而在那个连接池上。盯着监…- 6
- 0
-
用户A看到了用户B的信息:ThreadLocal 串号避坑
这是我职业生涯里最惊出一身冷汗的一次线上事故。我们用 ThreadLocal 存当前登录用户的上下文——请求进来时在拦截器里把用户信息塞进 ThreadLocal、后续业务随时取当前是谁,用了很久一直稳稳的。可某天客服收到一个让所有人头皮发麻的投诉:一个用户登录后在自己的页面里看到的却是另一个陌生用户的姓名手机号订单,用户信息串了——这涉及隐私泄露性质极其恶劣。连夜拉日志排查才拼出全貌:Web 服…- 2
- 0
-
改一段切片污染另一段:Go slice 底层数组避坑
有个 Go 服务处理一批数据时有这么个逻辑:从一个大切片里按条件切出几段子切片分别交给不同业务处理,其中一段会被追加新元素、另一段会被原地修改,代码写得清清爽爽测试也过了便上线。可线上偶尔冒出灵异现象:某一段数据会莫名其妙出现本不该属于它的内容,像是被另一段处理串味了,复现概率不高数据也对不上、排查好几天毫无头绪——两段切片在代码里明明独立处理八竿子打不着怎么会互相影响?直到把切片底层机制重新啃了…- 11
- 0
-
下游换了 IP 我却死连旧址:JVM DNS 缓存避坑
下游团队做了一次寻常的机房迁移:换了台机器、域名没变,只把 DNS 指向新 IP,并通知调用方切换无感知。可切换之后我们的服务开始疯狂报错,连接超时、连接被拒,日志全是连不上下游的红字。诡异的是同一台机器上我用 ping 和 curl 访问那个域名,解析到的明明是新 IP、访问也完全正常,可我的 Java 进程就是死活连着那个早已废弃的旧 IP 不撒手;把进程重启一下问题立刻消失。这个重启就好的特…- 2
- 0
-
单线程也崩:Java 遍历删除 fail-fast 异常避坑
有个每天凌晨跑的批处理任务,逻辑很朴素:遍历一批订单,把失效的剔除掉,剩下的继续处理,测试环境跑了无数遍都好好的。直到某天凌晨任务突然挂了,异常栈顶端赫然写着 java.util.ConcurrentModificationException。我当时就懵了——这台机器上就一个线程在跑,哪来的并发修改?名字里却带着并发二字,这误导性的命名让我一开始完全找错方向,围着多线程查了半天一无所获。静下心读异…- 0
- 0
-
内存只涨不降、几万协程卡死:Go goroutine 泄漏避坑
有个 Go 后台服务跑了几周后运维找上门:进程内存像吹气球一样一天涨一点、从不回落,最后逼近上限被 OOM 杀掉,重启再涨周而复始。我先按内存泄漏的老套路查对象没揪出元凶,直到顺手看了眼 runtime.NumGoroutine 返回的协程数量当场倒吸一口凉气:这个数字也在只涨不降,从启动时几十个涨到几万个还在稳步往上爬。真相浮出水面——不是对象泄漏,是 goroutine 泄漏:每处理一个请求代…- 3
- 0
-
钱扣了订单却没了:微服务分布式事务避坑复盘
一次让我至今心有余悸的线上事故:下单流程被拆成订单、库存、账户三个微服务依次配合,上线后大多风平浪静,某天财务对账却发现一笔诡异记录——用户的钱被扣了、库存也减了,订单却不存在,客服电话被打爆。扒日志还原现场才明白:那次请求账户成功扣款、库存成功减货,轮到最后写订单时,订单服务的机器恰好抖了一下、数据库连接超时,订单没写成,而前两步已经木已成舟,谁来还?在单体里这三步本可包在一个本地事务里要么全成…- 0
- 0
-
下游没挂自己先崩:TCP 连接 TIME_WAIT 端口耗尽避坑
一个调用下游接口的服务,平时风平浪静,流量一冲高就大面积抽风:日志刷屏般地报 connection refused,更多的是一句陌生的 cannot assign requested address,可被调用的下游监控却一切正常、根本没挂。我顺着"下游扛不住"查了半天一无所获,直到在本机敲下 ss -s,数字一出来就全明白了——几万个连接密密麻麻堆在 TIME_WAIT,本机用…- 7
- 0
-
缓存命中率离奇趴在 0%:Java equals 与 hashCode 避坑
一个跑得好好的 Java 服务,某次我顺手看了眼缓存命中率监控,当场愣住:命中率常年趴在接近 0% 的地方,缓存等于白做,内存里那个缓存 map 倒越涨越大,光占地方不干活。打日志一比对更迷惑——两个 key 在日志里长得一模一样,map.get(key) 却就是返回 null。扒开那个作为 key 的自定义类,真相经典得让我有点不好意思:它重写了 equals 让业务上相等的对象被判相等,却偏偏…- 0
- 0
-
进程偶发猝死、recover 拦不住:Go 并发读写 map 避坑
一个 Go 写的网关服务,上线大半年一直省心,直到某天开始毫无征兆地整个进程崩掉:不是某个请求报错,而是整个服务"啪"地一下没了,被守护进程拉起来,过几小时再崩一次。本地怎么压都不崩,只在生产高并发下偶尔发作;到处写了 recover 兜底,却根本拦不住。崩溃日志最后一行 fatal error: concurrent map read and map write——这不是 p…- 2
- 0
-
请求集体卡顿、单核打满:Node.js 事件循环阻塞避坑
一个平时快得没存在感的 Node.js 服务,偶尔会"集体卡顿"——几乎所有接口在同一瞬间一起超时几秒,然后又一起恢复,像什么都没发生。病来得没规律,日志翻不出半个 ERROR,内存也稳,唯一可疑的是卡顿那几秒总有一个 CPU 核心瞬间被打满到 100%,其它核都闲着。这个"单核打满、其它核闲置"的画面,正是 Node 单线程特性在喊话:某个请求里藏着一坨不…- 2
- 0
-
大促后对账发现重复扣款:一篇讲透接口幂等性设计
大促结束后的第二天上午,财务一条"对账对不平、几十个用户被重复扣款"的消息把我从复盘的轻松里一把拽出来,更夸张的是有人同一笔订单在库里躺着三四条记录。复盘下来真相平淡得后背发凉:流量冲顶时下单接口变慢,用户疯狂连点,客户端和网关又都配了超时重试,同一个请求被结结实实送进后端好几遍——而整个下单链路没有任何一处做了幂等保护。这篇文章从那次重复扣款事故出发,把接口幂等设计从头讲透:…- 8
- 0
-
三万个 CLOSE_WAIT 压垮服务:看懂 TCP 连接状态机
一个风平浪静的上午,核心服务突然刷出满屏 too many open files,接口大面积超时。调大 ulimit 只撑了十几分钟,一条 netstat 揭开真相:三万八千个 CLOSE_WAIT 死死占着句柄只增不减。从这次句柄耗尽事故出发,这篇文章把 TCP 四次挥手状态机、CLOSE_WAIT 与 TIME_WAIT 的本质区别、连接泄漏的定位与修复、长连接复用、超时设置到优雅关闭,一次讲…- 0
- 0
-
被一个 catch 吃掉的异常:Java 异常处理里那些查到崩溃的坑
这个 bug 我查了整整三天,最折磨人的地方在于:日志里干干净净,什么都没有。线上偶尔有几笔订单金额对不上,概率很低、毫无规律,可一旦出现就是真金白银的差错。把整条链路的日志翻了个底朝天,期待看到一行报错、一段堆栈,结果一片祥和。直到逐个方法去读源码,才在一个不起眼的工具类里看到那行让我血压飙升的代码——一个空的 catch 块,把异常静悄悄咽了下去,程序若无其事地把错误金额写进了库。没有报错、没…- 0
- 0
-
Spring @Transactional 失效的 7 种典型场景:从扣款不回滚事故说起 + code review 检查清单
扣款接口失败时没回滚,代码里明明写了 @Transactional,事务怎么就没生效?这是 Spring 老手都不一定能一次答对的问题。这篇把团队踩过的七种典型失效场景全部整理出来 — 类内自调用、非 public 方法、checked exception、异常被吞、传播行为配错、多数据源、@Async 跨线程,每种给最小复现、根因、修法,以及一套能在 code review 阶段就拦住的 Arc…- 2
- 0
-
WebSocket 实时推送完全指南:从一次"用户开着页面挂一会儿就再也收不到消息"看懂长连接工程
2023 年我做一个站内实时消息推送用户开着网页不用刷新就能实时收到新通知新私信。我选了 WebSocket。第一版我做得很省事服务端用 WebSocket 库起一个 server 客户端 new WebSocket 连上去服务端有消息就 send 客户端 onmessage 收到就显示。本地一测完美消息几乎瞬间就到。我心里很踏实WebSocket 嘛不就是建一个长连接两边随便互发消息。可等它真正…- 0
- 0
-
数据库读写分离完全指南:从一次"用户改完资料刷新又变回去、刚下单订单列表却没有"看懂主从一致性
2022 年我负责一个用户量正在往上涨的系统。数据库单机越来越吃力尤其是读压力各种列表页详情页的查询把数据库 CPU 压得很高。我做了一个很标准的优化读写分离。一个主库负责写挂两个从库负责读主库的数据通过主从复制同步到从库。我做得很直接在代码里判断 SQL 写操作走主库读操作走从库。本地一测顺极了写进去的数据转头就能从从库读出来主库压力肉眼可见地降了下来。我心里很踏实读写分离嘛不就是写走主读走从。…- 2
- 0
-
数据库索引完全指南:从一次"加了索引查询还是慢、EXPLAIN 一看根本没走索引"看懂索引优化
2021 年我负责一个订单系统。订单表 orders 已经有几百万行。有个查我的订单的接口越来越慢从几百毫秒一路劣化到好几秒。我看了下它执行的 SQL 是按 user_id 过滤再按 create_time 倒序。我想当然地判断慢无非是没索引加一个就好了。我在 user_id 上建了索引信心满满地上线还是慢。我又想可能 create_time 也得有索引再加一个还是慢。我甚至把 user_id s…- 0
- 0
-
一致性哈希完全指南:从一次"缓存集群加了一台机器、命中率瞬间归零"看懂分布式分片
2020 年我做一个分布式缓存。业务的读压力越来越大单台 Redis 扛不住了我决定加机器上 4 台 Redis 把缓存数据分散到这 4 台上。要解决的核心问题只有一个一个 key 进来我怎么决定它该存到该去哪一台机器上读。第一版我做得很直接把 key 算个哈希值对机器数取模算出 0 1 2 3 就去对应那台。本地一测很顺几百万个 key 均匀地散在 4 台机器上每台四分之一读写都飞快缓存命中率稳…- 0
- 0
-
分库分表完全指南:从一次"订单表分了 16 张、查我的订单却要扫遍全部"看懂数据分片
2021 年我做一个订单系统。orders 表一开始好好的几百万行查询飞快。业务涨了两年多orders 涨到了三亿多行单表彻底慢了下来加索引也救不动了深分页一次查询要几十秒大促那几天直接把数据库 CPU 打满整个下单链路被拖垮。我决定分库分表把 orders 这一张大表水平拆成 16 张小表。第一版我做得很直接按订单的自增主键 id 取模把数据分到 orders_0 到 orders_15。本地一…- 3
- 0
后端
幸运之星正在降临...
点击领取今天的签到奖励!
恭喜!您今天获得了{{mission.data.mission.credit}}积分
我的优惠劵
-
¥优惠劵使用时效:无法使用使用时效:
之前
使用时效:永久有效优惠劵ID:×
没有优惠劵可用!
























