Spring Log4j2的异步日志

用于低延迟日志记录的异步日志记录器

异步日志记录可以通过在单独的线程中执行I/O操作来提高应用程序的性能。Log4j 2在这方面做了许多改进。

异步记录器是Log4j 2中的新添加的。它们的目标是从对Logger.log的调用尽快返回到应用程序。您可以选择让所有记录器都是异步的,还是混合使用同步和异步记录器。使所有记录器都异步将提供最佳性能,而混合则提供更多的灵活性。

LMAX粉碎机技术。异步日志记录器在内部使用Disruptor(一种无锁的线程间通信库),而不是队列,从而获得更高的吞吐量和更低的延迟。

作为Async logger工作的一部分,异步追加器已得到增强,可以在批处理结束时(队列为空时)刷新到磁盘。这将产生与配置"immediateFlush=true"相同的结果,即所有接收到的日志事件始终在磁盘上可用,但更有效,因为它不需要对每个日志事件都访问磁盘。(Async Appenders在内部使用ArrayBlockingQueue,不需要在类路径上使用disruptor jar。)

权衡

尽管异步日志记录可以带来显著的性能优势,但在某些情况下,您可能希望选择同步日志记录。本节描述异步日志记录的一些利弊。

好处

更高的峰值吞吐量。使用异步日志记录器,应用程序可以以同步日志记录器速率的6 - 68倍记录消息。

对于偶尔需要记录消息突发的应用程序来说,这尤其有趣。异步日志记录可以通过缩短记录下一条消息之前的等待时间来帮助防止或抑制延迟高峰。如果队列大小配置得足够大,可以处理突发事件,那么异步日志记录将有助于防止应用程序在活动突然增加时落后(同样多)。

更低的日志响应时间延迟。响应时间延迟是对Logger.log的调用在给定工作负载下返回所需的时间。异步日志记录器的延迟始终低于同步日志记录器,甚至低于基于队列的异步追加器。

缺点

错误处理。如果在日志记录过程中发生问题并抛出异常,则异步日志记录器或appender不太容易将此问题通知应用程序。这可以通过配置ExceptionHandler部分缓解,但这可能仍然不能涵盖所有情况。由于这个原因,如果日志记录是业务逻辑的一部分,例如,如果您使用Log4j作为审计日志记录框架,我们建议同步记录那些审计消息。(注意,除了用于审计跟踪的同步日志记录外,您仍然可以将它们组合在一起,并对调试/跟踪日志记录使用异步日志记录。)

在一些罕见的情况下,必须小心可变消息。大多数时候你不需要担心这个。Log4将确保像logger.debug("My object is {}", myObject)这样的日志消息将在调用logger.debug()时使用myObject参数的状态。即使稍后修改myObject,日志消息也不会改变。异步地记录可变对象的日志是安全的,因为Log4j内置的大多数Message实现会获取参数的快照。但是也有一些例外:MapMessage和StructuredDataMessage是设计可变的:字段可以在创建消息对象之后添加到这些消息中。在异步日志记录器或异步追加器记录这些消息后,不应该修改它们;您可能会也可能不会在结果日志输出中看到修改。类似地,定制消息实现在设计时应该考虑到异步使用,要么在构造时对其参数进行快照,要么记录它们的线程安全特征。

如果您的应用程序运行在一个CPU资源稀缺的环境中,比如一个单核CPU的机器,启动另一个线程不太可能获得更好的性能。

如果应用程序记录消息的持续速率比底层appender的最大持续吞吐量快,队列将被填满,应用程序将以最慢的appender的速度结束日志记录。如果出现这种情况,请考虑选择更快的appender,或者减少日志记录。如果这两种方法都不适用,那么您可以通过同步日志记录来获得更好的吞吐量和更少的延迟峰值。

使所有日志记录器异步

Log4j-2.9及更高版本需要在类路径上使用disruptor-3.3.4.jar或更高版本。在Log4j-2.9之前,需要disruptor-3.0.0.jar或更高版本。

这是最简单的配置,并提供最佳性能。要使所有日志记录器都是异步的,可以将干扰器jar添加到类路径中,并设置系统属性log4j2。contextSelector org.apache.logging.log4j.core.async.AsyncLoggerContextSelector。

默认情况下,位置不会被异步日志记录器传递给I/O线程。如果您的某个布局或自定义过滤器需要位置信息,您需要在所有相关记录器(包括根记录器)的配置中设置" inclelocation =true"。

不需要位置的配置可能如下所示:

<?xml version="1.0" encoding="UTF-8"?>
 
<!-- Don't forget to set system property
-Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
     to make all loggers asynchronous. -->
 
