Как стать автором
Обновить

Как мы переписали платёжный сервис в банке

Уровень сложностиСредний
Время на прочтение7 мин
Количество просмотров3.5K

Привет, Хабр! Меня зовут Александр, я работаю в банке. Банк обслуживает более 15 миллионов клиентов – преимущественно физлиц с классическими банковскими продуктами и инвестиционными сервисами. Хочу поделиться нашим опытом модернизации "платёжного сервиса" – системы, которая дирижирует почти всеми нашими платежами. Проект стартовал в конце 2022 года, и через год мы успешно запустили новую систему в промышленную эксплуатацию.

TL;DR: За год мы мигрировали с монолитного IBM WebSphere на Java/Spring Boot, Apache Kafka, PostgreSQL и событийную архитектуру. Решили проблемы с производительностью, масштабируемостью и подготовились к будущим вызовам.

Зачем вообще банку отдельный платёжный сервис?

Любой банк проводит массу платежей и переводов: клиенты платят за ЖКХ, мобильную связь, переводят деньги друг другу и организациям. Каждая такая операция — это финансовая транзакция: у одного деньги списываются, у другого — появляются. Эти изменения отражаются в "главных книгах" банка, которые ведут так называемые АБС (автоматизированные банковские системы) — наши мастер-системы.

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

Важно: речь не идёт об эквайринге (обработке карточных операций в рознице) – это отдельная вселенная. Также наш сервис не хранит остатки по счетам, он только оркестратор.

Как выглядит платёжный процесс?

Платёжные процессы могут отличаться в разных банках и для разных типов платежей. Тем не менее, "душа" процесса может быть представлена в таком виде:

Платёжный процесс
Платёжный процесс
  1. Клиент создаёт платёжное поручение (например, в мобильном банке).

  2. Поручение проходит проверки.

  3. Деньги списываются/блокируются у отправителя.

  4. Деньги зачисляются получателю.

  5. В главной книге формируются финальные бухгалтерские проводки.

Процесс этот неинтерактивный (клиент не ждёт у экрана, пока всё пройдёт), линейный (без циклов назад, но с ветвлениями), транзакционный (либо всё, либо ничего, хотя "всё" не всегда означает зачисление в стороннем банке в ту же секунду) и быстрый (секунды внутри операционного дня банка).

Что нас не устраивало в старом монолите?

Раньше всё это жило на монолитном приложении внутри IBM WebSphere Application Server (WAS) под управлением AIX. Данные хранились в Oracle. Вся интеграция была построена на SOAP.

В общем виде архитектура выглядела следующим образом:

Архитектура устаревшего Платёжного сервиса
Архитектура устаревшего Платёжного сервиса

Основные боли

  • Производительность. Онлайн-платежи проходили относительно нормально, но пакетные операции (массовые зачисления зарплат) ставили систему в трудное положение. Жёсткие временные рамки часто не соблюдались.

  • Устаревший стек. Продукты IBM и их доступность в РФ.

  • Масштабируемость и T2M. Наращивать скорость обработки было почти невозможно. Новые типы платежей и доработки старых требовали титанических усилий, а Time-to-Market был удручающим.

Архитектурные принципы для новой системы

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

  • Независимое масштабирование. Ускоряем только те участки, где это нужно.

  • Модульность От монолита отказались. Но и цели "перейти на микросервисы" строго в их каноническом виде не было.

  • Слабая связанность. Модули максимально независимы друг от друга.

  • Горизонтальное масштабирование. Больше нагрузки – больше экземпляров модуля.

  • Изоляция отказов. Падение одного модуля не должно затрагивать платежи, которые через него уже пролетели, а тем более ронять всё.

  • Независимые доработки. Рутинные и незначительные доработки локализованы в конкретных модулях.

  • Минимальное технологическое разнообразие. Зрелые, известные команде технологии.

  • Без SPOF. Никаких общих оперативных БД или единых оркестраторов.

Важно: Платёжный сервис не автономен. Он зависит от АБС, где хранится главная книга и ведутся счета. Так что некоторые принципы действуют только до потолка, который задаёт АБС. Справедливости ради, в наших условия потолок был скорее теоретический.

Ограничения, с которыми пришлось смириться

  • Запрет на изменения бизнес-процесса. Платёжные процессы переносились "как есть", даже если их можно было оптимизировать.

  • Последовательный переезд. Платежи разных категорий переезжали в новую систему по очереди. Нужно было обеспечить совместную работу старой и новой систем.

Новая архитектура платёжного сервиса

Целевая архитектура нового платёжного сервиса
Целевая архитектура нового платёжного сервиса

Инфраструктура и стек

Все компоненты развёрнуты на серверах x86. Модули написаны на Java + Spring Boot и крутятся в нашем кластере OpenShift. К началу развёртывания OpenShift уже вовсю использовался в банке.

Внешний API

API реализован двумя независимыми модулями:

  • Модуль приёма платежей. Принимает поручение клиента, проводит первичную валидацию и быстро отвечает синхронно. Если всё ОК — запускает асинхронный процесс.

  • Модуль консолидации. Инфо-API. Обслуживает информационные запросы (статус платежа, история), отправляет уведомления.

Это разделение позволяет:

  • Не забивать канал приёма платежей тяжелыми информационными запросами.

  • Разделить приём и информирование по отказам.

СУБД "только для чтения"

