JVM调优篇-09
1.CPU 过高问题排查?
1.top 命令
使用 top 查询到 cup 过高的进程 PID
top
2.查线程
#根据进程id查询占用高的线程id
ps H -eo pid,tid,%cpu | grep 19235
#查看十六进制的异常线程PID
printf "%x\n" 线程PId
#生成stack文件
jstack -l 3033 > ./3033.stack
#查看线程信息
cat 3033.stack |grep 'xxxx'
#查看使用最耗费cpu的线程堆栈信息
cat stack | grep -i 34670 -C10 --color
3.异常信息
#使用jstack查看进程,并查找指定线程的前100行信息
jstack pid |grep 线程id -A100
4.查看gc信息
jstat -gc pid 1000 100 > gctimes.log
5.使用脚本
sudo sh show-busy-java-threads -p 19235
2.生产环境访问慢?
1.查看错误日志
#最后1000行
tail -1000 xxx.log
如果看到 OOM
2.进容器排查
#获取容器id,并查看容器运行状态
docker stats
#进入容器
docker exec -it 47863d1021e9 /bin/bash
#十进制转十六进制
printf "%x\n" 24306
#找到进程pid
ps -ef |grep java
#查看gc情况,1000ms执行一次,一共执行10次
jstat -gc 进程pid 1000 10
#线程快照,用于排查线程间死锁、死循环、请求外部资源导致的长时间挂起等
jstack 进程pid
#打印出堆内存相关信息
jmap -heap 进程pid
#生成dump文件
jmap -dump:format=b,file=/home/heap.hprof 进程pid
#图形化展示
jhat heap.hprof
3.OOM 问题定位
#可以查看新生代,老年代堆内存的分配大小以及使用情况,看是否本身分配过小
jmap -heap pid
#结果以表格的形式显示存活对象的信息,并按照所占内存大小排序,找到最耗内存的对象
jmap -histo:live 进程pid | more
3.visualVM
在服务器上使用命令导出文件
#检测容器占用的内存和cpu,以及IO情况
docker stats
#进入容器
docker exec -it 容器id bash
#进入home目录
cd /home
#查找进程id
ps -ef|grep java
#生成dump文件
jmap -dump:format=b,file=/home/heap-$(date +%F%n).hprof 进程id
#拷贝文件到宿主机
docker cp ce4830fa74f7:/home/heap-2023-03-23.hprof /home/app/deepexi-dsc-belle-insight-command/
打开 visualVM 软件,导入生成的 dump 文件,主要观测概览,对象,线程三个主要信息
summary:概览
objects:
对象信息
线程:
观测可能出现的死锁信息
在 idea 中使用,需要使用 visualVM 启动应用
4.jvm 调优如何提前调参?
JVM(Java 虚拟机)调优是优化 Java 应用程序性能的关键步骤之一。在实际应用中,提前调整 JVM 参数可以在一开始就为应用程序的性能和稳定性奠定良好的基础。以下是在提前调优 JVM 时应该考虑的一些关键方面:
-
了解应用需求: 在开始调优之前,了解应用程序的性能需求、资源使用情况以及预期的负载情况。这将有助于您根据实际情况选择合适的调优策略。
-
硬件资源: 考虑应用程序运行所需的硬件资源,例如内存、CPU 核数等。这有助于您设置合适的 JVM 参数,以充分利用可用资源。
-
内存设置: 调整堆内存大小是 JVM 调优的一个关键因素。您可以使用
-Xms
(初始堆大小)和-Xmx
(最大堆大小)参数来配置。合理地设置堆内存可以避免频繁的垃圾回收,从而提高性能。 -
垃圾回收: 选择适当的垃圾回收器和调整相关参数是重要的。不同的应用场景可能需要不同的垃圾回收策略,例如 CMS、G1、Parallel 等。
-
线程设置: 根据应用程序的并发需求,调整与线程相关的参数,如线程池大小、并发线程数等。
-
GC 日志和监控: 启用 GC 日志记录以及相关监控工具(如 VisualVM、JConsole)有助于您分析垃圾回收性能,以及发现内存泄漏等问题。
-
PermGen/Metaspace 调整: 对于较老的 JVM 版本,考虑调整 PermGen 空间大小(使用
-XX:PermSize
和-XX:MaxPermSize
参数)。在 Java 8+中,PermGen 已被 Metaspace 取代。 -
健康监控: 配置应用程序的健康监控,以及性能指标采集和报警机制,以便在出现问题时及时做出反应。
-
压力测试: 使用压力测试工具模拟实际负载,以观察应用程序在不同负载下的表现,从而根据测试结果进行调优。
-
逐步调整: 调优过程中建议逐步更改参数,然后进行测试和评估,避免一次性更改过多参数造成不可预测的结果。
调优是一个实验和优化的过程。根据应用程序的性质和需求,您可能需要尝试不同的参数设置并进行测试,以找到最佳的配置。同时,时刻关注最新的 JVM 版本和最佳实践,以确保您的应用程序在性能和稳定性方面保持在最佳状态。
5.如何做 JVM 预热?
通过流量控制来进行预热:
- 利用网关的流量控制功能,根据新服务上线的时间,给予不同的访问权重。这样,服务能够逐步达到正常访问的热度,避免因为流量过大导致服务崩溃。
- 使用 sentinel 等组件进行 warmup 限流,在服务刚上线时,将过高的流量直接拦截,防止对服务造成过大的压力,确保服务的稳定运行。
- spring 的 ribbon 组件策略改造,使其流量控制策略与网关的流量控制策略保持一致。这样,可以更好地协调各个组件之间的流量控制,提高服务的预热效果。
对外服务之前,通过合适的手段提前预热
- 服务开发者可以在编写代码时,设计一个初始化预热模块,该模块在服务启动后会自动执行。
- 在这个初始化模块中,可以编写逻辑来遍历所有的重要访问接口,这样在服务启动后,就能对这些接口进行预热。
- 这种方式能够确保服务在启动后的早期阶段,就对重要的访问接口进行了遍历,提高了服务的响应速度和稳定性。
6.内存溢出查看
docker stats
是 Docker 命令行工具的一部分,用于显示关于运行中容器的实时资源使用情况的统计信息。下面是对 docker stats
命令的中文详细解释:
#查看状态
docker stats
#显示指定容器
docker stats container_name
#显示所有容器(包括停止的)
docker stats --all
#指定格式
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"
docker stats
输出的信息包括以下列:
- CONTAINER:容器的名称或 ID。
- CPU %:CPU 使用率。
- MEM USAGE / LIMIT:内存使用量和限制。
- MEM %:内存使用率。
- NET I/O:网络输入/输出。
- BLOCK I/O:块设备输入/输出。
- PIDS:进程 ID 数量。
如果机器内存充足的情况下,可以适当调大堆内存的大小:
Xmx 不能大于总内存的 3/4
ENV JAVA_OPTS="\
-Xms4g \
-Xmx4g \
-Xmn2g \
-Xss1m \
-XX:SurvivorRatio=8 \
-XX:MaxTenuringThreshold=10 \
-XX:+UseConcMarkSweepGC \
-XX:CMSInitiatingOccupancyFraction=70 \
-XX:+UseCMSInitiatingOccupancyOnly \
-XX:+AlwaysPreTouch \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=:./logs/gc \
-verbose:gc \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-XX:+PrintGCTimeStamps \
-Xloggc:./logs/gc/gc.log \
"
7.如何导出堆内存文件
非容器启动
#第一步:通过jps命令确认jvm进程号
[root@dataprocess-server]# jps -l
19570 customer-datap-1.3.2.jar
10589 sun.tools.jps.Jps
#第二步:通过jmap命令dump堆内存文件到指定目录
[root@dataprocess-server]# jmap -dump:format=b,file=/temp/dump.thprof 19570
Dumping heap to /temp/dump.thprof ...
Heap dump file created
配置OOM自动生成dump文件:
在 Java 虚拟机(JVM)启动时,可以通过设置一些参数来配置 OutOfMemoryError(OOM)时自动生成 Dump 文件。Dump 文件是 JVM 在遇到 OOM 时生成的一种内存转储文件,它包含了 JVM 堆内存的快照,有助于诊断内存溢出问题。
#JVM在发生OutOfMemoryError时生成Heap Dump文件
java -XX:+HeapDumpOnOutOfMemoryError -jar your_application.jar
#指定Heap Dump文件的输出路径
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump/files -jar your_application.jar
#当发生OutOfMemoryError时,执行指定的命令
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump/files -XX:OnOutOfMemoryError="kill -9 %p" -jar your_application.jar
容器启动:
#docker容器的基本信息
docker stats
#这里的PIDS是容器内的PID,基本上没什么用
Dockerfile 配置:
FROM openjdk:latest
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
WORKDIR /home
USER root
ENV PROFILE="dev"
ENV LC_ALL en_US.UTF-8
ENV LANG en_US.UTF-8
ENV JAVA_OPTS="\
-Xms4g \
-Xmx4g \
-Xmn2g \
-Xss1m \
-XX:SurvivorRatio=8 \
-XX:MaxTenuringThreshold=10 \
-XX:+UseConcMarkSweepGC \
-XX:CMSInitiatingOccupancyFraction=70 \
-XX:+UseCMSInitiatingOccupancyOnly \
-XX:+AlwaysPreTouch \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=:./logs/gc \
-verbose:gc \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-XX:+PrintGCTimeStamps \
-Xloggc:./logs/gc/gc.log \
"
ENV PARAMS=""
COPY ./insight-provider/target/*.jar /home/app.jar
EXPOSE 80
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
RUN echo -e 'mkdir -p ./logs/gc && java $JAVA_OPTS -jar ./app.jar --spring.profiles.active=$PROFILE $PARAMS' > entrypoint.sh
ENTRYPOINT ["sh", "entrypoint.sh"]
启动脚本:
#!/usr/bin/env bash
CONTAINER_NAME=insight-command
IMAGE_NAME=xxx.xxx.com/xxx-uat/xxx-xx-xx-insight-command:$1
docker rm -f ${CONTAINER_NAME}
docker rmi ${IMAGE_NAME}
docker pull ${IMAGE_NAME}
docker run -d --name ${CONTAINER_NAME} \
--privileged=true \
-e PROFILE=uat \
-e PARAMS="--logging.level.root=info" \
-w /home \
-p 8090:80 \
-v $PWD/logs:/home/logs \
-v /home/uploads:/home/uploads \
--restart=always ${IMAGE_NAME}
docker logs -f --tail 500 ${CONTAINER_NAME}
- 点赞
- 收藏
- 关注作者
评论(0)