文章 587
评论 5
浏览 233546
线程池用了LinkedBlockingQueue没设容量,把整台机器搞OOM了

线程池用了LinkedBlockingQueue没设容量,把整台机器搞OOM了

凌晨运维群炸了,一条告警:订单服务响应超时率飙到 80%,紧接着 JVM 挂掉,Pod 重启。 上去一看,OOM 前老年代被打满了。heap dump 里最大的对象是一个 LinkedBlockingQueue,里面堆了 300 多万个任务对象,光队列就占了将近 2G。 翻代码,线程池是这么配的: ExecutorService executor = new ThreadPoolExecutor( 10, // corePoolSize 20, // maximumPoolSize 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>() // ← 没设容量,默认 Integer.MAX_VALUE ); 10 个核心线程忙不过来的时候,任务进了队列。队列没有上限,上游的定时任务每 10 毫秒投递一个任务,半小时就塞了 300 万个。 线程在消费,队列在膨胀——消费速度跟不上生产速度,OOM 只是时间问题。 这就是 LinkedBlockingQueue 最坑人的地方:默认构造是无界的。 一、为什么无界队列是定时炸弹 new L....

Redis 内存碎片化治理:used_memory 低却 OOM?内存碎片整理 + 对象池优化

Redis 内存碎片化治理:used_memory 低却 OOM?内存碎片整理 + 对象池优化

朋友公司的 Redis 集群监控上 used_memory 才 4GB,但 used_memory_rss 已经到了 8GB——是 used 的两倍。运维加了内存,过两个月又一样。最离谱的是有一次 used_memory 只有 2GB,Redis 却报了 OOM。排查发现内存碎片率 3.5,8GB 的物理内存被碎片占了一半多。 这就是 Redis 的内存碎片问题。used_memory 是你存进去的有用数据,used_memory_rss 是 Redis 实际向操作系统申请的内存。两者之间的差,就是碎片。 今天聊聊怎么用 Redis 自带的内存碎片整理和对象复用,把碎片率降到 1.1 以下。 碎片怎么来的 Redis 的内存分配是 jemalloc 管理的。当你反复写入和删除不同大小的 Key,就会出现这样的场景: 内存布局(简化): |AAAA| 空闲 |BB| 空闲 |CCCC| 空闲 |DD| 空闲 |... 删掉的 Key 留下的空隙不够大,放不下新的 Key。新 Key 只能往后申请新内存。结果就是 used 没涨多少,rss 一直涨。 碎片率计算公式: mem_fra....

SpringBoot + 文件上传 OOM 防护:大文件直接读内存?我们用流式处理防崩溃。

SpringBoot + 文件上传 OOM 防护:大文件直接读内存?我们用流式处理防崩溃。

一、文件上传 OOM 的痛点 上个月,我的一个电商系统客户遇到了严重的生产事故:系统在处理用户上传的商品图片时,突然出现了 OOM(内存溢出)崩溃。 "我们的系统每天都要处理大量的图片上传,"客户焦急地说,"昨天有用户上传了几个 100MB 以上的大文件,直接导致服务器内存溢出,整个服务都崩溃了。" 我查看了他们的代码,发现问题确实很严重: 使用了 Spring Boot 默认的文件上传配置 上传的文件直接存储在内存中 没有对文件大小进行合理限制 没有使用流式处理,而是一次性读取整个文件 系统内存只有 4GB,根本无法处理大文件 更关键的是,他们根本不知道有多少用户正在上传大文件,也无法及时发现和处理这种内存风险。 二、传统方案的局限性 1. 默认配置上传 使用 Spring Boot 默认的文件上传配置。 @PostMapping("/upload") public String upload(@RequestParam("file") MultipartFile file) throws IOException { byte[] bytes = file.getBytes();....

服务端开发博客:后端架构、高并发、性能优化与微服务实战教程