前言
排查过程
进入容器里
生产应用是跑在docker上的,所以需要先进入到应用里面去,步骤如下
docker ps 找到对应的应用id,比如 zxc
进入容器内部
docker exec -it 7690ea7660bf sh
docker exec -it 7690ea7660bf /bin/bash 有些是这个
查具体的应用 jps 如 1 注:jps -v 可以查看到配置的参数信息
查看gc 情况 jstat -gc 1 1000 10000 # 每1秒打印一次,连续打印10000次
配置gc参数-1
配置如下, 参数是固定的
- JAVA_OPTS 中添加的信息
-XX:+PrintGCDetails -XX:+PrintGCDateStamps 代表gc打印的详情格式
-Xloggc:/opt/admin-gc.log gc日志的位置,不配置默认会放到控制台
java
blade-test:
image: "${REGISTER}/test:${TAG}"
environment:
- TZ=Asia/Shanghai
- JAVA_OPTS=-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/opt/admin-gc.log
privileged: true
restart: always
networks:
- test_net
如果上面的配置无效可以试试下面的
配置gc参数-2
查看你的项目是不是有Dockerfile文件,内容大概如下
java
FROM openjdk:8-alpine
MAINTAINER jiangshaonneg
ADD ./lib/local_policy.jar /usr/lib/jvm/java-1.8-openjdk/jre/lib/security/local_policy.jar
VOLUME /logs
EXPOSE 8803/tcp
RUN echo "java -jar web.jar -Dfile.encoding=UTF-8" > start.sh \
&& chmod 777 start.sh
CMD ./start.sh
如果有的话则直接把参数放到里面去即可,也就是直接放进去即可
java -jar -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/opt/game-app-gc.log web.jar
docker部分操作
docker cp /file mycontainer:/zxc 把文件放入docker内 mycontainer为容器id
docker cp mycontainer:/zxc /file 拿docker文件数据到主机,反过来即可
如果是采用docker方式的就需要停止后重启容器才生效
docker-compose down 停止相应的数据
docker-compose up -d 启动,并且在后台
arthas工具
首页 https://arthas.aliyun.com/doc/
基本命令,具体看文档
dashboard 面板
jvm 内存 --- 可以看到配置的参数生效没, 放在最上面了,在INPUT-ARGUMENTS中
thread 线程
jvm 参数查看是否生效
剩下的就是拿日志了,怎么拿就是自己指定的,这里就不细说了
分析日志
分析网址
我采用的是gceasy https://gceasy.io/ 可以大概知道哪些存在哪些问题,基本都是图形化的,下面说下几个相对重要的查看指标
关键性能指标
吞吐量是越高越好,这里基本接近了100,所以不会有太多问题了
延迟是越短越好,这里稍微偏高,可能需要了解下啥原因
GC 数据
可以结合业务分析是否不合理
GC原因(重要)
这里可以很明显的看到大部分gc都是分配失败,很有可能就是因为内存分配不合理导致的,至于每种错误是什么,可以参考源码的返回,如下
java
const char* GCCause::to_string(GCCause::Cause cause) {
switch (cause) {
case _java_lang_system_gc:
return "System.gc()";
case _full_gc_alot:
return "FullGCAlot";
case _scavenge_alot:
return "ScavengeAlot";
case _allocation_profiler:
return "Allocation Profiler";
case _jvmti_force_gc:
return "JvmtiEnv ForceGarbageCollection";
case _gc_locker:
return "GCLocker Initiated GC";
case _heap_inspection:
return "Heap Inspection Initiated GC";
case _heap_dump:
return "Heap Dump Initiated GC";
case _wb_young_gc:
return "WhiteBox Initiated Young GC";
case _wb_conc_mark:
return "WhiteBox Initiated Concurrent Mark";
case _wb_full_gc:
return "WhiteBox Initiated Full GC";
case _no_gc:
return "No GC";
case _allocation_failure:
return "Allocation Failure";
case _tenured_generation_full:
return "Tenured Generation Full";
case _metadata_GC_threshold:
return "Metadata GC Threshold";
case _metadata_GC_clear_soft_refs:
return "Metadata GC Clear Soft References";
case _cms_generation_full:
return "CMS Generation Full";
case _cms_initial_mark:
return "CMS Initial Mark";
case _cms_final_remark:
return "CMS Final Remark";
case _cms_concurrent_mark:
return "CMS Concurrent Mark";
case _old_generation_expanded_on_last_scavenge:
return "Old Generation Expanded On Last Scavenge";
case _old_generation_too_full_to_scavenge:
return "Old Generation Too Full To Scavenge";
case _adaptive_size_policy:
return "Ergonomics";
case _g1_inc_collection_pause:
return "G1 Evacuation Pause";
case _g1_humongous_allocation:
return "G1 Humongous Allocation";
case _dcmd_gc_run:
return "Diagnostic Command";
case _last_gc_cause:
return "ILLEGAL VALUE - last gc cause - ILLEGAL VALUE";
default:
return "unknown GCCause";
}
ShouldNotReachHere();
}
最后一个就是网站的好处了,他会建议你一些优化点,在最上面建议里
建议(重要,修改建议)
可以看到几个明显的问题
没有开启指针压缩
没有初始化元空间大小分配
等
结语
到此gc日志的基本分析就结束了, 可以参考上面美团的文章进行了更全面的分析建议,这里只是初步的一些分析流程