Java虚拟机之 XX:+UseGCLogFileRotation 解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
日志服务 SLS,月写入数据量 50GB 1个月
简介: 通常,在生产环境中,我们需要借助 GC Log 来实时检测我们的微服务基于 Java 虚拟机层面活动状态,涉及年轻代、年老代以及全局的垃圾回收 ,只有基于上述方案,我们才能够快速的定位、分析微服务在某一时刻、时间段所呈现的活动轨迹及事件,以便高效解决业务问题。此篇文章来自笔者早期博客,依据实际的项目场景进行总结整理的。因技术群里有朋友在问此方面领域的问题,故再次将其呈现出来。

    通常,在生产环境中,我们需要借助 GC Log 来实时检测我们的微服务基于 Java 虚拟机层面活动状态,涉及年轻代、年老代以及全局的垃圾回收 ,只有基于上述方案,我们才能够快速的定位、分析微服务在某一时刻、时间段所呈现的活动轨迹及事件,以便高效解决业务问题。此篇文章来自笔者早期博客,依据实际的项目场景进行总结整理的。因技术群里有朋友在问此方面领域的问题,故再次将其呈现出来。

    首先,我们来看一下在实际的生产环境中,应用服务中是如何开启日志打印相关开关,具体示例可参考如下所示:


JAVA_OPTS="-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/data/logs/adminMana/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 -XX:GCLogFileSize=512k"

      上述参数为 JDK 9 之前,尤其是 JDK 6/8 的通用型 GC Log 启用参数,针对  JDK 9 之后,以 JDK 11 为例,可尝试通过以下命令行参数启用,具体如下所示:


-Xlog:gc*,gc+ref=debug,gc+age=trace,gc+heap=debug:file=gc%p%t.log:tags,uptime,time:filecount=10,filesize=10m

    本文暂不解析 JDK 11 版本的相关日志规范及相关案例,后续文章将会给出。现在针对 JDK 9 之前版本的核心日志参数进行简要解析,以让大家能够了解下相关参数的作用及场景特点,具体如下:

1、-XX:+PrintGCDetails

        此参数主要定义GC Log 的详细信息。

2、-XX:+PrintGCTimeStamps

        此参数主要定义GC Log 的时间戳信息,通常以“基准时间”形式打印。

3、-Xloggc:/data/logs/adminMana/gc.log

        此参数主要定义GC Log 的存储路径以及所输出的文件名称。

4、-XX:+UseGCLogFileRotation

        此参数主要定义GC Log 的滚动功能,需要进行开启或关闭,其通常基于第3条的    

    -Xloggc 参数展开。

5、-XX:NumberOfGCLogFiles=3

        此参数主要定义滚动日志文件的个数,此参数值必须大于等于1,对应的日志文件

    命名策略为:.0、.1、 ... 、 .n-1等,其中 n 是  

    该参数的值。

6、-XX:GCLogFileSize=512k

        此参数主要定义滚动日志文件的大小,必须大于 8k,当前写日志文件大小超过该    

    参数值时,日志将写入下一个文件,依次类推。

    具体,我们来看一下简单的 GC Log 输出的示例,如下所示:


