Чому Google Pub/Sub втрачає повідомлення при піковому навантаженні
Втрата повідомлень рідко виглядає як помилка в логах — частіше це тиша: обробник працює, метрики рівні, а частина даних просто не доходить. Підписка зберігає повідомлення обмежений час і не чекає нескінченно: усе, що не підтверджено в строк, видаляється без повернення в чергу.
Перше вузьке місце — переповнення підписки. При піковому навантаженні публікація обганяє обробку: непідтверджені повідомлення та повтори накопичуються, лічильник очікуваних зростає, і обробник отримує більше, ніж здатен прийняти. Повідомлення не лежать у черзі вічно — хвіст сплеску витісняється раніше, ніж до нього дійде черга.
Друге — тайм-аут підтвердження. Обробник забирає повідомлення, йде у зовнішній виклик або важкий запит і не встигає підтвердити його у відведене вікно.
Сервіс вважає доставку невдалою і надсилає копію: зростають дублі та лічильник доставок, а за відсутності політики повторів повідомлення потрапляє в чергу недоставлених або стирається мовчки.
Третій сценарій — «залиплі» обробники: процес живий, метрики в нормі, але підтвердження не надсилається — втрачено контекст, потік заблоковано, контейнер іде в перезапуск.
Повідомлення ходить по колу, поки не сплине строк зберігання, і губиться рівно там, де потрібна була діагностика.
Усі три сценарії сходяться в одній точці — конфігурація підписки, недоставлених повідомлень і прав доступу до них. Розбираємо, де саме рветься потік і як це закривається.
Вимірний ефект: менше втрат, дублів і простоїв
Налаштування підписки змінює те, що видно в метриках. До нього збій обробника виглядає як тиша: повідомлення доставлено, підтверджено, обробник упав — і події немає ні в системі, ні в черзі.
Після налаштування все, що не пройшло обробку за задану кількість спроб, потрапляє в dead-letter: вони залишаються в черзі розбору, а не зникають.
Дублі — друга стаття втрат. Продовжене вікно підтвердження разом з ідемпотентністю за ключем події прибирають повторну обробку там, де вона не потрібна, а залишкові повтори стають безпечними: повторна доставка не створює другого запису і не проводить друге списання. Обсяг повторної обробки падає, бо частина збоїв закривається на боці підписки.
Третій ефект — час відновлення. Інцидент виявляється не за зверненням клієнта, а за алертом на вік найстарішого непідтвердженого повідомлення і на зростання dead-letter: черговий бачить проблему на початку, а не в кінці. Повернення в роботу — перемикання підписки на резервний обробник, це хвилини, а не години.
Зникає цілий клас інцидентів: «тиха втрата події», «подвійна обробка», «черга зростала добу, і ніхто не помітив».
Спостережуваність потоку будується на трьох сигналах — вік непідтверджених повідомлень, кількість доставок на повідомлення, обсяг dead-letter — і кожен прив’язаний до конкретної дії чергового.
Працюємо в інфраструктурі Google Cloud Pub/Sub: правила повторів, права доступу та пороги алертів задаються декларативно і версіонуються разом з кодом сервісу.
Режими Google Pub/Sub: підписки, підтвердження, повтори
У Google Pub/Sub режим доставки здається деталлю, поки потік один.
Щойно споживачів стає кілька, він задає, які збої ви отримаєте: виштовхувальна підписка приходить на вашу адресу і вимагає швидкої відповіді, витягувальна — забирає повідомлення сама, тому темп, розмір пакета і вікно обробки підбираються під навантаження.
Окремо вирішуються порядок і підтвердження. Ключ упорядкування прив’язує повідомлення до однієї черги — порядок тримається всередині ключа, але паралелізм падає.
Підтвердження обробки продовжує вікно: не встиг споживач — повідомлення повернеться в доставку, а після заданої кількості спроб піде в чергу недоставлених.
| Варіант | Коли підходить | Обмеження |
|---|---|---|
| Витягувальна підписка | власні сервіси, пакетна вибірка, високий темп | потрібен цикл опитування і власна логіка підтверджень |
| Виштовхувальна підписка | події в зовнішні сервіси, функції без постійного споживача | потрібна доступна адреса і швидка відповідь, вікном підтвердження не керуєте |
| Потокова обробка | безперервний потік з мінімальною затримкою | постійне з’єднання, складніше призупинити і відкотити |
| Кілька підписників | один потік на різні команди і сценарії | політики повторів і недоставлених у кожної свої, дублі гасить ідемпотентність |
| Ключ упорядкування | важливий порядок усередині однієї сутності | менше паралелізму, гарячий ключ стає вузьким місцем |
Режим доставки визначає клас відмов, який ви потім розбираєте на чергуванні. Нижче — як пов’язуємо підписки, права і моніторинг в одну керовану схему.
Порядок впровадження: від аудиту потоків до передачі регламентів
Порядок робіт будуємо так, щоб кожен крок закінчувався перевірюваним артефактом — схемою, конфігурацією або звітом про перевірку.
Починаємо не з налаштувань, а з аудиту потоків: помилку в схемі обміну повідомленнями простіше зловити на папері, ніж у проді під піковим навантаженням.
- Аудит потоків. Інвентаризація топіків і підписок Pub/Sub: хто публікує, хто читає, яка затримка допустима, де помилки не спливають у метриках.
- Проєктування схеми. Розкладаємо потоки за критичністю, фіксуємо топологію топіків і підписок, строк зберігання і окремий dead-letter-топік для необроблених повідомлень.
- Налаштування повторів. Політика повторів із затримкою між спробами, кількість доставок до відправлення в dead-letter, поведінка при відкликанні підтвердження: збійне повідомлення йде вбік, а потік продовжує йти.
- Доступи. Сервісні облікові записи та ролі за мінімально необхідним набором прав: підписник не публікує, збирач метрик не читає тіла повідомлень.
- Перевірка на відмовах. Відключаємо підписника, відкликаємо права, ламаємо обробник — дивимося, що відбувається з чергою, чи спрацьовують повтори, чи видно інцидент у моніторингу.
- Навантажувальна перевірка. Ганяємо профіль, близький до пікового: скільки тримає потік без зростання затримки, як зростає обсяг необроблених повідомлень, на якому темпі починаються масові повтори.
- Моніторинг і передача регламентів. Алерти на вік найстарішого непідтвердженого повідомлення, частку повідомлень у dead-letter і помилки публікації; інструкції для чергової зміни та порядок розбору інцидентів.
Комплект поставки: схеми потоків, політики доступу, регламенти
Комплект поставки — це не презентація, а робоча документація, за якою ваша чергова зміна та інженери діють без нас.
Усі налаштування Pub/Sub ми фіксуємо у вашому репозиторії: схеми, політики та регламенти версіонуються, зміни проходять рев’ю, а не живуть у чиїйсь пам’яті або листуванні.
- Схема потоків: топологія топіків і підписок, хто публікує і хто читає, які повідомлення вважаються критичними і який маршрут проходять при повторних спробах.
- Розділення середовищ: тестовий, передпродуктивний і бойовий контури живуть в окремих проєктах з незалежними правами і квотами — навантажувальний тест не може зчитати бойові дані.
- Політики доступу: ролі на рівні конкретних топіків і підписок, окремий обліковий запис на кожен сервіс, принцип мінімальних прав замість одного спільного ключа для всіх.
- Пороги оповіщень: зростання кількості необроблених повідомлень, вік найстарішого з них, частка помилок доставки і затримка публікації — із зазначенням норми та умови виклику чергового.
- Інструкції для чергових: покрокові сценарії на кожен тип збою — що дивитися першим, що безпечно перезапустити, коли ескалувати і кому.
- Регламент повторних спроб: скільки разів і з яким інтервалом повторюється доставка, за якої кількості відмов повідомлення йде в окрему чергу і як її розбирати.
- Карта володіння та порядок змін: хто відповідає за топік, через який процес проходить правка політик і як відкотити невдалу зміну за один крок.
Кейс: втрати подій у розрахунковому контурі — динаміка до і після
Потік розрахункових подій ішов через шину без розділення приймання та обробки: підписник підтверджував повідомлення одразу після отримання, а бізнес-логіка відпрацьовувала слідом.
Помилка зовнішнього модуля або тайм-аут призводили до того, що подія вважалася доставленою і зникала — розбіжність за звіркою спливала лише наступного дня, а пошук причини йшов вручну по логах.
Ми перебудували підтвердження: приймання фіксується окремо від результату обробки, невдалі спроби йдуть у повторну доставку з наростаючою затримкою, а ті, що не пройшли за відведену кількість спроб, потрапляють у чергу недоставлених повідомлень із збереженням початкового тіла і заголовків.
Доступ сервісів до топіків і підписок розвели за окремими ролями — обліковий запис завантажувача більше не може читати і видаляти чужі підписки.
Динаміка за метриками
| Метрика | До робіт | Після спостереження |
|---|---|---|
| Частка втрачених розрахункових подій | близько 2% на добу | нижче 0.05% |
| Виявлення збою обробки | на ранковій звірці | за алертом, хвилини |
| Ручний розбір інциденту | розбір усієї пачки логів | за ідентифікатором повідомлення |
| Відкат на попередню схему обробки | перезапуск контуру | перемикання версії підписника |
Контур працює на Google Cloud Pub/Sub, і ключовим виявилося не саме ввімкнення повторів, а узгодження вікна зберігання недоставлених повідомлень із часом реакції чергової зміни: якщо воно коротше, повідомлення губляться вже на виході з черги.
За підсумками місяця спостереження жоден розрахунковий день не закрився з розбіжністю, що потребувала ручної правки проводок.
Чим відрізняється недоставлене повідомлення від повторного
Межа проходить не за фактом невдалої обробки, а за лічильником спроб. Поки межу спроб не вичерпано, повідомлення залишається в підписці й повертається підписнику повторно — це штатний режим повторної доставки, а не помилка.
Платформа вважає повідомлення «в роботі» до підтвердження, і якщо підтвердження не надійшло за відведене вікно, повертає його в чергу видачі зі збільшеним номером спроби.
Політика повторів задає, як саме це відбувається: інтервал між спробами та його зростання від спроби до спроби. Наростаюча затримка потрібна, щоб сервіс, що падає, не отримував потік задач швидше, ніж встигає відновлюватися, а сусідні підписки не забивали спільний ресурс.
Поки помилка тимчасова — недоступність залежності, мережева затримка, сплеск навантаження — кількох циклів достатньо, і повідомлення йде в роботу.
Отруєні повідомлення поводяться інакше: обробник падає на кожному повторі з однієї і тієї самої причини. Невалідна схема, посилання на видалений об’єкт, порушення інваріанта даних — такі збої детерміновані, і нарощувати спроби безглуздо. Ознака рівно одна: однаковий клас помилки за різних спроб.
Коли лічильник доходить до межі, платформа зобов’язана вибрати: видалити повідомлення або відправити його в окрему чергу розбору. Черга розбору — це не архів і не смітник, а робоче місце чергового інженера: туди потрапляє лише те, що потребує ручного рішення або правки даних. Якщо її не завести, платформа відкине повідомлення, і слідів не залишиться.
Практичний висновок: повторна доставка лікує тимчасові відмови, черга розбору зберігає непоправне автоматично. Налаштовуйте строк зберігання та сповіщення в черзі розбору — інакше вона сама стане відкладеною втратою даних.
Технічні сумніви: затримки, дублі, розмежування прав
Затримки доставки — не збій, а властивість асинхронного обміну. У Google Cloud Pub/Sub шлях від публікації до обробки залежить від розміру батчу, вікна підтвердження і швидкості самого обробника.
Якщо підписник відповідає довше, ніж спливає вікно, брокер вважає повідомлення необробленим і віддає його повторно — так з’являються дублікати.
Схему будуємо так, щоб повтор був безпечний: ідемпотентні операції, ключ дедуплікації всередині повідомлення, окрема черга для того, що не вдалося розібрати за задану кількість спроб.
Права роздаємо за сервісними акаунтами — публікатор тільки публікує, підписник тільки читає і підтверджує, адміністративні ролі застосункам не видаємо.
Оповіщення вішаємо на глибину черги і вік найстарішого непідтвердженого повідомлення, а не на лічильник помилок у логах: саме ці метрики показують витрату ресурсів і відставання обробки.
Повідомлення приходять повторно — це помилка налаштування?
Ні, базова гарантія — доставка щонайменше один раз. Дублікати знімаються на боці обробника: ключ дедуплікації та перевірка стану перед записом. Упорядкування за ключем вмикаємо там, де порядок важливий, але ідемпотентність воно не замінює.
Як зрозуміти, що справа в правах, а не в коді?
Відмова публікації та порожня вибірка підписника виглядають схоже. Ми розводимо їх за журналом доступу: роздільні ролі на топік і на підписку одразу показують, де саме відмова. Доступ видаємо за мінімумом необхідного, тому розширювати його для налагодження не доводиться.
Налаштування впливають на витрату ресурсів?
Так. Розмір батчу, вікно підтвердження і строк зберігання недоставлених повідомлень визначають обсяг трафіку і зберігання напряму. Підбираємо їх під профіль навантаження, а не залишаємо за замовчуванням, і страхуємо оповіщеннями на зростання черги.
Обговоримо вашу схему обміну повідомленнями та точки відмови
Щоб повернутися з оцінкою і планом, а не із загальними словами, нам потрібна ваша поточна картина обміну повідомленнями.
Достатньо вивантаження конфігурації топіків і підписок, схеми потоків між сервісами та опису того, що зараз відбувається з повідомленням, яке споживач не обробив.
- Список топіків і підписок, їх призначення, хто виступає видавцем і хто споживачем.
- Як налаштовані повтори та черга недоставлених повідомлень: після якої кількості спроб повідомлення йде в dead-letter і хто розбирає її вміст.
- Ролі та права доступу: які облікові записи публікують і читають, де повноваження видані ширше, ніж потрібно.
- Що вже збирається в моніторингу: затримка доставки, обсяг нерозібраної черги, алерти і кому вони приходять.
- Відомі точки відмови: сплески навантаження, дублі, втрата повідомлень при перезапуску споживача, ручні розбори інцидентів.
- Вимоги до порядку робіт: що має працювати без простою і які зміни допустимі в робочий час.
Обговоримо задачу у форматі розбору: пройдемо за схемою обміну, відзначимо вузькі місця та точки відмови, зафіксуємо, що робимо в першу чергу. Опишіть вашу ситуацію — повернемося з оцінкою і планом робіт, де будуть етапи, зони відповідальності та спосіб перевірки результату.







