Повторные попытки, порядок и обратное давление

Что это такое

От этой механики зависит, надёжна ли асинхронная работа: что делать, когда обработчик падает; как повторяются неудавшиеся сообщения и куда попадают, если падают снова; какой порядок наблюдают потребители; и что происходит, когда сообщения приходят быстрее, чем их успевают обработать. Всё это — решения о настройке и проектировании, принятые и в брокере, и в обработчике, и именно они определяют, как система поведёт себя под нагрузкой.

Почему это важно

Асинхронные системы отказывают тихо. Сообщение, которое не удаётся обработать, либо исчезает, либо блокирует всё за собой, либо повторяется бесконечно, — и каждый из этих исходов кто-то выбрал. От обратного давления зависит, поглотится всплеск и рассосётся или накопится, пока не заполнит брокер. Эти решения и позволяют очереди сдержать обещание развязки; оставленные на значениях по умолчанию, они превращают её в место, где работа тихо пропадает.

Ключевые идеи

Повторяйте с задержкой и ограничьте число попыток

Немедленный повтор отказа, вызванного недоступной зависимостью, снова не удастся и умножит нагрузку на неё. Отложите каждую попытку с растущим интервалом и добавьте немного случайности — так у зависимости появится время восстановиться, и потребители не станут повторять все в один и тот же момент, а ограничение числа попыток не даст вечно падающему сообщению повторяться бесконечно.

попытка 1 -> пауза ~1с -> попытка 2 -> пауза ~2с -> попытка 3 -> dead-letter

Очередь недоставленных сообщений и делает отказ видимым

Исчерпав попытки, сообщение должно попасть туда, где оператор сможет его осмотреть, и за этим местом нужно следить. Очередь без пути для недоставленных либо теряет сообщение, либо блокирует свой раздел; и то и другое хуже, чем растущая куча, которую кто-то видит, — а размер такой очереди остаётся одним из самых полезных эксплуатационных сигналов в системе.

Отравленные сообщения блокируют раздел

Сообщение, которое падает всегда, остановит обработку всех сообщений за ним — если очередь сохраняет порядок. Убрать его в сторону, заметив повторные падения, — единственное, что не даёт одной плохой записи остановить поток; здесь политика повторных попыток связана с гарантией порядка самым прямым образом.

Порядок и параллелизм прямо противоречат друг другу

Порядок не даёт позднему сообщению обогнать раннее, а параллельная обработка даёт пропускную способность. Журнал снимает противоречие тем, что упорядочивает внутри раздела: параллелизм достигается за счёт разделов, а ключ нужно выбирать так, чтобы сообщения, которым нужен порядок, попадали в один раздел; потребителей же сверх числа разделов добавлять бесполезно — параллелизма это не прибавит.

Обратное давление — это политика, а не нехватка мощности

Когда сообщения приходят быстрее, чем их успевают обрабатывать, что-то должно уступить: брокер буферизует, производитель замедляется или работа отбрасывается. Буферизация откладывает решение, однако буфер не бесконечен: когда он кончится, проблема пропускной способности превратится в проблему памяти и задержки. Политику выбирают осознанно — приостановить производителя, отбросить низкоприоритетную работу или отбросить её с записанным отказом, — и она должна быть видна в метрике отставания.

Расстояние между самым новым сообщением и позицией потребителя показывает, успевает ли система или отстаёт, и это самое полезное число для алерта. Отставание, которое устойчиво растёт, говорит о пропускной способности; то, что подскакивает и восстанавливается, — о поглощённом всплеске; а ровное и высокое означает, что потребители застряли.

Идемпотентность и делает всё это безопасным

Каждый механизм здесь — повтор, доставка заново, воспроизведение из очереди недоставленных сообщений, перезапуск потребителя с более ранней позиции — может привести к тому, что одно сообщение обработают больше одного раза. Обработчик, который записывает идентификатор сообщения до применения эффекта, переживает всё перечисленное; тот, который этого не делает, порождает дубли побочных эффектов на каждом пути восстановления.

Практика

Настройте повтор и путь для недоставленных сообщений

Возьмите потребителя, обработчик которого может упасть, задайте ему ограниченные повторы с задержкой и очередь недоставленных сообщений, а затем заставьте его упасть намеренно.

Готово, когда: сообщение повторяется заданное число раз и оказывается в очереди недоставленных сообщений, а не теряется и не блокирует поток.

Понаблюдайте за отставанием при всплеске

Опубликуйте всплеск больше, чем потребитель может обработать, запишите отставание потребителя во времени и опишите, что произойдёт, когда буфер исчерпается.

Готово, когда: вы можете показать метрику, по которой очередь сливается, и назвать политику, которая применяется, когда этого не происходит.

Частые ошибки

  • Немедленные и бесконечные повторы — падающая зависимость забивается запросами, а сообщение никогда не уходит; исправить: отступайте с задержкой, добавьте случайность и ограничьте число попыток.
  • Отсутствие очереди недоставленных сообщений — отказы теряются или блокируют поток; исправить: направляйте исчерпавшие попытки сообщения туда, где за ними наблюдают.
  • Потребители сверх числа разделов — дополнительного параллелизма не появляется; исправить: увеличьте число разделов, выбрав ключ так, чтобы связанные сообщения остались упорядочены.
  • Молчаливое поглощение перегрузки буфером — проблема пропускной способности становится проблемой задержки и памяти; исправить: выберите политику обратного давления и следите за отставанием.
  • Неидемпотентный обработчик — каждая повторная доставка дублирует эффект; исправить: записывайте идентификатор сообщения до применения изменения.

Что читать дальше