Исключения и исключения тайм-аутов Kafka Producer

Мы получаем случайные NetworkExceptions и TimeoutExceptions в нашей производственной среде:

Brokers: 3
Zookeepers: 3
Servers: 3
Kafka: 0.10.0.1
Zookeeeper: 3.4.3

Мы иногда получаем это исключение в моих журналах производителей:

Истекает 10 записей для TOPIC: XXXXXX: 5608 мс прошло с момента выпуска создание плюс время ожидания.

Количество миллисекунд в таких сообщениях об ошибках продолжает меняться. Иногда его ~ 5 секунд в других случаях это до ~ 13 секунд!

И очень редко мы получаем:

NetworkException: Server disconnected before response received. 

Кластер состоит из брокеров 3 и 3 zookeepers. Сервер производителей и кластер Kafka находятся в одной сети.

Я делаю синхронные вызовы. Там есть веб-служба, к которой обращаются несколько пользовательских запросов на отправку своих данных. Веб-сервис Kafka имеет один объект-производитель, который выполняет всю отправку. Время ожидания запроса производителя составляло 1000 мс, которое было изменено на 15000 мс (15 секунд). Даже после увеличения периода ожидания TimeoutExceptions все еще отображаются в журналах ошибок.

В чем может быть причина?

Ответ 1

Это немного сложно найти основную причину, я поделюсь с этим опытом, надеюсь, кто-то может найти это полезным. В общем, это может быть проблема с сетью или чрезмерное затопление сети в сочетании с ack=ALL. Вот схема, которая объясняет TimeoutException из Kafka KIP-91 во время его написания (все еще применимо до 1.1.0):

enter image description here

Исключая проблемы или ошибки конфигурации сети, это свойства, которые можно настроить в зависимости от сценария, чтобы смягчить или решить проблему:

  • buffer.memory контролирует общий объем памяти, доступной производителю для буферизации. Если записи отправляются быстрее, чем они могут быть переданы в Kafka, тогда и этот буфер будет превышен, тогда дополнительные вызовы отправки блокируются до max.block.ms, после чего Producer выдает TimeoutException.

  • max.block.ms уже имеет высокое значение, и я не предлагаю его увеличивать. buffer.memory имеет значение по умолчанию 32 МБ, и в зависимости от размера сообщения вы можете увеличить его; при необходимости увеличьте пространство кучи JVM.

  • Повторные попытки определяют, сколько попыток повторно отправить запись в случае ошибки, прежде чем отказаться. Если вы используете ноль повторных попыток, вы можете попытаться смягчить проблему, увеличив это значение, остерегайтесь порядка записей, если вы не установите для max.in.flight.requests.per.connection значение 1.

  • Записи отправляются, как только достигнут размер пакета или истекло время ожидания, в зависимости от того, что наступит раньше. если batch.size (по умолчанию 16 КБ) меньше максимального размера запроса, возможно, вам следует использовать более высокое значение. Кроме того, измените linger.ms на более высокое значение, например 10, 50 или 100, чтобы оптимизировать использование пакета и сжатие. это приведет к меньшему затоплению в сети и оптимизации сжатия, если вы его используете.

На этот тип вопросов нет точного ответа, поскольку они зависят также от реализации, в моем случае эксперимент с приведенными выше значениями помог.

Ответ 2

Мы столкнулись с подобной проблемой. Много NetworkExceptions в логах и время от времени TimeoutException.

Причина

После того, как мы собрали протоколы TCP с производства, оказалось, что некоторые TCP-соединения с брокерами Kafka (у нас есть 3 узла брокера) были сброшены без уведомления клиентов после примерно 5 минут простоя (без флагов FIN на уровне TCP). Когда клиент пытался повторно использовать это соединение после этого времени, был возвращен флаг RST. Мы могли бы легко сопоставить сброс этих соединений в журналах TCP с NetworkExceptions в журналах приложений.

Что касается TimeoutException, мы не могли сделать такое же сопоставление, как к тому времени, когда мы нашли причину, такого типа ошибки больше не возникало. Однако в отдельном тесте мы подтвердили, что разрыв TCP-соединения может также привести к TimeoutException. Я предполагаю, что это связано с тем, что Java Kafka Client использует сокет Java NIO Socket Channel. Все сообщения буферизуются и затем отправляются, как только соединение будет готово. Если соединение не будет готово в течение тайм-аута (30 секунд), срок действия сообщений истечет, что приведет к TimeoutException.

Решение

Для нас было исправлено сокращение connections.max.idle.ms на наших клиентах до 4 минут. Как только мы применили его, NetworkExceptions исчезли из наших журналов.

Мы все еще расследуем то, что разрывает соединения.

Изменить

Причиной проблемы был шлюз AWS NAT, который сбрасывал исходящие соединения через 350 секунд.

https://docs.aws.amazon.com/vpc/latest/userguide/nat-gateway-troubleshooting.html#nat-gateway-troubleshooting-timeout

Ответ 3

Решение 1

Изменить

listeners=PLAINTEXT://hostname:9092

в файле server.properties для

listeners=PLAINTEXT://0.0.0.0:9092

Решение 2

Измените значение broker.id на значение, равное 1001, измените идентификатор брокера, установив переменную среды KAFKA_BROKER_ID.

Вам нужно будет установить переменную окружения KAFKA_RESERVED_BROKER_MAX_ID примерно на 1001, чтобы разрешить устанавливать идентификатор брокера на 1001.

Я надеюсь, что это поможет

Ответ 4

Увеличьте request.timeout.ms и повторы вашего производителя