手机网站优化排名,龙华网络推广公司,上海集团平台app,用家用电脑建设网站线上出现问题首先应该做什么#xff0c;不是解决问题#xff0c;而是先恢复系统#xff0c;把损失降到最小#xff0c;有机会的话保留日志等数据用于后期问题复盘分析。解决问题可以后期慢慢复现排查#xff0c;而线上用户的体验则不能多耽误一分一秒#xff0c;任何线上…线上出现问题首先应该做什么不是解决问题而是先恢复系统把损失降到最小有机会的话保留日志等数据用于后期问题复盘分析。解决问题可以后期慢慢复现排查而线上用户的体验则不能多耽误一分一秒任何线上问题的解决都应以用户为主。
出现问题的解决方法重启扩容回滚降级限流
高并发高流量系统的设计处理缓存降级限流
1. GC问题
收到预警后查看JVM监控确定问题的时间点内存FGC频率CPU使用率线程数等。 如果频率规律内存起伏正常初步排除内存泄漏。了解该时间点之前有没有上线升级等操作初步确定范围。了解JVM的参数设置是否合理。导出需要的堆栈文件条件可以的话也可以使用jmapjstack等基本命令。针对大对象或者长生命周期对象导致的FGC可通过 jmap -histo 命令并结合dump堆内存文件作分析 定位到可疑对象通过可疑对象定位到具体代码再次分析。CPU使用率高 , top命令查询cpu使用率高的进程 top -Hp pid 定位进程中高使用率线程 jstack tid获 取栈信息,如果垃圾回收线程(VM Thread) 说明GC导致cpu使用率高问题在GC上如果不是可以定位runnable中业务线程是否有死循环出现或者耗时计算正常情况会出现我们工程相关代码Full GC 次数过多如果没有大对象产生判断一下是不是有显示调用System.gc()的记录。Full GC 不多CPU使用率不高系统慢分析jstack获取栈信息中如下关键字 Deadlock 死锁 waiting for monitor entry 等待获取锁waiting on condition 等待某个资源或条件in Object.wait定位到具体代码行优化处理。对于一些阻塞性的操作这种操作不一定每次都能复现可以通过压力测试的方式放大阻塞效果 定位阻塞点
2. 慢查询优化
先运行看看是否真的很慢注意设置SQL_NO_CACHEwhere条件单表查锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起单表每个字段分别查询看哪个字段的区分度最高explain查看执行计划是否与2预期一致从锁定记录较少的表开始查询order by limit 形式的sql语句让排序的表优先查了解业务方使用场景加索引时参照建索引的几大原则观察结果不符合预期继续从1分析
3. 内存使用率报警
3.1 内存泄漏问题-fastJson使用不当导致的内存泄漏
2020-05-31 20:40左右我这边收到任务服务告警内存使用率超过75%
同时查看任务服务ump监控tp99出现极值高达17秒
紧接着查看JVM监控发现在20:40触发了一次Full GC而这次Full GC执行长达十几秒故tp99出现极值是FullGC导致。 继续观察GC后堆内存使用情况发现无论Young GC还是Full GC执行后仍让留有3个G的堆内存而且每次都是堆内存即将打满后触发的GC可以说GC执行的“很不顺利”。问题暴露后为不影响接口性能及线上服务暂时先将容器重启了堆内存被重置。
持续观察线上服务内存
观察近期内存使用率情况时间跨度为一个月发现随着时间的推移即使有GC内存使用率依然逐步增高早晚会触发下一次内存告警
观察近期GC情况发现随着时间的推移Yong GC后剩余堆内存在逐步递增如下图
6月10左右GC后剩余堆内存在300M左右
10天后6月20日GC后剩余堆内存普遍在1.7个G即随着时间推移GC后剩余的堆内存越来越多
问题定位
查看JVM参数配置
年轻代Eden区(1879M) S0(85M) S1(84M) 2048M
老年代3072M
垃圾收集器用的是Java8默认的注重吞吐量的并行收集器
利用MAT工具查看堆内存对象使用情况
(a)首先找到java进程ID
(b)利用jmap命令打印dump二进制日志
jmap -dump:formatb,file/export/Logs/Domains/union-content- api.jd.local/server1/logs/dump.log pid
将dump日志输出到日志目录再利用jdos的容器目录查询将日志下载下来日志比较大压缩后再下载
(c)利用MAT工具查看堆内存使用情况
MATMemory Analyzer Tool是一个java堆内存分析工具可有效帮助我们排查内存泄漏问题
前面dump日志有4个G。。。 因日志过大需要修改MAT的MemoryAnalyzer.ini配置文件-Xmx5120m否则无法分析
MAT工具导入dump日志分析后发现fastJson的IdentityHashMap的Entry数组占用了绝大部分堆内存。
查看IdentityHashMap源码是一个线性探测模式一个简单的Hash表只不过他的key是由System.identityHashCode(key)生成即一个对象对应一个唯一key且与对象的HashCode方法不同无法被重写。 百度查fastJosn的IdentityHashMap内存泄漏相关资料发现有很多类似问题
比如这篇文章https://www.cnblogs.com/liqipeng/p/11665889.html
通过博客及源码发现fastjson在处理泛型的反序列化时ParserConfig类会反对序列化的目标类的泛型对象做缓存而缓存容器正是IdentityHashMapkey则是反射包里的type对象.
说到fastjson处理泛型的反解析一下子就想到任务服务的redis缓存优化正是4月份上线的功能
下面这段代码是程序中触发内存泄漏的代码它主要是将从redis取出的json字符串反解析成带泛型的java对象。
每次反解析都会实例化ParameterizedType对象ParameterizedType继承自Type接口
在JSONObject.parseObject方法中ParameterizedType对象会被作为Map的key缓存在IdentityHashMap中故随着这段代码调用次数的增加越来越多的对象被实例化并被IdentityHashMap缓存起来而不被GC释放故内存使用率越来越高。 参考https://github.com/alibaba/fastjson/issues/1418以及TypeReference的用法
修改为或者将ParameterizedType对象做缓存也行 参考资料
【MAT工具使用介绍】java学习-【转】使用Eclipse MAT查找内存泄漏工具介绍_invalid hprof file header. (java.io.ioexception)-CSDN博客
【fastjson反序列化使用不当导致内存泄露】 https://www.cnblogs.com/liqipeng/p/11665889.html
【“com.alibaba.fastjson”遇到的内存泄漏问题】“com.alibaba.fastjson”遇到的内存泄漏问题 - 简书
【GitHub-IssueparseObject是否存在内存泄漏情况】https://github.com/alibaba/fastjson/issues/1418
【GitHub-WikiTypeReference使用】https://github.com/alibaba/fastjson/wiki/TypeReference
netty在recyler使用FastThreadLocalThread内存溢出
由于内存的 allocate 和 release 不再同一个线程造成的内存泄漏。
https://www.cnblogs.com/405845829qq/p/6255931.html 3.2 内存泄漏问题-从ThreadLocalMap分析ThreadLocal使用不当导致内存泄漏
首先我们先看看ThreadLocalMap的类图在前面的介绍中我们知道ThreadLocal只是一个工具类他为用户提供get、set、remove接口操作实际存放本地变量的threadLocals调用线程的成员变量也知道threadLocals是一个ThreadLocalMap类型的变量下面我们来看看ThreadLocalMap这个类。在此之前我们回忆一下Java中的四种引用类型相关GC只是参考前面系列的文章(JVM相关)
①强引用Java中默认的引用类型一个对象如果具有强引用那么只要这种引用还存在就不会被GC。
②软引用简言之如果一个对象具有弱引用在JVM发生OOM之前即内存充足够使用是不会GC这个对象的只有到JVM内存不足的时候才会GC掉这个对象。软引用和一个引用队列联合使用如果软引用所引用的对象被回收之后该引用就会加入到与之关联的引用队列中
③弱引用这里讨论ThreadLocalMap中的Entry类的重点如果一个对象只具有弱引用那么这个对象就会被垃圾回收器GC掉(被弱引用所引用的对象只能生存到下一次GC之前当发生GC时候无论当前内存是否足够弱引用所引用的对象都会被回收掉)。弱引用也是和一个引用队列联合使用如果弱引用的对象被垃圾回收期回收掉JVM会将这个引用加入到与之关联的引用队列中。若引用的对象可以通过弱引用的get方法得到当引用的对象呗回收掉之后再调用get方法就会返回null
④虚引用虚引用是所有引用中最弱的一种引用其存在就是为了将关联虚引用的对象在被GC掉之后收到一个通知。不能通过get方法获得其指向的对象
分析ThreadLocalMap内部实现
上面我们知道ThreadLocalMap内部实际上是一个Entry数组我们先看看Entry的这个内部类
当前ThreadLocal的引用k被传递给WeakReference的构造函数所以ThreadLocalMap中的key为ThreadLocal的弱引用。当一个线程调用ThreadLocal的set方法设置变量的时候当前线程的ThreadLocalMap就会存放一个记录这个记录的key值为ThreadLocal的弱引用value就是通过set设置的值。如果当前线程一直存在且没有调用该ThreadLocal的remove方法如果这个时候别的地方还有对ThreadLocal的引用那么当前线程中的ThreadLocalMap中会存在对ThreadLocal变量的引用和value对象的引用是不会释放的就会造成内存泄漏。考虑这个ThreadLocal变量没有其他强依赖如果当前线程还存在由于线程的ThreadLocalMap里面的key是弱引用所以当前线程的ThreadLocalMap里面的ThreadLocal变量的弱引用在gc的时候就被回收但是对应的value还是存在的这就可能造成内存泄漏(因为这个时候ThreadLocalMap会存在key为null但是value不为null的entry项)。
总结THreadLocalMap中的Entry的key使用的是ThreadLocal对象的弱引用在没有其他地方对ThreadLoca依赖ThreadLocalMap中的ThreadLocal对象就会被回收掉但是对应的不会被回收这个时候Map中就可能存在key为null但是value不为null的项这需要实际的时候使用完毕及时调用remove方法避免内存泄漏。