log4j2 与 Kafka 结合性能不佳

the*_*chy 4 java apache-kafka log4j2

我在使用 log4j2 (2.5) 和 Kafka (0.10.1.0) 时遇到了性能问题。当我在 log4j2.xml 文件中启用 Kafka 时,我的应用程序会变慢到爬行,同时只向 Kafka 代理输出大约 200KB/s 的事件。这比 Kafka 应该实现的目标低几个数量级(https://engineering.linkedin.com/kafka/benchmarking-apache-kafka-2-million-writes-second-three-cheap-machines)。

这是我的 log4j2.xml 配置文件的相关部分:

<Kafka name="KafkaAll" topic="all">
  <PatternLayout pattern="%date %message" />
  <Property name="bootstrap.servers">localhost:9092</Property>
  <Property name="buffer.memory">67108864</Property>
  <Property name="batch.size">8196</Property>
  <Property name="acks">1</Property>
</Kafka>
Run Code Online (Sandbox Code Playgroud)

在运行一些测试之后,我已经能够确定问题并发现 Kafka 附带的 ProducerPerformance 测试确实实现了不错的性能。它的性能约为 5MB/s,具有类似大小的 100 字节消息。经过大量测试,我发现不同之处不在于配置,而在于实现调用的方式。log4j2 KafkaAppender 使用 KafkaManager 类将日志写入 Kafka:

public void send(final byte[] msg) throws ExecutionException, InterruptedException, TimeoutException {
    if (producer != null) {
        producer.send(new ProducerRecord<byte[], byte[]>(topic, msg)).get(timeoutMillis, TimeUnit.MILLISECONDS);
    }
}
Run Code Online (Sandbox Code Playgroud)

性能问题是由调用“get”方法引起的,该方法会阻塞直到发送完成。有趣的是,Kafka 中包含一个 log4j appender,它确实考虑到了这个问题:

Future<RecordMetadata> response = producer.send(new ProducerRecord<byte[], byte[]>(topic, message.getBytes()));
if (syncSend) {
    try {
        response.get();
    } catch (InterruptedException ex) {
        throw new RuntimeException(ex);
    } catch (ExecutionException ex) {
        throw new RuntimeException(ex);
    }
}
Run Code Online (Sandbox Code Playgroud)

换句话说,当 syncSend 设置为 false 时,对 send 的调用会立即返回。然而,在 KafkaAppender 的 log4j2 实现中找不到这个“syncSend”属性。

我尝试通过其他方式使调用异步,例如使用 log4j2 附带的 AsyncAppender 并将 acks 属性设置为 0 而不是 1。但是,没有任何设置通过不等待发送完成来实现性能提升。我也尝试使用 Kafka 附带的 log4j appender,但我没有设法让它与 log4j2 一起工作(我想坚持使用 log4j2)。

所以,最后,我决定分叉 log4j2 附带的 KafkaAppender 并删除调用的阻塞部分。这有效,但当然我更愿意使用现成的软件包。

有没有人也遇到过这个问题?你是如何解决这个问题的?有没有更简单的方法而不改变代码?

the*_*chy 5

KafkaAppender 现在有一个新属性“syncSend”,可以设置为支持异步发送,显着提高了对 Kafka 的吞吐量。感谢您的支持!