DLQ та обробка отруйних повідомлень
Dead Letter Queue (DLQ) - це ізольована черга/топік для повідомлень, які не вдалося обробити штатним консьюмером після заданого числа спроб або з явних технічних/бізнес-причин (невалідна схема, таймаут, конфлікт версій тощо). Отруйне повідомлення (poison message) - запис, повторна обробка якого стабільно завершується помилкою і загрожує стабільності пайплайна.
Мета DLQ: зберегти SLO, локалізувати збій, не допустити блокування основного потоку і гарантувати можливості аналізу і безпечного повторного відтворення (редрайва).
1) Звідки беруться отруйні повідомлення
Схеми/контракти: несумісні зміни, відсутні обов'язкові поля, невірні типи.
Бізнес-валідації: дублікати, порушені інваріанти, прострочені події.
Порядок і причинність: прийшло «Update» до «Create», пропущені кореляції, out-of-order.
Ідемпотентність: повторна обробка породжує побічні ефекти.
Зовнішні залежності: обмежені ліміти/таймаути, недоступність API.
Дані: корупція корисного навантаження, невірне кодування, перевищення розмірів.
2) Критерії відправки в DLQ
Повідомлення потрапляє в DLQ, якщо виконано одну або кілька умов:- Перевищено maxAttempts обробки у консьюмера/воркера.
- Помилка класифікована як невиправна (non-retryable): невалідна схема, відсутність критичного ресурсу, бізнес-заборона.
- Закінчився deadline повідомлення (TTL/expiration).
- Спрацювала політика circuit breaker або admission control для даного ключа/тенанта.
- Явне рішення оператора (ручний «eject» з основного потоку).
3) Топології та патерни DLQ
Per-queue DLQ: у кожної черги/топіка є свій DLQ. Просто і прозоро.
Central DLQ (parking lot): загальний «паркінг» для складних випадків, зручний для єдиних інструментів аналізу.
DLT (Dead Letter Topic): для лог-орієнтованих шини (event log) - окремий топік з метаданими причини відмови.
Quarantine: карантинний буфер з жорстким доступом і PII-санітацією для ручного аналізу.
Shadow-stream: дублювання проблемних повідомлень в «тінь» для безпечних експериментів з фіксом.
4) Метадані, які зобов'язані супроводжувати DLQ
Мінімальний набір:- Причина відмови: код/клас помилки, stack/trace id.
- Контекст ретраїв: `attempt`, `maxAttempts`, `first_seen_ts`, `last_attempt_ts`.
- Кореляція: 'trace _ id','span _ id','tenant _ id','entity _ id', ключ партіонування.
- Оригінальний offset/partition/sequence (для лігвих шин) або message-id.
- Контракт/схема/версія корисного навантаження.
- Idempotency-key/Request-id (якщо є).
- Джерело маршрутизації: ім'я черги/топіка, консьюмер-група.
5) Політики ретраїв до DLQ
Перед відправкою в DLQ використовуйте коректні повторні спроби:- Короткі ретраї консьюмера: 'maxAttempts'2-5, exponential backoff + джиттер, caps на concurrency.
- Кооперативний backpressure: зменшення конкуренції при зростанні помилок.
- Класифікація помилок: retryable ('5xx', таймаут) vs non-retryable (валідація, schema mismatch).
- Відкладені черги (delay queue): 5s → 30s → 2m для тимчасових збоїв.
- Per-key ізоляція: якщо «шумить» конкретний ключ, не блокуйте весь партишен.
6) Безпечний редрайв (повторна доставка з DLQ)
Редрайв - це контрольоване повернення повідомлень з DLQ в обробку.
Принципи:1. Перевірка фікса: редрайв тільки після виправлення коду/конфігурації/схеми або після відновлення зовнішніх залежностей.
2. Ідемпотентність: обробники повинні бути стійкі до повтору (upsert, ефект-толурантні операції).
3. Дедуплікація: по `idempotency_key`/`message_id`/`business_key`.
4. Дозування та вікна: batches за N повідомлень, rate-limit на редрайв, «вікна» за часом/партіями.
5. Локальна валідація: швидка перевірка схеми перед редрайвом (reject ранніх невалідних кейсів).
6. Пріоритет: редрайв не повинен витісняти продовий трафік (низький пріоритет воркерів/окремий пул).
7. Спостережуваність: окремі метрики і трейси для редрайва; звіт про результати (успіх/повторний DLQ/втрата).
7) Семантика доставки і порядок
At-least-once - найчастіший режим: необхідні ідемпотентність і дедуплікація.
At-most-once - DLQ може бути відключений; ризик втрати. Використовуйте тільки при допустимих втратах.
Exactly-once (ефективне): досягається транзакціями і дедупом в бізнес-сховищі; дорого і специфічно.
Порядок: DLQ зазвичай розриває порядок для конкретного ключа/партії. Якщо порядок критичний, редрайвіте по ключу і послідовно.
8) Схеми, контракти і валідація
Schema registry/контракти: чітке версіонування, еволюція з backward/forward-сумісністю.
Валідація на вході: дешева перевірка через JSON Schema/Protobuf/Avro перед важкими кроками.
Політика несумісності: при «ламаючому» полі - негайно в DLQ з кодом'SCHEMA _ INCOMPATIBLE'.
Redaction PII: в DLQ зберігайте тільки необхідне; чутливі поля маскуйте.
9) Ідемпотентність і дедуплікація
Idempotency-key: формуйте на продьюсере з «бізнес-сенсу» (tenant + entity + operation + ts-bucket).
Дедуп-журнали: зберігайте останні «N» ключів з TTL; запам'ятовуйте «ефект» операції.
Upsert/merge: уникайте «insert-only» без обмежень.
Сайд-ефекти: для зовнішніх викликів - журналюйте і перевіряйте «повтор» перед викликом.
10) Спостережуваність і SLO
Метрики (по черзі/тенанту/ключу):- DLQ rate (msg/s), частка повідомлень, середній/медіанний «вік» в DLQ.
- Успіх редрайва (%), повторна DLQ-частка.
- Класифікація причин: schema, validation, timeout, dependency, unknown.
- p95/p99 латентність обробки основного потоку vs в редрайві.
- Розмір DLQ, ризик переповнення.
- Обов'язкові теги: `message_id`, `entity_id`, `tenant_id`, `attempt`, `reason`, `redrive_batch_id`.
- Трасування «гілки DLQ»: від джерела до повторного успіху.
- Частка успішно оброблених повідомлень ≥ X% за T хвилин.
- Час розслідування та виправлення для DLQ-кейсу ≤ Y годин.
- Максимальний «вік» повідомлення в DLQ ≤ Z годин (з алертом).
11) Безпека та відповідність
Доступ за принципом найменших привілеїв: редрайв - тільки операторам/плейбукам.
Аудит: хто і коли тригерив редрайв/видалення/редагування метаданих.
Санітація: при перенесенні в central DLQ видаляйте зайві PII/секрети.
Retention: окремі терміни зберігання і політика видалення для DLQ.
12) Мульти-тенантність
Теги'tenant _ id/plan': розрізняйте ліміти, пріоритети редрайву, звіти.
Пер-тенантні DLQ або партії: щоб «галасливий» клієнт не забивав загальний DLQ.
Білінг/квоти: враховуйте обсяг DLQ і вартість редрайва в usage.
13) Конфігураційні шаблони (приклад)
yaml consumer:
max_attempts: 4 backoff:
strategy: exponential_full_jitter initial_ms: 200 max_ms: 5000 classify_errors:
retryable: [TIMEOUT, DEP_UNAVAILABLE, 5xx]
nonretryable:[SCHEMA_INCOMPATIBLE, VALIDATION_FAILED, DUPLICATE]
concurrency_caps:
per_partition: 8 per_tenant: 50
dlq:
type: topic name: myapp. events. dlq metadata:
include: [reason, stack, attempt, first_seen_ts, last_attempt_ts, schema_version,
tenant_id, entity_id, trace_id, source_topic, partition, offset]
retention_hours: 168 pii_redaction: true
redrive:
mode: batch batch_size: 500 rate_limit_per_sec: 50 priority: low validate_schema_before_redrive: true idempotency:
dedup_ttl_hours: 24 ordering:
by_key: true
14) Операційні плейбуки (runbooks)
1. Аномальне зростання DLQ: включити throttling прод-консьюмера, проаналізувати топ-причини, перевірити релізи/схеми.
2. Schema mismatch: відкат/фіксація схеми, міграція адаптера, redrive після перевірки.
3. Зовнішня залежність недоступна: пауза ретраїв, включити delay-чергу, redrive після відновлення.
4. Повторні DLQ після редрайву: включити «тіньовий» обробник/симулятор, перевірити ідемпотентність, звузити batch.
5. Переповнення DLQ: евакуація в архів-storage, включити селективний редрайв з ключів/причин.
15) Тестування і хаос
Ін'єкція помилок: schema-break, валідація, таймаути, 1-на-N «липкі» помилки.
Масовий редрайв: перевірка дозування та впливу на прод.
Out-of-order послідовності: ensure коректна обробка по ключах.
Корупція корисного навантаження: валідація і безпечна відмова.
Відновлення після падіння редрайв-воркера: ідемпотентність batch-операцій.
16) Типові помилки
Відсутність метаданих в DLQ → неможливо кластеризувати причини і безпечно редрайвити.
Масовий редрайв без лімітів → повторна деградація продакшену.
Немає ідемпотентності/дедупа → дублі і побічні ефекти.
Змішування PII в central DLQ без санітації.
Відсутність схем/контрактів → «сюрпризи» при еволюції повідомлень.
Єдиний загальний DLQ без партіонування за тенантами/ключами.
Нескінченні ретраї замість раннього DLQ для non-retryable помилок.
17) Швидкі рецепти
Звичайний бізнес-потік: 3-4 спроби, експоненціальний backoff c джиттером, рання класифікація помилок, DLQ з повними метаданими.
Критичні події (платіж): сувора ідемпотентність, короткі таймаути, мінімум спроб, швидкий DLQ і ручний розбір.
Масовий редрайв після фіксу: small batches (100-500), rate-limit, окремий пул воркерів, моніторинг успіху> 95% перед збільшенням швидкості.
Мульти-тенант: пертенантні ліміти на редрайв, звіт по топ-клієнтам-генераторам DLQ.
Висновок
DLQ - це не «сміттєвий кошик», а контрольований контур надійності. Чіткі правила попадання, багаті метадані, ідемпотентність і дедуплікація, безпечний дозований редрайв, дисципліна схем і спостережуваність перетворюють отруйні повідомлення з загрози для SLO в керований інженерний процес - зі зрозумілими плейбуками, прогнозованими витратами і мінімальним впливом на користувачів.