<Configuration status="WARN">
  <Appenders>
    <!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
    <RandomAccessFile name="RandomAccessFile" fileName="async.log" immediateFlush="false" append="false">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m %ex%n</Pattern>
      </PatternLayout>
    </RandomAccessFile>
  </Appenders>
  <Loggers>
    <Root level="info" includeLocation="false">
      <AppenderRef ref="RandomAccessFile"/>
    </Root>
  </Loggers>
</Configuration>

当使用AsyncLoggerContextSelector使所有记录器异步时,确保在配置中使用正常的和元素。AsyncLoggerContextSelector将确保所有记录器都是异步的,使用的机制与配置或时所发生的机制不同。后一个元素用于混合使用异步记录器和同步记录器。如果同时使用这两种机制,就会得到两个后台线程,应用程序将日志消息传递给线程A,线程A将消息传递给线程B,线程B最后将消息记录到磁盘。这是可行的,但中间会有一个不必要的步骤。

您可以使用一些系统属性来控制异步日志记录子系统的各个方面。其中一些可用于调优日志记录性能。

还可以通过创建一个名为log4j2.component.properties的文件并将该文件包含在应用程序的类路径中来指定以下属性。

注意,在Log4j 2.10.0中,系统属性被重命名为更一致的样式。这里仍然支持所有旧的属性名。

系统属性以配置所有异步记录器

系统属性默认值描述

log4j2.asyncloggerexceptionhandler default handler实现com.lmax.disruptor.ExceptionHandler接口的类的完全限定名。类需要有一个公共的零参数构造函数。如果指定,当记录消息时发生异常时将通知该类。

如果未指定,默认异常处理程序将打印消息和堆栈跟踪到标准错误输出流。

log4j2.asyncloggerringbuffersize 256 * 1024异步日志子系统使用的RingBuffer的槽位大小。使这个值足够大以处理突发活动。最小尺寸是128个。RingBuffer将在第一次使用时被预先分配,并且在系统的生命周期中不会增长或收缩。

当应用程序的日志记录速度快于底层appender能够持续足够长的时间来填充队列时,行为由AsyncQueueFullPolicy决定。

log4j2。asyncloggerwaitstrategy Timeout有效值:Block, Timeout, Sleep, Yield。

Block是一种策略,为等待日志事件的I/O线程使用锁和条件变量。当吞吐量和低延迟不像CPU资源那么重要时,可以使用块。推荐用于资源受限/虚拟化环境。

Timeout是Block策略的一种变体,它将定期从锁条件await()调用中唤醒。这确保了如果一个通知以某种方式丢失了,消费者线程不会被卡住,而是会以一个小的延迟(默认10ms)恢复。

Sleep是一种策略,它首先旋转,然后使用thread .yield(),最后在I/O线程等待日志事件时,将操作系统和JVM允许的最小纳诺数停车。睡眠是性能和CPU资源之间的一个很好的折衷。这种策略对应用程序线程的影响非常小,以换取实际获取消息日志的一些额外延迟。

Yield是一种策略,它使用Thread.yield()在初始旋转之后等待日志事件。Yield是性能和CPU资源之间的一个很好的折衷,但是为了更快地将消息记录到磁盘,可能会比Sleep使用更多的CPU。

log4j2。asyncloggertimeout 10超时时间,单位为毫秒

System PropertyDefault ValueDescription
log4j2.asyncLoggerExceptionHandlerdefault handlerFully qualified name of a class that implements the com.lmax.disruptor.ExceptionHandler interface. The class needs to have a public zero-argument constructor. If specified, this class will be notified when an exception occurs while logging the messages.

If not specified, the default exception handler will print a message and stack trace to the standard error output stream.

log4j2.asyncLoggerRingBufferSize256 * 1024Size (number of slots) in the RingBuffer used by the asynchronous logging subsystem. Make this value large enough to deal with bursts of activity. The minimum size is 128. The RingBuffer will be pre-allocated at first use and will never grow or shrink during the life of the system.

When the application is logging faster than the underlying appender can keep up with for a long enough time to fill up the queue, the behaviour is determined by the AsyncQueueFullPolicy.

