我在 MySQL db 上进行了测试,发现锁定了以下方法:
org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager.write(org.apache.logging.log4j.core.LogEvent, java.io.Serializable) (line: 261)
因为在源代码中你可以看到 write 方法的同步:
/**
* This method manages buffering and writing of events.
*
* @param event The event to write to the database.
* @param serializable Serializable event
*/
public final synchronized void write(final LogEvent event, final Serializable serializable) {
if (isBuffered()) {
buffer(event);
} else {
writeThrough(event, serializable);
}
}
我认为如果您指定缓冲区大小,它将增加吞吐量,因为日志将被收集成批次并且同步将非常低。
在使用更新 log4j2 配置文件后,AsyncLogger
您将看到锁定:
org.apache.logging.log4j.core.async.AsyncLoggerConfigDisruptor.enqueue(org.apache.logging.log4j.core.LogEvent, org.apache.logging.log4j.core.async.AsyncLoggerConfig) (line: 375)
和该方法的实现:
private void enqueue(final LogEvent logEvent, final AsyncLoggerConfig asyncLoggerConfig) {
if (synchronizeEnqueueWhenQueueFull()) {
synchronized (queueFullEnqueueLock) {
disruptor.getRingBuffer().publishEvent(translator, logEvent, asyncLoggerConfig);
}
} else {
disruptor.getRingBuffer().publishEvent(translator, logEvent, asyncLoggerConfig);
}
}
synchronizeEnqueueWhenQueueFull
默认情况true
下,它会在线程上产生锁,您可以管理这些参数:
/**
* LOG4J2-2606: 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 ringbuffer 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.
*/
static final boolean ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = PropertiesUtil.getProperties()
.getBooleanProperty("AsyncLogger.SynchronizeEnqueueWhenQueueFull", true);
static final boolean ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = PropertiesUtil.getProperties()
.getBooleanProperty("AsyncLoggerConfig.SynchronizeEnqueueWhenQueueFull", true);
但是您应该了解使用这些参数的副作用,如代码片段中所述。
想法为什么数据库会成为瓶颈?:
- 远程数据库(vpn等)
- 检查 id 列(SEQUENCE、TABLE、IDENTITY)使用什么策略以避免额外的数据库调用
- 列上有索引吗?(它可以在每个事务提交上产生重新索引操作)