Падение соединения сельдерея с AWS ELB и RabbitMQ
В нашей среде мы используем RabbitMQ и Celery на AWS для параллельной работы задач на многих узлах.
Недавно мы превратили RabbitMQ в кластер из трех узлов, сконфигурировали политику ha и добавили балансировку нагрузки AWS (ELB) для порта 5672 ко всем 3 узлам. Наши работники Celery и клиентский код используют DNS-сервер ELB в качестве URL-адреса брокера.
Мы заметили, что после этого изменения ожидающий завершения задач async будет генерировать исключение IOError: Socket closed
.
ELB отключит все холостые соединения через 60 секунд. У нас есть задачи, которые занимают несколько часов.
Установка BROKER_HEARTBEAT на значение ниже 60 разрешенных соединений падает на рабочих. Но мы не можем найти какой-либо настройки, которая будет поддерживать клиентское соединение.
Это правильный подход, чтобы ждать длительных задач с помощью Celery?
Обходной путь, который мы еще не тестировали, заключается в том, чтобы вспомнить метод AsyncResult.wait()
, пока он не завершится успешно. Так, например:
async_result = task.delay(params)
while True:
try:
async_result.wait()
break
except IOError:
pass
Мы используем:
- RabbitMQ 3.6.5
- Сельдерей 3.1.20
- Бекленок сельдерея - это pyamqp
- Бэкэнд результатов сельдерея - rpc
Ответы
Ответ 1
Я полагаю, что вам нужно сделать, это увеличить тайм-аут на AWS ELB. Что происходит, соединение закрывается до завершения задачи. Вы можете выполнить это, выпустив следующую команду
elb-modify-lb-attributes myTestELB --connection-settings "idletimeout=3600" --headers
Это даст вам час для выполнения задачи. См. https://aws.amazon.com/blogs/aws/elb-idle-timeout-control/ для получения дополнительной информации об этом.
Если час недостаточно, вам придется отключить объединение пулов. Добавьте эти два параметра в конфигурацию celery
BROKER_POOL_LIMIT = None
BROKER_TRANSPORT_OPTIONS = {'confirm_publish': True}
Во-вторых, у вас будет удар производительности, так как он добавит некоторые накладные расходы. Поскольку у вас есть длительные задачи, это может не быть проблемой. Вторая настройка может быть не нужна, но я бы рекомендовал ее, учитывая, что вы находитесь за балансировщиком нагрузки. Этот параметр гарантирует, что сообщения будут получены и не будут потеряны в процессе.
Еще один вариант - сломать свою длинную задачу на более мелкие задачи! Это может означать больше кода, но в конечном итоге это может стоить.