发布网友 发布时间:2024-09-15 08:15
共1个回答
热心网友 时间:2024-10-05 03:18
需求无论是在springboot还是springcloud项目中,随着应用的不断增多,JVM参数的统一管理的重要性就会凸显出来,否则你可能会遇到几个问题:
Java进程出现性能问题,无GC日志支撑提供重要信息;
OOM异常频发,无法通过dump文件进行分析定位;
JVM堆内存设置规格不一致,被动等待出问题时发现;
作为运维,虽然没有超强的能力去最终的定位、分析、排查问题,但并不意味着我们就可以袖手旁观,那么我们能做什么呢?
首先,我们要知道Java进程默认参数启动并不会打印某些我们需要的日志,而是需要我们按需去设置的。
其次,即使开启了相应的日志参数,其统一输出位置就成了我们需要面对的问题,毕竟我们不希望满盘搜文件,浪费不必要的时间。
最后,各种个性化的JVM参数,无益于运维对数量为百、千级别进程的有效管理。
此时统一的Java进程管理规范就可以发挥作用,通过标准化部署,Java使用统一的JVM参数运行,一旦某个应用出现异常,我们可以快速收集各种异常日志提供给研发进一步定位问题。
最终目标是,运维能提供给研发的有效信息,肯定是排除了因环境差异、参数配置差异等这些低级别干扰因素的,这样才能保证运维和研发的快速定位。
进程规范1.GC日志GC日志是用来描述JAVA虚拟机垃圾回收情况,主要用来快速定位潜在的内存故障和性能瓶颈。默认情况下是关闭的,我们需要通过参数设置启用。
参数格式如下:
-XX:+PrintGC输出简要GC日志-XX:+PrintGCDetails输出详细GC日志#gc.log输出到统一的日志目录-Xloggc:/data/logs/gc.log输出GC日志到文件-XX:+PrintGCTimeStamps输出GC的时间戳(以JVM启动到当期的总时长的时间戳形式)-XX:+PrintGCDateStamps输出GC的时间戳(以日期的形式,如2013-05-04T21:53:59.234+0800)-XX:+PrintHeapAtGC在进行GC的前后打印出堆的信息-XX:+PrintReferenceGC打印年轻代各个引用的数量以及时长2.dump文件dump文件是Java进程出现OOM时自动生成的文件,通过此文件可以定位进程发生OOM的位置。可配置参数自动生成dump文件。
-XX:+HeapDumpOnOutOfMemoryError#dump文件输出到统一的日志目录-XX:HeapDumpPath=/data/logs/HeapDumpOnOutOfMemoryError.dump3.堆内存堆内存设置是我们最容易设置混乱的参数,但对于我们标准化交付的服务器,虽不至于所有的应用使用完全一致的堆内存参数,但是大多数情况下是可以统一的。
-Xms2048m-Xmx2048m-XX:MaxPermSize:256m至此,常见的JVM参数设置完毕,由于这些参数多和开发定位问题有关,因此我们在此只是将其作为进程管理规范的内容进行讲解,而不是研究其具体作用。但你以为我们的工作就到此为止了吗?
我们还可以通过设置JVM环境变量来实现部分扩展功能,因此也需要将环境变量作为进程管理规范的一部分。
4.JVM环境变量环境变量便于运维能够灵活控制java进程运行的参数,这样可以和自动化相结合,实现应用的统一部署,有效避免更改配置文件的动作。
关于环境变量的定义,需要结合各自的生产环境特性来自行定义,我这面的定义的变量如下:
#应用名-Dapp.name=test#环境区分-Denv=prod或uat或stg#临时文件目录-Djava.io.tmpdir=/data/tmpdir其中比较重要的是-Denv=xxx,通过在各个环境预设此变量,可实现不同环境配置文件的绑定。例如:在springcloud项目中可以和各环境的配置中心调用进行关联。
其他环境变量大家可以和研发协商按需灵活添加。
按规范管理1.统一管理通过以上各参数的简单讲解,我们有了一套比较固定且完整的JVM参数,稳定性和灵活性兼顾,也便于我们后续的管理。
-server-Xms2048m-Xmx2048m-XX:MaxPermSize:256m-Dapp.name=test-Denv=prod-Djava.io.tmpdir=/data/tmpdir-Xloggc:/data/logs/gc.log-XX:+PrintGC-XX:+PrintGCDetails-XX:+PrintGCTimeStamps-XX:+PrintGCDateStamps-XX:+PrintHeapAtGC-XX:+PrintReferenceGC-Dsun.jnu.encoding=UTF-82.supervisor守护管理随着JVM启动参数的尘埃落定,如何启动Java进程就是我们接下来要面对的问题。我们经常使用的后台启动方式有以下几种:
nohup
screen
supervisor
其中nohup、screen都需要配合脚本,才能更友好的管理,因此我还是选择supervisor作为java应用的守护进程。
#1.安装yuminstallsupervisorsystemctlenablesupervisordsystemctlstartsupervisord#2.配置vim/etc/supervisord.d/test.ini[program:test];启动用户user=work;程序启动命令command=java-server-Xms2048m-Xmx2048m-XX:MaxPermSize:256m-Dapp.name=test-Denv=prod-Djava.io.tmpdir=/data/tmpdir-Xloggc:/data/logs/gc.log-XX:+PrintGC-XX:+PrintGCDetails-XX:+PrintGCTimeStamps-XX:+PrintGCDateStamps-XX:+PrintHeapAtGC-XX:+PrintReferenceGC-Dsun.jnu.encoding=UTF-8-jartest.jarnumprocs=1;程序启动目录directory=/App/java_app/test;在supervisord启动时自启动autostart=true;程序异常退出后自动重启,可选值:[unexpected,true,false],默认为unexpectedautorestart=true;启动10秒后没有异常退出,就表示进程正常启动了startsecs=10;启动失败自动重试次数startretries=3#3.更新配置文件,更新配置文件并重启supervisorctlupdate#4.重载配置文件,注意reload会导致supervisor重启,所管理的进程会重启supervisorctlreload#5.查看状态supervisorctlstatus#6.启动supervisorctlstarttest在此需要注意的是supervisor并不能托管任何进程,而只适合管理运行于前台的进程(如java直接启动),对于运行后台daemon的进程(如tomcat),supervisorctlstatus会报错"BACKOFFExitedtooquickly(processlogmayhavedetails"。
总结总结出一份用于运维过程中各个环境的JVM参数其实很简单,关键在于我们是否意识到了一份进程管理规范的重要性,怎样和当前的自动化水平来结合,实现其最终的价值。而对于只负责躺平的规范来说,我们做的这些工作意义不大。
作者:木讷大叔爱运维