2016-12-12 3 views
1

У меня возникают проблемы с производительностью с использованием log4j2 (2.5) в сочетании с Kafka (0.10.1.0). Когда я включаю Kafka в файл log4j2.xml, мое приложение замедляется до обхода, в то время как выдает только 200 КБ/с событий для брокера Kafka. Это на порядок меньше, чем то, что должен достичь Кафка (https://engineering.linkedin.com/kafka/benchmarking-apache-kafka-2-million-writes-second-three-cheap-machines).Плохая производительность log4j2 в сочетании с Kafka

Вот соответствующая часть моего файла конфигурации 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> 

После выполнения некоторых тестов я смог придавить проблему и обнаружил, что тест ProducerPerformance поставляется с Кафкой делает достижение достойная производительность. Его производительность составляет около 5 Мбайт/с, причем сообщения с одинаковым размером 100 байт. После обширного тестирования я узнал, что разница заключается не в конфигурации, а в том, как выполняются вызовы. Log4j2 KafkaAppender использует класс KafkaManager для записи журнала Кафка:

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); 
    } 
} 

Проблема производительности вызвана вызовом метода «получить», который блокирует до отправки не завершена. Довольно забавно, есть 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 устанавливается на ложный вызов немедленно отправить возвращается. Это свойство "syncSend", однако, нигде не встречается в реализации log4j2 KafkaAppender.

Я пробовал делать асинхронные вызовы с помощью других средств, например, используя AsyncAppender, поставляемый с log4j2, и установил свойство acks равным 0 вместо 1. Однако ни одна из настроек не обеспечивает выигрыш в производительности, не дожидаясь отправки завершить. Я также пытался использовать приложение log4j, поставляемое с Kafka, но мне не удалось заставить его работать с log4j2 (и я хочу придерживаться log4j2).

Итак, наконец, я решил разблокировать KafkaAppender, поставляемый с log4j2, и удалить блокирующую часть вызова. Это работает, но, конечно, я предпочел бы использовать готовые пакеты.

Есть ли кто-нибудь, кто также столкнулся с этой проблемой? Как вы решили проблему? Есть ли более простой способ без изменения кода?

+0

Вы пытались использовать AsyncLogger вместо AsyncAppender? – Matt

+0

Да, я попробовал обернуть KafkaAppender с помощью AsyncAppender, но это не ускоряет общение с Kafka. Он просто позволяет приложению работать быстрее, чем сообщения отправляются в Kafka, но в конечном итоге блокируется, когда очередь заполнена. – thedutchy

+0

Вы сделали правильную вещь и подняли эту проблему в сообществе Log4j2 (https://issues.apache.org/jira/browse/LOG4J2-1733). Усовершенствования и предложения для Log4j всегда приветствуются! Самый быстрый способ включить ваше улучшение - предоставить запрос на патч или тяну с модульными тестами. –

ответ

1

У KafkaAppender теперь есть новый атрибут syncSend, который можно настроить для поддержки асинхронной отправки, что значительно улучшает пропускную способность для Kafka. Спасибо за Вашу поддержку!

+0

Спасибо за предоставление патча! –