在软件系统中,打日志几乎是每个系统都会使用的行为。不管是用来记录系统健康状态,辅助问题定位,还是收集数据,以便后续数据分析等,日志都起着举足轻重的作用。但是IO的阻塞行为和磁盘的读写速度低下意味着写日志并非是没有代价的。
存在问题
在很多系统中,日志模块用的都是log4j,打日志用的都是同步方法,基本配置如下:
<appender name="appAppender" class="org.apache.log4j.DailyRollingFileAppender"> <!-- <param name="Threshold" value="INFO" /> --> <param name="File" value="/data/applogs/XXXXXXXX/logs/app.log"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="[hotel-order-service]%d [%t] %-5p [%X{HOTEL_LOG_TRACE_ID }] [%c %L] %m%n"/> </layout> </appender>
按照这种配置,日志的输出行为是,在代码层每次调用输出日志接口的时候,这条日志就马上写入到磁盘中,java的io是阻塞的,而当前磁盘的读写性能低下是共知的。我随机找了公司几台服务器用iostat命令查看了每次写磁盘的时间,发现每次io最快也要1.5ms,慢的需要5.7ms!如果某个接口平均需要打5条日志,那么花在打日志上的时间平均就需要10ms。为了减少打日志的时间,最主要的是减少往磁盘写日志的次数,但是如果不能从代码层减少写日志的次数,那么考虑从系统上减少往磁盘写日志的次数。
优化方法&测试
log4j的DailyRollingFileAppender的实现了缓存模式,即合并日志输出的模式,它先把所有的日志都放到一个buffer数组里,如果buffer满了,就把buffer里内容全部写入磁盘,这样可以大大减少调用磁盘的次数。buffer的大小默认是8K(不同的版本默认值可能不一样)。举个例子, 比如你每次要输出1K的日志,那么你输出8次,才会调用1次磁盘io。为了开启合并日志的方式,需要在配置把bufferedIO设置为true,同时也可以根据系统实际情况设置bufferSize来改变buffer数组的大小。
为了验证缓存模式的性能,在某系统中,尝试开启了缓存模式,同时把buffersize设置为50K。下面的配置是开启log4j的缓存:
<appender name="appAppender" class="org.apache.log4j.DailyRollingFileAppender"> <param name="bufferedIO" value="true" /> <!-- 50k为一个写单元 ,可以自己定义--> <param name="bufferSize" value="51200" /> <param name="File" value="/data/applogs/XXXXXXXX/logs/app.log"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="[hotel-order-service]%d [%t] %-5p [%X{HOTEL_LOG_TRACE_ID}] [%c %L] %m%n"/> </layout> </appender>
下面是开启缓存模式前后的响应时间测试:
首先,需要保证服务器环境的一致性,因为不同的服务以及服务器再不同的qps压力下,响应时间也会不同。因此整个的测试数据收集时间再2个小时以内,从公司内部监控系统来看,测试前后的qps基本一致,保证了测试数据的可靠性。然后对比系统响应时间。系统主要的几个接口响应时间基本降低了10-20ms,同时系统的整体平均响应时间降低了4%。说明了开启缓存模式确实有助于减少系统的响应时间,提升系统的性能。
优化日志完整性
那么问题来了:既然开启缓存模式能提高系统,那么log4j为什么没有默认开启缓存模式呢?个人猜测是因为缓存模式需要缓存填充满了才会写入磁盘,但是假如系统突然崩溃了,缓存中残留的数据没有写入磁盘,从而导致日志丢失。而系统崩溃时的日志往往是排查和定位问题的关键,所以大部分情况下日志的完整性更为重要。但是享受缓慢模式的高性能与日志的完整性真的是鱼与熊掌不可兼得吗?log4j的DailyRollingFileAppender确实不可兼得,但是可以自己扩展DailyRollingFileAppender类。使用jvm钩子,在jvm退出前,先把缓存里的日志写到磁盘上。下面是自己扩展的ExtendDailyRollingFileAppender。
public class ExtendDailyRollingFileAppender extends DailyRollingFileAppender{ public ExtendDailyRollingFileAppender() { super(); Runtime.getRuntime().addShutdownHook(new Log4jHockThread()); } public ExtendDailyRollingFileAppender(Layout layout, String filename, String datePattern) throws IOException { super(layout, filename, datePattern); Runtime.getRuntime().addShutdownHook(new Log4jHockThread()); } public QuietWriter getQw() { return super.qw; } private class Log4jHockThread extends Thread { @Override public void run() { QuietWriter qw = ExtendDailyRollingFileAppender.this.getQw(); if (qw != null) { qw.flush(); } } } }
相关推荐
Log4j作为Java领域广泛应用的日志框架,提供了强大的日志记录功能和灵活的配置。本文将深入探讨log4j的配置以及配置文件的详解。** 首先,我们要理解什么是`log4j.properties`文件。这是log4j框架的配置文件,使用...
Log4j是一款广泛使用的Java日志记录框架,它允许开发者按照功能模块或特定需求记录应用程序运行过程中的事件信息。在“log4j按功能保存日志”的场景中,我们通常会利用Log4j的配置灵活性,将不同功能的日志分别写入...
**日志性能优化** 虽然日志对调试和监控非常有用,但过多的日志可能会降低程序性能。因此,合理配置日志级别和使用条件语句(例如,只在调试时启用DEBUG日志)是必要的性能优化策略。 总之,Log4j作为一个强大而...
在Java开发中,日志记录是一项至关重要的任务,它帮助我们追踪程序运行状态,定位问题,以及进行性能...在项目中使用自定义的日志处理方式,能够极大地提高日志的管理和分析效率,为问题排查和性能优化提供有力支持。
日志系统是软件开发中不可或缺的一部分,它能够帮助开发者追踪程序运行状态,定位错误,优化性能,并提供审计和监控功能。在Java编程语言中,`log4j`是一个广泛使用的日志记录框架,因其强大的功能和灵活性而备受...
《深入理解Log4j日志框架》 在Java开发领域,日志系统是不可或缺的工具,它用于记录程序运行过程中的各种信息,帮助开发者在问题出现时定位和解决问题。Log4j作为Apache软件基金会的一个开源项目,是Java世界中最...
在“log4j日志.zip”压缩包中,包含的可能是Log4j的配置文件(如log4j.properties或log4j.xml)。这个文件定义了日志的级别、输出位置和格式。例如: ```properties # log4j.properties 示例 log4j.rootLogger=...
在实际应用中,我们还可以调整Log4j2的异步配置,例如设置队列大小、选择不同的Appender实现(如FileAppender、ConsoleAppender等)以及日志级别,以优化日志性能和存储需求。此外,Log4j2的AsyncAppender利用了LMAX...
Log4j的优点包括可配置性、性能高效以及支持多种输出格式,如控制台、文件、数据库等。在Tomcat中,Log4j可以用来代替默认的日志系统,提供更精细化的日志控制和更好的日志分析能力。 压缩包中的"**log4j....
在深入探讨Log4j日志等级之前,我们首先需要了解Log4j是什么。Log4j是Apache的一个开源项目,用于Java应用程序的日志记录。它提供了一种高度灵活且功能强大的日志解决方案,允许开发者和系统管理员自定义日志级别、...
Log4j是一个广泛使用的Java日志框架,它提供了强大的日志处理功能,包括日志级别控制、自定义日志格式、多路复用等。然而,由于Android系统对第三方库的限制,直接在Android工程中使用Log4j需要一些额外的步骤。本文...
**正文** 日志系统在软件开发中扮演着至关重要的角色,它可以帮助开发者追踪程序...在"log4j日志打印demo"中,你将学习到如何设置Log4j以实现控制台和SD卡(针对Android)的日志输出,从而在实际开发中更加得心应手。
在Android开发中,日志记录是一项非常重要的任务,它帮助开发者追踪应用的运行状态,调试错误,优化性能。本文将详细介绍如何在Android Studio中使用log4j库来记录日志,并实现按照日志文件大小自动滚动的功能,以及...
3. **强大的异步日志功能**:Log4j2提供了基于LMAX Disruptor库的强大异步日志处理能力,显著提高了日志记录的性能。 4. **插件式架构**:Log4j2采用了插件式的软件架构,这使得框架易于扩展而无需修改其核心代码。...
Log4j2相比Log4j 1.x有许多改进,包括性能提升、更丰富的配置选项、异步日志记录支持以及动态日志配置等。 在Tomcat 9中配置SLF4J和Log4j2,你需要以下步骤: 1. **添加依赖**:确保你的项目中包含SLF4J和Log4j2的...
8. **性能优化**:Log4j通过延迟初始化和日志门面模式,可以在不影响性能的情况下,实现高效的日志记录。 9. **MDC与NDC**:Mapped Diagnostic Context (MDC) 和 Nested Diagnostic Context (NDC) 是Log4j提供的两...
Log4j的配置文件通常是`log4j.properties`或`log4j.xml`,在这里你可以设置不同级别的日志输出,例如DEBUG、INFO、WARN、ERROR等。 对于Ibatis,这是一个轻量级的持久层框架,它将SQL语句与Java代码分离,提供了...
Log4j是Apache提供的一款广泛使用的日志框架,它提供了丰富的功能,包括控制日志级别、定制日志格式、支持多种输出方式等。本示例将详细介绍如何使用Log4j来控制指定类或包的日志级别。 首先,我们来理解日志级别的...
Log4j是Apache的一个开源项目,提供了一套强大的日志API,而Log4j2是其升级版,旨在解决Log4j1.x存在的性能问题和设计缺陷。 Log4j2的核心改进在于其引入了全新的API——Log4j 1.2 API,文件`log4j-1.2-api-2.8.2....
通过以上介绍,我们可以看出Log4j日志框架在Java开发中的重要地位,它不仅简化了日志处理,还为故障排查、性能分析和系统监控提供了有力支持。正确使用和配置Log4j,将有助于提升软件质量和维护效率。