Используем PostgreSQL, но только как витрину для модуля консолидации. В самом процессе обработки платежа эта БД не участвует. Напрямую использовать эту БД в модулях запрещено. Если она упадёт, приём и обработка платежей продолжатся, просто не будет работать инфо-API.

Интеграция: Kafka как кровеносная система

Apache Kafka стал основой для обмена данными между модулями. Это идеально ложится на асинхронную природу процесса, обеспечивает слабую связанность и параллельную обработку. Kafka Topic – ключевая единица, семантически разделяющая потоки данных.

Оркестрация или Хореография?

Мы выбрали паттерн «хореография» без центрального оркестратора. Это соответствует нашим принципам отсутствия SPOF и независимого масштабирования. Каждый модуль независимо реагирует на события и сам знает, что делать.

Модули и функции: рабочие лошадки

Система состоит из модулей, каждый из которых отвечает за определённый этап или подпроцесс. Модуль содержит одну или несколько функций, реализующих конкретную логику. Функции активно используют Kafka Streams для потоковой обработки платежей.

Архитектура модулей

Как модули общаются и работают: JSON по Kafka

Модули обмениваются JSON-документами через Kafka. Этот документ содержит всю информацию о платеже: канал поступления, данные поручения, техническую информацию и, главное, бизнес-статус.

Каждый модуль "умеет" обрабатывать документы только с определённым статусом (или набором статусов). После обработки модуль меняет статус и отправляет документ дальше. Это позволяет добавлять новые модули и статусы, расширяя систему.

Общая стратегия разделения на модули

  • Каждый модуль выполняет выраженную работу и меняет бизнес-статус.

  • Этапы бизнес-логики, всегда идущие вместе друг за другом, остаются в одном модуле.

  • Разветвление процесса – точка разделения на модули.

Логика работы типового модуля

  1. Принять документ из входящего Kafka-топика.

  2. Выполнить свою бизнес-логику (функцию), возможно, сходив во внешние системы. Как, например, АБС.

  3. Обогатить документ новыми данными (если нужно).

  4. Изменить бизнес-статус документа.

  5. Отправить обновлённый документ в исходящий Kafka-топик.

Архитектура типового модуля показана на иллюстрации:

Общая архитектура типового модуля
Общая архитектура типового модуля

Подписки и маршрутизация

Каждый модуль подписан на один или несколько входных топиков. Маршрут документа (т.е. в какой следующий топик его отправить) определяется на основе его текущего бизнес-статуса и общей таблицы маршрутизации. Эта таблица – своего рода конфигурация, связывающая статусы и топики.

Принцип работы "маршрутизации"
Принцип работы "маршрутизации"

Многие доработки модуля сводятся просто к изменению таблицы маршрутизации.

Композитные модули

Если модуль содержит несколько функций (например, основную и dummy-альтернативу "пропустить без изменений"), нужная функция выбирается селектором на основе флагов в заголовке Kafka-сообщения.

Модуль консолидации и топик NOTIFY

Чтобы иметь актуальную информацию по всем платежам для инфо-API и уведомлений (ведь центральной оперативной БД нет), каждый модуль после обработки отправляет копию документа в специальный топик NOTIFY. Модуль консолидации читает этот топик, "схлопывает" серию записей по каждому платежу до последнего актуального состояния и обновляет свою витрину на PostgreSQL.

Принцип работы "консолидации"
Принцип работы "консолидации"

Предварительные результаты

Производительность

  • Время отклика API (модуль приёма): от секунд в "сложные" часы до миллисекунд в любые.

  • Пакетная обработка: ускорение в 3-5 раз по сравнению со старой системой. Проблемы уложиться в допустимое окно больше нет.

  • Экономия ресурсов: в сравнении с прошлым вариантом на WAS, новый сервис почти не нагружает железо. Глядя на график загрузки CPU, сначала не поверили и пошли перепроверять.

  • Пропускная способность на входе: рост с ~1000 до 5000+ платежей в минуту на пиках.

Надёжность

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

Lessons Learned

  • Заранее учитывать сложность отладки. Найти проблему, когда она размазана по нескольким модулям и топикам Kafka – тот ещё квест. Бывало, приходилось искать зависшие платежи и почти вручную "толкать" их.

  • Если идёшь в новую парадигму, её понимать должны все. Начиная, мы думали, что событийный подход понимают все, кому это требовалось. По факту многое пришлось доносить практически "на пальцах" уже в процессе работы.

  • Eventual Consistency сложнее, чем кажется. Особенно, когда речь заходит про деньги и жёсткие регуляторные требования. С этим нужно научиться жить. Во многих местах нужно придумывать нетривиальные решения.

  • Репартиционирование Kafka дорогое. Немного недооценили, как оно влияет на устойчивость системы в первых версиях архитектуры.

  • PostgreSQL – не самая лучшая опция. А вот PostgreSQL мы переоценили. Даже в относительно второстепенной роли витрины для инфо-API. Медленный и архаичный.

Заключение

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

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

А пока – спасибо за прочтение! Какой у вас опыт модернизации подобных систем? Делитесь в комментариях!

Александр Читалкин, руководитель офиса архитектуры.

Продолжение следует.

Теги:
Хабы:
Всего голосов 5: ↑4 и ↓1+6
Комментарии6

Публикации

Работа

Ближайшие события