基础概述

对于log4j2的同步和异步的讲解,本人也是找了很多的资料,也阅读了官方的文档和源码。

对于两者的区别已经发送log执行流程可参考下面的文章,讲的挺全面的: https://www.cnblogs.com/yeyang/p/7944906.html

其中对于AsyncAppender和AsyncLogger源码的解读可参考: https://www.cnblogs.com/lewis09/p/10003462.html https://www.cnblogs.com/lewis09/p/10004117.html

Disruptor详解请参考: https://www.jianshu.com/p/bad7b4b44e48

配置优化

本文是对之前那篇log4j2异步将log发送到kafka(https://blog.csdn.net/qq_35754073/article/details/103386177)的补充和log4j2在高并发情况下的优化。

场景:qps需要可以稳定在10000以上,可是测试到3000就发生qps下降的情况,通过对apm以及服务cpu,内存的分析确认是log4j严重影响了性能,所以有了后来大量寻找log4j2异步性能的一些问题,总结之后也是对项目log4j2做了一些优化,也是的确提升了性能。

1.给log增加tracking_id,对每次请求的log作标识。

2.Loggers的配置从大部分配在root改为配置在logger,因为陪在root发现会有一些不是项目中的log发送到了kafka,而logger就很精准。

3.增加Disruptor队列长度并配置队列堵塞丢弃策略从而增加高并发下的性能

添加tracking_id

String tracingId = request.getHeader("tracing_id");
if (tracingId == null || tracingId.isEmpty()) {
     tracingId = UUID.randomUUID().toString();
}
MDC.put("tracking_id", tracingId);

Loggers全部改为AsyncLogger:

  Loggers:
    AsyncRoot:
      level: debug
      #      add location in async
      includeLocation: true
      AppenderRef:
        - ref: CONSOLE
    AsyncLogger:
      - name: REQUEST_LOG
        AppenderRef:
          - ref: REQUEST_LOG
      - name: SERVICE_LOG
        AppenderRef:
          - ref: SERVICE_LOG
      - name: ERROR_LOG
        AppenderRef:
          - ref: ERROR_LOG

增加Disruptor队列长度并配置队列堵塞丢弃策略:

需要更改System Property(系统参数)

log4j2.asyncLoggerRingBufferSize:指定队列的长度

log4j2.AsyncQueueFullPolicy:指定堵塞丢弃策略,如果未指定此属性或具有value “Default”,则此工厂创建DefaultAsyncQueueFullPolicy对象。

如果此属性具有value “Discard”,则此工厂将创建 DiscardingAsyncQueueFullPolicy对象。

默认情况下,如果队列已满,此路由器将丢弃级别为INFO,DEBUG和TRACE的事件。可以使用属性log4j2.DiscardThreshold(开始丢弃的级别名称)进行调整。

更详细的参数请参考官网:

https://logging.apache.org/log4j/2.x/manual/async.html

指定System Property(系统参数)的方式:

1.启动参数方式

启动的时候增加-Dlog4j2.asyncLoggerRingBufferSize=123456789

2.log4j2提供的 log4j2.component.properties file方式

classpath下创建 log4j2.component.properties 文件

log4j2.asyncLoggerRingBufferSize=65535
log4j2.AsyncQueueFullPolicy=Discard
log4j2.DiscardThreshold=INFO

如果两者都配置了,则第二种方式将会覆盖第一种方式的配置。

个人思考

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages = "com.github.houbb.sensitive.log4j2.layout">

    <Properties>
        <Property name="DEFAULT_PATTERN">%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
        <Property name="DEFAULT_CHARSET">UTF-8</Property>
        <Property name="LOG_HOME">/log4j2/logs/test</Property>
    </Properties>

    <Appenders>
        <RollingRandomAccessFile name="COMMON-FILE-APPENDER"
                                 filePattern="${LOG_HOME}/$${date:yyyy-MM}/error-%d{MM-dd-yyyy}-%i.log.gz"
                                 fileName = "${LOG_HOME}/common.log"
                                 immediateFlush="true">
            <ThresholdFilter level="ERROR" onMatch="DENY" onMisMatch="ACCEPT"/>
            <PatternLayout>
                <Pattern>${DEFAULT_PATTERN}</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="250 MB"/>
            </Policies>
        </RollingRandomAccessFile>

        <RollingRandomAccessFile name="ERROR-FILE-APPENDER"
                                 filePattern="${LOG_HOME}/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz"
                                 fileName = "${LOG_HOME}/error.log"
                                 immediateFlush="true">
            <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMisMatch="DENY"/>
            <PatternLayout>
                <Pattern>${DEFAULT_PATTERN}</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="250 MB"/>
            </Policies>
        </RollingRandomAccessFile>

<!--        <Console name="Console" target="SYSTEM_OUT">-->
<!--            <SensitivePatternLayout/>-->
<!--        </Console>-->
    </Appenders>

    <Loggers>

        <AsyncLogger name="com.github.houbb.sensitive.test" level="INFO" additivity="false">
            <AppenderRef ref="COMMON-FILE-APPENDER"/>
            <AppenderRef ref="ERROR-FILE-APPENDER"/>
        </AsyncLogger>

        <asyncRoot level="INFO">
            <AppenderRef ref="COMMON-FILE-APPENDER"/>
            <AppenderRef ref="ERROR-FILE-APPENDER"/>
        </asyncRoot>
    </Loggers>

</Configuration>

指定配置文件-log4j2.component.properties

指定配置文件

# 最多缓存多少个
log4j2.asyncLoggerRingBufferSize=100
# 策略为丢弃
log4j2.AsyncQueueFullPolicy=Discard
# 对应的策略隔离级别
log4j2.DiscardThreshold=INFO

参考资料

https://blog.csdn.net/qq_35754073/article/details/104116487