log4j2.asyncLoggerWaitStrategyTimeoutValid values: Block, Timeout, Sleep, Yield.
Block is a strategy that uses a lock and condition variable for the I/O thread waiting for log events. Block can be used when throughput and low-latency are not as important as CPU resource. Recommended for resource constrained/virtualised environments.
Timeout is a variation of the Block strategy that will periodically wake up from the lock condition await() call. This ensures that if a notification is missed somehow the consumer thread is not stuck but will recover with a small latency delay (default 10ms).
Sleep is a strategy that initially spins, then uses a Thread.yield(), and eventually parks for the minimum number of nanos the OS and JVM will allow while the I/O thread is waiting for log events. Sleep is a good compromise between performance and CPU resource. This strategy has very low impact on the application thread, in exchange for some additional latency for actually getting the message logged.
Yield is a strategy that uses a Thread.yield() for waiting for log events after an initially spinning. Yield is a good compromise between performance and CPU resource, but may use more CPU than Sleep in order to get the message logged to disk sooner.
log4j2.asyncLoggerTimeout10Timeout in milliseconds of TimeoutBlockingWaitStrategy. See the WaitStrategy System Property for details.
log4j2.asyncLoggerSleepTimeNs100Sleep time (in nanoseconds) of SleepingWaitStrategy. See the WaitStrategy System Property for details.
log4j2.asyncLoggerRetries200Total number of spin cycles and Thread.yield() cycles of SleepingWaitStrategy. See the WaitStrategy System Property for details.
AsyncLogger.SynchronizeEnqueueWhenQueueFulltrueSynchronizes access to the Disruptor ring buffer for blocking enqueue operations when the queue is full. Users encountered excessive CPU utilization with Disruptor v3.4.2 when the application was logging more than the underlying appender could keep up with and the ring buffer became full, especially when the number of application threads vastly outnumbered the number of cores. CPU utilization is significantly reduced by restricting access to the enqueue operation. Setting this value to false may lead to very high CPU utilization when the async logging queue is full.
log4j2.asyncLoggerThreadNameStrategyCACHEDValid values: CACHED, UNCACHED.
By default, AsyncLogger caches the thread name in a ThreadLocal variable to improve performance. Specify the UNCACHED option if your application modifies the thread name at runtime (with Thread.currentThread().setName()) and you want to see the new thread name reflected in the log.
log4j2.clockSystemClock

Implementation of the org.apache.logging.log4j.core.util.Clock interface that is used for timestamping the log events when all loggers are asynchronous.
By default, System.currentTimeMillis is called on every log event.

CachedClock is an optimization intended for low-latency applications where time stamps are generated from a clock that updates its internal time in a background thread once every millisecond, or every 1024 log events, whichever comes first. This reduces logging latency a little, at the cost of some precision in the logged time stamps. Unless you are logging many events, you may see "jumps" of 10-16 milliseconds between log time stamps. WEB APPLICATION WARNING: The use of a background thread may cause issues for web applications and OSGi applications so CachedClock is not recommended for this kind of applications.

You can also specify the fully qualified class name of a custom class that implements the Clock interface.

1478/5000 
还有一些系统属性可以用于维持应用程序吞吐量,即使底层appender无法跟上日志记录速率,队列正在被填满。查看系统属性log4j2的详细信息。asyncQueueFullPolicy log4j2.discardThreshold。

混合使用同步和异步日志记录器

Log4j-2.9及更高版本需要在类路径上使用disruptor-3.3.4.jar或更高版本。在Log4j-2.9之前,需要disruptor-3.0.0.jar或更高版本。不需要将系统属性“Log4jContextSelector”设置为任何值。

同步和异步日志记录器可以在配置中组合使用。这给您带来了更大的灵活性,但代价是略微降低了性能(与使所有日志记录器都是异步的相比)。使用或配置元素来指定需要异步的记录器。一个配置只能包含一个根日志记录器(或元素),但除此之外,异步和非异步日志记录器可以组合使用。例如,包含元素的配置文件还可以包含同步记录器的和元素。

默认情况下,位置不会被异步日志记录器传递给I/O线程。如果您的某个布局或自定义过滤器需要位置信息,您需要在所有相关记录器(包括根记录器)的配置中设置" inclelocation =true"。

混合异步记录器的配置可能如下所示:

  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
好的,下面是Spring Boot集成log4j2输出日志文件的步骤: 1. 在pom.xml文件中添加log4j2的依赖 ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> ``` 2. 在src/main/resources目录下创建log4j2.xml文件,并配置输出文件的路径、格式等信息。以下是一个示例配置文件: ``` <?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> <RollingFile name="RollingFile" fileName="logs/log4j2.log" filePattern="logs/log4j2-%d{yyyy-MM-dd}-%i.log"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> <Policies> <TimeBasedTriggeringPolicy /> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <DefaultRolloverStrategy max="10"/> </RollingFile> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="Console"/> <AppenderRef ref="RollingFile"/> </Root> </Loggers> </Configuration> ``` 3. 在Spring Boot的启动类中添加注解@EnableAsync和@ImportResource,开启异步调用和导入log4j2.xml配置文件。 ``` @SpringBootApplication @EnableAsync @ImportResource(locations = {"classpath:log4j2.xml"}) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 4. 在需要输出日志的类中,使用log4j2日志记录器进行日志输出。以下是一个示例: ``` import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class SampleClass { private static final Logger logger = LogManager.getLogger(SampleClass.class); public void doSomething() { logger.info("This is a sample log message."); } } ``` 这样就完成了Spring Boot集成log4j2输出日志文件的配置。希望对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

psyuhen

你的鼓励是我最大的动力谢谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值