У 2018 році, коли Kafka Streams ще тільки набирала обертів, 20‑річний розробник із Кіто Матео Рохас отримав завдання, яке сьогодні багато хто назвав би надто сміливим: побудувати реальну фінансову систему управління полісами на базі щойно народженої стрімінгової технології. У розмові на Confluent Developer Podcast він детально описує, як команда спроєктувала платформу ануїтетів, що покладалася на Kafka Streams для оркестрації KYC, AML і клірингу коштів, та чому Kafka фактично стала єдиним джерелом істини для всього продукту.

Це історія не лише про складну фінансову логіку, а й про те, як виглядає «event‑driven» банківська система, коли всі критичні рішення приймаються на основі подій у Kafka, а стан застосунків відновлюється простим програванням топіків.
Ануїтет як продукт: реальні гроші поверх подій
Бізнес‑логіка платформи була зрозумілою для фінансистів, але вимагала бездоганної технічної реалізації. Користувач заходив на веб‑сторінку, купував поліс ануїтету — наприклад, трирічний продукт із 3% річних на депозит у 10 000 доларів — і очікував, що гроші почнуть «працювати». Для розробників це означало одне: жодна помилка в обробці подій не могла призвести до подвійного нарахування відсотків чи активації полісу без належних перевірок.
Щойно користувач оформлював поліс, у системі створювалася подія, яка запускала ланцюжок перевірок і взаємодій з третіми сторонами. До активації полісу та початку нарахування відсотків потрібно було виконати три критичні кроки:
- Перевірка KYC (Know Your Customer) — ідентифікація клієнта.
- Перевірка AML (Anti‑Money Laundering) — виявлення можливого відмивання коштів.
- Кліринг коштів у банку — підтвердження, що 10 000 доларів дійсно надійшли й доступні.
Кожен із цих кроків реалізовувався як окремий зовнішній або внутрішній сервіс, який працював у власному темпі, повертав результат асинхронно й публікував його назад у Kafka. Завдання платформи полягало в тому, щоб коректно «зібрати» ці результати й лише тоді вважати поліс активним.
Оркестрація KYC, AML і клірингу: Kafka Streams як координатор
Замість централізованого оркестратора команда обрала підхід, де саме Kafka Streams виступає «мозком» процесу. Архітектурно це виглядало так: кожен зовнішній сервіс — KYC, AML, банківський кліринг — після завершення своєї роботи надсилав результат у відповідний топік Kafka. Наприклад, сервіс AML, отримавши запит через вебхук, виконував власні перевірки, а потім публікував подію з результатом у топік AML‑перевірок.
Ключовою вимогою було те, що поліс не міг перейти в активний стан, доки система не отримає три незалежні підтвердження:
- успішний KYC,
- успішний AML,
- підтверджений кліринг коштів.
Ці три події надходили в різні топіки, у різний час і з різних систем. Щоб визначити момент, коли всі умови виконано, команда використала можливості Kafka Streams для приєднання (join) потоків.
Join трьох топіків за policy ID
У центрі рішення лежала ідея: усі події, що стосуються одного й того самого полісу, мають однаковий ключ — policy ID. Це дозволило побудувати в Kafka Streams приєднання трьох топіків, кожен із яких містив результати одного з етапів:
- топік результатів KYC,
- топік результатів AML,
- топік клірингу коштів.
Kafka Streams, отримуючи події з цих трьох джерел, мала «зрозуміти», коли для конкретного policy ID з’явилися всі три записи. Лише тоді система могла згенерувати подію «policy activated» і запустити нарахування відсотків за ануїтетом.
На практиці це означало, що логіка активації полісу була повністю подієвою: не існувало централізованої транзакції в класичному реляційному сенсі. Натомість було три незалежні події, які з’єднувалися за ключем policy ID у стрімінговому процесорі.
Вікна приєднання: чому довелося мислити «роками»
Реалізація приєднання в Kafka Streams виявила важливу деталь, яка сьогодні здається очевидною, але тоді стала неприємним сюрпризом: join працює лише в межах заданого часовго вікна. Якщо одна з трьох подій для певного policy ID приходила за межами цього вікна, приєднання не відбувалося, навіть якщо всі три події фізично були в топіках.
Для банківської системи це створювало серйозний ризик. KYC, AML і кліринг коштів можуть мати різну тривалість: одна перевірка завершується за хвилини, інша — за години чи навіть дні, особливо якщо залучені зовнішні провайдери або міжнародні банки. Відмовитися від активації полісу лише тому, що подія прийшла «занадто пізно» для вікна join, було неприйнятно.
Команда обрала радикальний, але прагматичний для того часу підхід: налаштувати вікно приєднання, вимірюване роками. Ідея полягала в тому, щоб практично усунути ризик того, що якась із трьох подій вийде за межі вікна. З технічної точки зору це не виглядало елегантно, але відповідало бізнес‑реальності: поліс може проходити перевірки довго, а система не має права «забути» про нього через обмеження стрімінгового вікна.
Це рішення добре ілюструє, як у реальних фінансових продуктах архітектори змушені підлаштовуватися під обмеження інструментів, не жертвуючи при цьому коректністю бізнес‑процесу. Kafka Streams забезпечувала механізм join, але його потрібно було налаштувати так, щоб він відповідав часовій природі банківських перевірок.
20 мікросервісів навколо Kafka: події як єдине джерело істини
Платформа ануїтетів не обмежувалася лише KYC, AML і клірингом. Навколо Kafka виросла повноцінна мікросервісна екосистема — близько двадцяти сервісів, кожен із яких споживав події з багатьох топіків і реалізовував власну бізнес‑логіку.
Ці сервіси відповідали за різні аспекти життєвого циклу полісу: від створення й активації до нарахування відсотків, звітності, інтеграцій із зовнішніми системами та внутрішньої аналітики. Важливо, що всі вони були побудовані навколо однієї ідеї: Kafka — це не просто транспорт, а головне джерело істини.
Kafka як «журнал правди»
Рішення трактувати Kafka як основний шар істини означало, що події в топіках вважалися канонічними даними про стан системи. Локальні бази даних мікросервісів, кеші чи проєкції розглядалися як похідні, які можна відновити в будь‑який момент, якщо зберігається повний журнал подій.
Цей підхід дав кілька важливих переваг.
По‑перше, він спростив відновлення після збоїв. Якщо якийсь мікросервіс втрачав свій локальний стан або потребував міграції, його можна було просто «перезапустити» з початку відповідних топіків, програти всі події й відбудувати актуальний стан. У світі, де ануїтети йдуть роками, а історія транзакцій має критичне значення, це особливо цінно.
По‑друге, така модель дозволила уникнути складних розподілених транзакцій між мікросервісами. Замість узгоджених транзакцій між базами даних різних сервісів, узгодженість досягалася через послідовність подій у Kafka. Якщо подія про активацію полісу є в топіку, усі сервіси, які її споживають, рано чи пізно приведуть свій локальний стан у відповідність до неї.
По‑третє, це створило чітку точку спостереження за системою. Аналітика, аудит, розслідування інцидентів — усе це можна було будувати, читаючи ті самі події, які використовувалися для бізнес‑логіки.
Самокерований кластер Kafka на Kubernetes
Сьогодні керовані сервіси на кшталт Confluent Cloud чи AWS MSK стали стандартом для багатьох команд, що працюють із Kafka. Але в часи, коли створювалася платформа ануїтетів, таких опцій для цієї команди фактично не було.
Довелося розгортати власний кластер Kafka на Kubernetes, налаштовувати брокери, зберігання, реплікацію, моніторинг і оновлення самостійно. Це додавало ще один рівень складності до вже непростої задачі побудови фінансової системи на базі стрімінгової платформи, яка сама перебувала в активній еволюції.
Самокерований кластер означав, що будь‑які проблеми з продуктивністю, доступністю чи зберіганням безпосередньо впливали на «журнал істини» всієї системи. У такій моделі рішення «Kafka — це джерело істини» автоматично тягне за собою вимогу: інфраструктура Kafka має бути максимально надійною, бо від неї залежить відновлюваність і коректність усіх мікросервісів.
Як відновлювали стан: реплей топіків як базова операція
Коли Kafka використовується як основний шар істини, реплей топіків — не екзотична операція, а повсякденний інструмент. У платформі ануїтетів це стало ключовим механізмом для відновлення стану застосунків і перевірки коректності роботи системи.
Якщо мікросервіс змінював свою модель даних, логіку обробки або просто виходив із ладу, команда могла:
- Очистити або скинути локальний стан сервісу.
- Перезапустити його споживачів Kafka.
- Програти всі релевантні топіки з початку або з певної точки.
- Відновити повний стан на основі історії подій.
У контексті ануїтетів це означало, що система могла знову «прожити» весь життєвий цикл полісів — від створення до активації та нарахування відсотків — і відтворити фінансовий стан так, ніби нічого не сталося. Для банківських продуктів, де помилки в балансах чи історії транзакцій неприпустимі, це критично важливо.
Такий підхід також допомагав у тестуванні. Можна було розгорнути тестове середовище, програти реальні або анонімізовані події з продакшн‑топіків і перевірити, чи нова версія мікросервісів приходить до того самого кінцевого стану, що й попередня. Це давало додаткову впевненість у тому, що зміни в логіці не порушують фінансову коректність.
Висновки: що показує цей експеримент із Kafka Streams для фінансів
Історія платформи ануїтетів, побудованої на Kafka Streams у 2018 році, демонструє, як далеко можна зайти, якщо трактувати Kafka не просто як шину повідомлень, а як фундаментальний шар істини для всієї фінансової системи.
По‑перше, вона показує, що оркестрація складних процесів на кшталт KYC, AML і банківського клірингу може бути реалізована повністю подієвою моделлю. Три незалежні події, що надходять із різних систем, можуть бути надійно зведені разом за допомогою join у Kafka Streams, якщо уважно ставитися до таких деталей, як часові вікна.
По‑друге, архітектура з приблизно двадцяти мікросервісів, які споживають безліч топіків і будують власну логіку поверх подій, добре масштабується за функціональністю, але вимагає чіткої дисципліни: усі мають погодитися, що Kafka — це джерело істини, а локальні стани — лише похідні.
По‑третє, рішення покладатися на реплей топіків як на базовий механізм відновлення стану виявилося потужним інструментом для стійкості й тестованості. У світі, де ануїтетні поліси живуть роками, а історія транзакцій має зберігатися без втрат, можливість «переграти» всю історію подій — це не розкіш, а необхідність.
Нарешті, цей досвід підкреслює, що навіть у ранні роки Kafka Streams була здатна тягнути на собі реальні банківські продукти з живими грошима — за умови, що команда готова глибоко розуміти обмеження інструменту й будувати архітектуру навколо них. Вікна join, самокерований кластер на Kubernetes, десятки мікросервісів і реплей як стратегія відновлення — усе це стало частиною інженерної «ціни» за можливість мати подієву, гнучку й відновлювану платформу ануїтетів.
Джерело
Building Banking Systems with Kafka Streams with Mateo Rojas | Ep. 28 | Confluent Developer Podcast


