引入Log4J2 JDBCAppender后GC失败

时间:2019-07-12 06:04:14

标签: java log4j2

我正在使用Log4J2将事务数据记录到数据库中。

下面是我的log4J2.xml配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="ERROR">
        <!-- Define custom levels before using them for filtering below. -->
        <CustomLevels>
            <CustomLevel name="TRANSACTION" intLevel="1"/>
        </CustomLevels>

        <!--Configuring appenders for logging -->
        <Appenders>

            <!--Console appender for application logs-->
            <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %m%n"/>
            </Console>

            <!--RollingFile appender for application logs-->
            <RollingFile name="RollingFileAppender" fileName="${sys:user.home}/logs/App.log" filePattern="${sys:user.home}/logs/App $${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
                <PatternLayout>
                    <Pattern>%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %m%n</Pattern>
                </PatternLayout>
                <Policies>
                    <SizeBasedTriggeringPolicy size="500 MB"/>
                </Policies>
                <DefaultRolloverStrategy max="20"/>
            </RollingFile>

            <RollingFile name="RollingFileAppenderTransaction" fileName="${sys:user.home}/logs/App-Transaction.log" filePattern="${sys:user.home}/logs/App-Transaction $${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
                <PatternLayout>
                    <Pattern>%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %m%n</Pattern>
                </PatternLayout>
                <Policies>
                    <SizeBasedTriggeringPolicy size="500 MB"/>
                </Policies>
                <DefaultRolloverStrategy max="20"/>
            </RollingFile>

            <!--JDBCAppender for transaction logs-->
            <JDBC name="JDBCAppender" tableName="Logs">
                <ConnectionFactory class="com.example.app.utils.LoggerConnectionFactory" method="getConnection"/>
                <Column name="id" pattern="%u"/>
                <Column name="entryDate" isEventTimestamp="true"/>
                <Column name="logger" pattern="%logger"/>
                <Column name="logLevel" pattern="%level"/>
                <Column name="message" pattern="%m"/>
            </JDBC>

        </Appenders>
        <Loggers>
            <!-- Only transaction logs from LoggerVerticle should be logged using JDBCAppender -->
            <Logger name="com.example.app.verticles.LoggerVerticle" level="Transaction" additivity="false">
                <AppenderRef ref="JDBCAppender" level="TRANSACTION"/>
            </Logger>
            <!-- Root logger configuration-->
            <Root level="INFO">
                <AppenderRef ref="RollingFileAppender"/>
            </Root>
        </Loggers>
    </Configuration>

下面是我的LoggerConnectionFactory类:

    package com.example.app.utils;

    import com.example.app.commonutils.ConfigKey;
    import com.example.app.commonutils.PropertyFileUtils;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.mariadb.jdbc.MariaDbPoolDataSource;

    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.SQLException;

    public class LoggerConnectionFactory {
      private static final Logger logger = LogManager.getLogger(LoggerConnectionFactory.class);
      private DataSource dataSource;

      private LoggerConnectionFactory() {
        String url = PropertyFileUtils.getConfig(ConfigKey.ENVIRONMENT_DB_URL) +
          (String) PropertyFileUtils.getConfig(ConfigKey.ENVIRONMENT_DB_NAME);
        try {
          MariaDbPoolDataSource mariaDbPoolDataSource = new MariaDbPoolDataSource(url);
          mariaDbPoolDataSource.setUser((String) PropertyFileUtils.getConfig(ConfigKey.ENVIRONMENT_DB_USERNAME));
          mariaDbPoolDataSource.setPassword((String) PropertyFileUtils.getConfig(ConfigKey.ENVIRONMENT_DB_PASSWORD));
          mariaDbPoolDataSource.setMaxPoolSize(50);
          mariaDbPoolDataSource.setPoolName("LoggerConnectionPool");
          mariaDbPoolDataSource.initialize();
          dataSource = mariaDbPoolDataSource;
        } catch (SQLException e) {
          logger.catching(e);
        }
      }

      private interface Singleton {
        LoggerConnectionFactory INSTANCE = new LoggerConnectionFactory();
      }

      public static Connection getConnection() throws SQLException {
        return Singleton.INSTANCE.dataSource.getConnection();
      }
    }

对于每个请求,大约有5个日志条目。我正在使用JMeter测试1500个请求。

如果我使用RollingFileAppender进行事务数据记录,则应用程序没有任何问题,如上所述,在负载下一切正常。

但是,每当事务日志在与上述相同的负载下路由到JDBCAppender时,应用程序堆的使用就会在短时间内增加,从而导致完全GC失败。

我了解RollingFileAppenderJDBCAppender都是两个不同的东西,可能不会带来相同的性能,但是我想确保JDBCAppender配置正确。

我遇到过Garbage Free Logging,其中未列出JDBCAppender受支持。是这个原因吗?

您能建议我是否缺少任何东西吗?或可以采取什么措施来提高性能?

注意

  1. 我尝试过更改池的大小和其他实现 LoggerConnectionFactory返回一个DataSource(与连接 池连接)和PoolingDriver配置。
  2. 我尝试通过设置启用异步记录器 -Dlog4j2.contextSelector = org.apache.logging.log4j.core.async.AsyncLoggerContextSelector 这也没有任何区别。

0 个答案:

没有答案