内存曲线像极了漏水的水龙头 订单服务上线两周,Old 区内存从 1.2G 缓慢爬到 3.8G,Full GC 后也只回一点,没真正回落。不是突崩,是慢性失血。这种"缓增长"最容易被忽视,因为单次看都正常,直到某天 Old 区满了频繁 Full GC,接口全抖。我用多次 dump 对比把它揪出来,过程
ThreadLocal 在虚拟线程时代水土不服 我们的链路追踪 ID 一直用 ThreadLocal 传。切到虚拟线程后,一个请求一个虚拟线程,数量可能上百万,ThreadLocal 的哈希表跟着膨胀,而且线程复用导致上下文串台——上一个请求的 traceId 漏到了下一个。Java 21 的预览特
不想为了监控拖垮生产 之前用 VisualVM 连生产抓采样,JMX 一开 CPU 就飘,GC 行为都变了,抓到的数据还不可信。后来发现 JDK 11 起的 JFR(Java Flight Recorder)开销极低,而且 JDK 14 起的 Event Streaming 能实时订阅事件,不用等
定时任务从 Quartz 搬出来的契机 老系统用 Quartz 集群,任务一多就出现重复触发,两台机器各跑一遍,数据算重了还得手工修。排查发现是 Quartz 的数据库锁在高峰期没兜住。今年做调度中台,我在 XXL-JOB 和 Elastic-Job 之间选,两者都能解决分布式场景,但设计取向不同,
想给搜索加上"语义" 我们的商品搜索一直靠关键词匹配,用户搜"适合送妈妈的礼物"这种长尾 query 基本搜不到,因为标题里没有这几个字。运营天天抱怨转化差。ES 8 增强了 dense_vector 和 kNN 检索,我试着把商品标题做成向量塞进去,让语义相近的也能召回,点击率明显好转。这里把建模
为了启动快,走上 GraalVM 原生镜像 FaaS 场景下单实例冷启动 4 秒太慢,用户第一次请求要等很久。我们想用 GraalVM 把订单服务编译成原生镜像,目标启动 50ms 内。Spring Boot 3 的 AOT 引擎能提前做大部分 Bean 的初始化分析,理论上开箱即用。可一上来就卡在
等到了 Spring Boot 3.2 的虚拟线程开关 Spring Boot 3.2 把虚拟线程集成做进了自动配置,一个属性就能让 Tomcat 用虚拟线程处理请求。我在 3.2 RC 阶段就拉下来试了,把订单查询接口从平台线程池切过去,吞吐数据很说明问题。不过 RC 阶段 API 还有微调,正式
一次全量上线引发的事故 三个月前我们直接全量发了订单服务 v2,结果一个新分支的序列化逻辑和旧版不兼容,老客户端解不出字段,半小时 rollback 了,期间丢了几十笔订单的回调。复盘会上被喷得不轻。痛定思痛,我搭了一套灰度发布体系,核心四件事:流量染色、网关路由、数据兼容、回滚机制。这套跑顺之后,
等了两年的正式版 JDK 21 在 9 月正式 GA,虚拟线程(Project Loom)终于从预览转正。作为常年和线程池、异步回调搏斗的人,我第一时间把内部一个 IO 密集的采集服务迁了过去。结果不算惊艳到颠覆,但确实把"一个请求一个线程"这种直观写法重新变可行了,迁移成本也比预期低。这里把原理、
三套系统各看各的 故障复盘最头疼的是:告警在 Prometheus 里,调用链在 SkyWalking,日志在 ELK,三套 ID 对不上,定位一个问题要在三个系统间反复横跳。有次一个下单超时,我在 SkyWalking 看到 span 慢,却没法直接拿到那次请求的日志,只能靠时间戳去 ELK 捞,