文章目录
- 一、高并发压测故障
- 二、JVM 调优
- 1. 堆内存调优
- 2. 堆外内存调优
一、高并发压测故障
每次在大促之前,我们都需要对服务进行压测。而在压测期间,突然爆发了红灯告警,订单量直接少了一半,这是一次很严重的压测故障。首先看一下压测是怎么进行的:
① 正常的线上流量分布应该是 A、B 机房各承担一半的线上流量。
② 在压测之前,我们需要把全部流量都统一打到一个机房里面去,也就是让 B 机房承担整个线上流量。
③ A 机房腾空后,我们把压测流量打入 A 机房,在 A 机房统一做压测的操作,这样就不会影响线上的流量。
这次事故发生的节点其实并不是在压测的时候,而是在压测完毕之后,我们把原来 A 机房的流量重新打回到 A 机房的时候,出现了一个订单量环比下降的警告。
这时候的第一反应是,快速还原到之前没有出问题的状态,当切换到之前的分组后,发现告警消失。这里就有了一个问题,为什么在压测的时候没有告警,而是在把流量切回来的时候发生告警了呢?
订单那边的反馈说,A 机房打过去的流量请求都是带有一个压测标志的,而带有压测标记的订单都会被丢弃掉。把压测流量和线上流量做一个区分,其实在底层代码中是用了一个 ThreadLocal 定义了一个压测标识,但是由于我们的失误,压测时只 set 了压测标识,但是没有 remove,那么就导致这个压测标志永远不会消失,即使撤回了压测流量,但线程池依然是带有压测标志的一个状态,这就造成了线程池的污染,当再次把新的流量打进去的时候会被认为是压测流量,导致打进去的订单请求全部被丢弃掉。 所以 set 之后,一定要 remove。
二、JVM 调优
我还是想补充一下堆内存和堆外内存出现 OOM 时的调优过程。
1. 堆内存调优
① 首先,把出现问题的机器从负载均衡的环境里面拿出来;
② 然后通过 jps 命令查到 GC 的进程号;
③ 通过 jmap -dump 命令将它的堆快照 dump 出来;
④ 再使用 TCP copy 命令复制一份出来,一份给生产环境,一份给测试环境,我们在测试环境里面分析参数并修改业务代码。
2. 堆外内存调优
这里的堆外内存说的是方法区,我们都知道方法区里面存储着类信息,方法区不断上涨,说明代码在不断地生成类,从而导致频繁的 major GC。
① verbose: class 能够打印出所有的类加载信息;
② 找到频繁被加载的那个类,并在 idea 里面进行全局搜索;
③ 我们发现每次请求都会编译生成类,导致方法区不断膨胀;
④ 原因是并没有做缓存,经过缓存改造后,问题得以解决。