个人网站建设视频教学,太原seo关键词排名优化,wordpress 中字体插件,珲春市建设局网站周三下午#xff0c;正在摸鱼#xff0c;突然钉钉群里炸了#xff1a;[告警] 订单服务 POD重启
[告警] 订单服务 POD重启
[告警] 订单服务 POD重启3个Pod连续重启#xff0c;打开监控一看#xff0c;内存直接打满然后被K8s杀掉了。
经典的OOM。
现象
服务#xff1a;订单…周三下午正在摸鱼突然钉钉群里炸了[告警] 订单服务 POD重启 [告警] 订单服务 POD重启 [告警] 订单服务 POD重启3个Pod连续重启打开监控一看内存直接打满然后被K8s杀掉了。经典的OOM。现象服务订单服务JavaSpring Boot部署K8s3个Pod每个限制4G内存现象内存缓慢增长到达4G后被OOM Kill频率每隔2-3小时重启一次第一反应加内存领导说内存不够就加嘛。我…加内存治标不治本得找到根因。排查过程1. 先看GC日志# JVM参数里加上GC日志-XX:PrintGCDetails -XX:PrintGCDateStamps -Xloggc:/logs/gc.log等了一个小时服务挂了捞出GC日志[Full GC (Allocation Failure) 3800M-3750M(4096M), 5.234 secs] [Full GC (Allocation Failure) 3780M-3760M(4096M), 5.567 secs] [Full GC (Allocation Failure) 3790M-3785M(4096M), 6.012 secs]Full GC后内存几乎没释放说明有内存泄漏有东西一直占着不放。2. dump内存在容器里加了个脚本OOM前自动dump# JVM参数-XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/logs/heap.hprof但K8s的OOM Kill太快了还没来得及dump就被杀了。换个方式手动dump# 找到Java进程PIDjps# 手动dump等内存涨到3G左右时执行jmap -dump:formatb,file/logs/heap.hprofpiddump出来一个3G的文件。3. 分析heap dump把文件拷到本地用MATMemory Analyzer Tool打开。Leak Suspects Report: Problem Suspect 1: 256,789 instances of com.xxx.OrderDTO 占用内存2.1 GB (54%)25万个OrderDTO对象这订单量也没这么大啊。点进去看引用链java.util.concurrent.ConcurrentHashMap - com.xxx.cache.LocalCache - OrderDTO (256789 instances)LocalCache本地缓存。4. 定位代码// LocalCache.javapublicclassLocalCache{privatestaticfinalMapString,OrderDTOcachenewConcurrentHashMap();publicstaticvoidput(StringorderId,OrderDTOorder){cache.put(orderId,order);}publicstaticOrderDTOget(StringorderId){returncache.get(orderId);}// 没有remove方法// 没有过期机制// 没有大小限制}经典错误只往缓存里放不清理。一查代码提交记录是3个月前一个同事为了优化性能加的从那之后这个服务就开始间歇性OOM。5. 修复方案一直接删掉这个缓存最简单方案二换成带过期的缓存// 用Caffeine替代privatestaticfinalCacheString,OrderDTOcacheCaffeine.newBuilder().maximumSize(10000)// 最多1万条.expireAfterWrite(5,TimeUnit.MINUTES)// 5分钟过期.build();publicstaticvoidput(StringorderId,OrderDTOorder){cache.put(orderId,order);}publicstaticOrderDTOget(StringorderId){returncache.getIfPresent(orderId);}上线后内存稳定在1.5G左右再也没OOM过。JVM参数调优趁这个机会把JVM参数也优化了一下。之前的配置-Xms2g -Xmx4g# 就这两个参数...优化后的配置# 堆内存-Xms4g -Xmx4g# 初始和最大一样避免动态调整-XX:NewRatio2# 年轻代:老年代 1:2# GC选择JDK11推荐G1-XX:UseG1GC -XX:MaxGCPauseMillis200# 目标停顿时间200ms-XX:G1HeapRegionSize8m# Region大小# 元空间-XX:MetaspaceSize256m -XX:MaxMetaspaceSize256m# GC日志-Xlog:gc*:file/logs/gc.log:time,level,tags:filecount5,filesize100m# OOM时dump-XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/logs/# 容器感知JDK8u191-XX:UseContainerSupport -XX:MaxRAMPercentage75.0# 使用容器内存的75%监控指标加了几个关键监控# Prometheus指标-jvm_memory_used_bytes-jvm_gc_pause_seconds_sum-jvm_gc_pause_seconds_count-jvm_classes_loaded_classes_total设置告警老年代使用率 80% 持续5分钟Full GC 频率 1次/分钟GC停顿时间 1秒排查工具汇总场景工具命令查看堆内存jmapjmap -heapdump内存jmapjmap -dump:formatb,fileheap.hprof分析dumpMAT图形界面实时监控jstatjstat -gcutil 1000查看线程jstackjstack在线分析Arthasdashboard/heapdumpArthas神器推荐用Arthas在线诊断特别方便# 下载启动curl-O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar# 选择要attach的进程后# 查看堆内存dashboard# 查看最占内存的对象heapdump --live /tmp/heap.hprof# 查看某个类的实例数sc -d com.xxx.OrderDTO vmtool --action getInstances --className com.xxx.OrderDTO --limit10# 查看方法调用watchcom.xxx.LocalCache put{params, returnObj}-x2远程调试这次OOM排查还好在公司能直接连到服务器。如果在家收到告警K8s集群在公司内网怎么办之前的方案是远程专线但经常断而且手机上操作kubectl很难受。后来用星空组网把电脑和跳板机组到一起在家也能kubectl进容器排查了。总结这次OOM排查的经验步骤工具/方法1. 确认OOM监控告警、GC日志2. dump内存jmap / HeapDumpOnOutOfMemoryError3. 分析dumpMAT / jhat4. 定位代码引用链分析5. 修复上线代码修改6. 加固监控JVM监控指标常见的内存泄漏原因缓存无限增长本次静态集合持续添加未关闭的连接/流ThreadLocal使用不当监听器未注销最后写缓存的时候一定要想清楚什么时候过期最大存多少怎么清理不然就等着半夜被电话叫醒吧。有JVM相关问题欢迎评论区交流。