我使用log4j2(2.5)与Kafka(0.10.1.0)结合使用会遇到性能问题。当我在log4j2.xml文件中启用Kafka时,我的应用程序变慢为爬行,同时仅向Kafka代理输出大约200KB / s的事件。这比卡夫卡应该达到的要低几个数量级(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>
经过一些测试后,我已经能够解决问题,并发现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);
}
}
性能问题是由于调用&#34; get&#34;方法,阻止直到发送完成。有趣的是,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);
}
}
换句话说,当syncSend设置为false时,对send的调用立即返回。这个&#34; syncSend&#34;但是,在KafkaAppender的log4j2实现中找不到属性。
我尝试通过其他方式异步调用,例如使用log4j2附带的AsyncAppender并将acks属性设置为0而不是1.但是,没有设置通过不等待来获得性能提升发送完成。我也尝试使用Kafka附带的log4j appender,但我没有设法使用log4j2(我想坚持使用log4j2)。
所以,最后,我决定将log4j2附带的KafkaAppender分叉并删除阻塞部分。这有效,但我当然更喜欢使用现成的包装。
有没有人也遇到过这个问题?你是怎么解决这个问题的?没有更改代码有更简单的方法吗?
答案 0 :(得分:3)
KafkaAppender现在有一个新属性&#34; syncSend&#34;可以设置为支持异步发送,显着提高Kafka的吞吐量。感谢您的支持!