[administrator@JavaLangOutOfMemory cpu ]% less devopsDemo.log.0.current
Java HotSpot(TM) 64-Bit Server VM (25.271-b09) for bsd-amd64 JRE (1.8.0_271-b09), built on Sep 16 2020 16:54:38 by "java_re" with gcc 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.11.45.5)
Memory: 4k page, physical 4194304k(27404k free)
/proc/meminfo:
CommandLine flags: -XX:GCLogFileSize=524288 -XX:InitialHeapSize=67108864 -XX:MaxHeapSize=1073741824 -XX:NumberOfGCLogFiles=3 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseGCLogFileRotation -XX:+UseParallelGC 
Heap
 PSYoungGen      total 18944K, used 1311K [0x00000007aab00000, 0x00000007ac000000, 0x00000007c0000000)
  eden space 16384K, 8% used [0x00000007aab00000,0x00000007aac47cb0,0x00000007abb00000)
  from space 2560K, 0% used [0x00000007abd80000,0x00000007abd80000,0x00000007ac000000)
  to   space 2560K, 0% used [0x00000007abb00000,0x00000007abb00000,0x00000007abd80000)
 ParOldGen       total 44032K, used 0K [0x0000000780000000, 0x0000000782b00000, 0x00000007aab00000)
  object space 44032K, 0% used [0x0000000780000000,0x0000000780000000,0x0000000782b00000)
 Metaspace       used 2731K, capacity 4490K, committed 4864K, reserved 1056768K
  class space    used 291K, capacity 386K, committed 512K, reserved 1048576K

   上面的 GC 垃圾回收策略基于 JDK 1.8 ,采用默认指定的策略,从上述的简要的 GC Log ,我们可以看出当前的 Java 虚拟机基础环境信息、启动参数以及各个代的相关活动情况。

   通常,在我们开启 GC Log 文件后,日志文件的大小以及数量的分割有时候往往需要给予更多的关注,毕竟,无论从管理角度、信息完整性角度、友好性及其他相关联角度,都需要综合性考虑。因此,基于 -XX:+UseGCLogFileRotation 参数所定义的日志滚动功能,在大多数公司也应用,然而,在实际的生产环境中是否推荐呢?这也是本文所需要探讨的另一方面内容。

    其实,从生产落地场景来说,现在的日志采集、管理及存储框架比较成熟,比如,通过 Agent 将其存储至第三方系统,更有利于对其进行管理与维护。本文着重从应用日志处理角度,基于此参数 -XX:+UseGCLogFileRotation 的相关设置所引入的缺陷以及解决方案。那么,会带来哪些问题呢?具体如下:

1、内容丢失问题

    正如上述参数所描述的场景那样,假设,在我的微服务启动参数中显性定义了以下参数:-XX:+UseGCLogFileRotation、-XX:NumberOfGCLogFiles=3 以及 -XX:GCLogFileSize=20M ,即意味着我们设置了3个文件,应用程序运行一段时间过后就会生成3个日志文件,假如最先定义的是admin-gc.log.0,最近的是admin-gc.log.3,当admin-gc.log.3到达20M以后,日志会重新写入到admin-gc.log.0,admin-gc.log.0之前的内容会被清空掉,从而使得之前的信息不够完整。

2、可读性差

    还是基于上述相同场景,日志目录已生成3个日志文件:admin-gc.log.0 到 admin-gc.log.3,若此时因各种原因进行JVM重启操作,此时 GC Log 会重新从 admin- gc.log.0 开始写入,但是 admin-gc.log.1、admin-gc.log.2、admin-gc.log.3这里面的日志依然为之前旧的日志,新旧日志就混合写入,导致格式模糊,可读性较差,影响用户体验。因此,若要解决这个问题,在重启服务器之前我们需要把老的日志全部迁移到其他目录,以避免重启后日志重新写入问题,影响日志的可读性。

3、不易分析

    基于上述策略,若我们将 GC Log 进行分割后,生成的文件数量较多,通过日志分析平台(例如:类似GC Viewer及相关平台)进行解析时,往往需要导入多份文件,同时,由于各个文件( admin-gc.log.1、admin-gc.log.2、admin-gc.log.3、...)内容之间可能存在时间间断,故上传至分析平台的文件不够完整,导致分析出来的结果参考性意义不大,从而很难为具体的业务场景需求提供优化建议。

4、难以维护

    基于上述参数定义的场景,当前应用服务运行期间的活动日志文件的后缀名会被标记为 .current,假设,应用服务在某一时刻活动所生成的日志文件是 admin-gc.log.3,那么此时,其对应的活动日志文件名会被命名为 admin-gc.log.3.current,如果我们要把不同机器上的 GC Log 文件都集中传送至某一共享主机上去的话,通常我们会借助各种日志同步工具或命令行,例如:Rsyslog 等类似工具,然而,基于此种策略下的命名方式对 类似 Rsyslog 工具来说效率较为低下,影响数据的实时同步。

    综上4点所述为基于 -XX:+UseGCLogFileRotation 参数在 GC Log 分析、存储时所带来的弊端,当然,也有其他潜在的问题,本文暂不讨论。那么,针对如上问题,是否有较好的建议或意见呢?答案:当然有。而且很多,在这里,我们简要介绍 2 种参考方案,具体如下所示:

    1、对接至第三方日志系统

    若我们不对 GC Log 文件进行滚动操作,让其以原生态模式进行日志输出,然后将其转储至第三方日志系统,依据第三方日志系统定义的日志规范。即使我们的应用服务因各种原因进行重启操作,也不会影响 GC Log 的写入,从而避免数据的丢失。

    2、增加时间戳

   若我们想实现 GC Log 文件的切割,我们可以尝试在 GC Log 的文件后缀加上时间戳,当 JVM 重启以后,会生成新的日志文件,新的日志也不会覆盖老的日志,只需要在日志文件名中添加 %t的后缀即可,具体如下示例所示:


-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/data/logs/admin-gc-%t.log

    “%t” 将会在文件名添加时间戳后缀,其生成的通用格式为 YYYY-MM-DD_HH-MM-SS,例如:“admin-gc-2016-01-01_02-13-04.log” 。基于此种策略,我们就轻而易举地避免了基于 -XX:+UseGCLogFileRotation 参数带来的所有的困扰。当然,撇开应用服务本身的特性,如果基于日志切割,目前成熟的方案有很多种,无论是基于哪种,终极目标无非是性能损耗小、易分析、易维护,大家有兴趣的话,可以实践其他方案。

    至此,关于 Java 虚拟中 XX:+UseGCLogFileRotation 参数的相关解析本文到此为止,大家有什么疑问、想法及建议,欢迎留言沟通。

相关文章
|
11天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
39 2
|
15天前
|
Java
轻松上手Java字节码编辑:IDEA插件VisualClassBytes全方位解析
本插件VisualClassBytes可修改class字节码,包括class信息、字段信息、内部类,常量池和方法等。
66 6
|
22天前
|
存储 Java 编译器
Java内存模型(JMM)深度解析####
本文深入探讨了Java内存模型(JMM)的工作原理,旨在帮助开发者理解多线程环境下并发编程的挑战与解决方案。通过剖析JVM如何管理线程间的数据可见性、原子性和有序性问题,本文将揭示synchronized关键字背后的机制,并介绍volatile关键字和final关键字在保证变量同步与不可变性方面的作用。同时,文章还将讨论现代Java并发工具类如java.util.concurrent包中的核心组件,以及它们如何简化高效并发程序的设计。无论你是初学者还是有经验的开发者,本文都将为你提供宝贵的见解,助你在Java并发编程领域更进一步。 ####
|
2天前
|
数据采集 存储 Web App开发
Java爬虫:深入解析商品详情的利器
在数字化时代,信息处理能力成为企业竞争的关键。本文探讨如何利用Java编写高效、准确的商品详情爬虫,涵盖爬虫技术概述、Java爬虫优势、开发步骤、法律法规遵守及数据处理分析等内容,助力电商领域市场趋势把握与决策支持。
|
7天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
7天前
|
Java 测试技术 API
Java 反射机制:深入解析与应用实践
《Java反射机制:深入解析与应用实践》全面解析Java反射API,探讨其内部运作原理、应用场景及最佳实践,帮助开发者掌握利用反射增强程序灵活性与可扩展性的技巧。
|
12天前
|
存储 算法 Java
Java Set深度解析:为何它能成为“无重复”的代名词?
Java的集合框架中,Set接口以其“无重复”特性著称。本文解析了Set的实现原理,包括HashSet和TreeSet的不同数据结构和算法,以及如何通过示例代码实现最佳实践。选择合适的Set实现类和正确实现自定义对象的hashCode()和equals()方法是关键。
23 4
|
15天前
|
Java 编译器 数据库连接
Java中的异常处理机制深度解析####
本文深入探讨了Java编程语言中异常处理机制的核心原理、类型及其最佳实践,旨在帮助开发者更好地理解和应用这一关键特性。通过实例分析,揭示了try-catch-finally结构的重要性,以及如何利用自定义异常提升代码的健壮性和可读性。文章还讨论了异常处理在大型项目中的最佳实践,为提高软件质量提供指导。 ####
|
20天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
|
19天前
|
存储 分布式计算 Java
存算分离与计算向数据移动:深度解析与Java实现
【11月更文挑战第10天】随着大数据时代的到来,数据量的激增给传统的数据处理架构带来了巨大的挑战。传统的“存算一体”架构,即计算资源与存储资源紧密耦合,在处理海量数据时逐渐显露出其局限性。为了应对这些挑战,存算分离(Disaggregated Storage and Compute Architecture)和计算向数据移动(Compute Moves to Data)两种架构应运而生,成为大数据处理领域的热门技术。
40 2

推荐镜像

更多
下一篇
无影云桌面