Недавно мы писали о том, как работают IT-архитекторы, а теперь расскажем подробности об одном из наших кейсов и покажем схему работы системы. В этом проекте мы помогли заменить «коробочное» банковское приложение на микросервисное ДБО, при этом наладив быстрый выпуск релизов – в среднем 1 раз в неделю.
Примечание: в нашем примере мы хотим показать, в чем монолитные приложения могут уступать микросервисным, особенно в финтех-решениях. В силу NDA мы можем делиться не всеми техническими подробностями проекта – однако, мы надеемся, что наш кейс может быть полезен тем, кто работает с онлайн-банками.
Проблемы «коробочного» монолита
Среди средних и малых компаний востребованы готовые IT-решения, которые можно кастомизировать и выпустить со своим логотипом. Минусы – функции приложений «из коробки» бывают ограничены, а обновления зачастую приходится вносить долго и исключительно через вендора.
Именно такую «коробочную» систему дистанционного банковского обслуживания (ДБО) использовал один из наших клиентов. Онлайн-банк представлял собой монолитное приложение с достаточно небольшим набором функций.
Для того, чтобы не уступать конкурентам, банку нужно было постоянно внедрять улучшения и новые фичи. Однако, даже для того, чтобы просто передвинуть кнопки в приложении, приходилось обращаться к вендору. Обновления выходили в среднем 1 раз в квартал.
Таким образом, развивать продукт было сложно из-за ряда ограничений:
- Вендор вносил желаемые изменения неприемлемо долго, а переписать мобильный интерфейс в конкретной «коробке» и вовсе было практически невозможно.
- Из-за сбоев в шине данных или «коробке» пользователи зачастую не могли войти в онлайн-банк.
- Работать с приложением пользователи могли только в том случае, если у них была установлена самая свежая версия.
- Для распределения нагрузки инстансы монолита были развернуты на нескольких серверах, каждый из которых обслуживал свою группу абонентов. При падении одного из серверов пропадал доступ у всех абонентов соответствующей группы.
- Вся экспертиза хранилась у производителя коробочного решения, а не в банке.
- Из-за того, что банк не мог оперативно внести изменения по просьбам пользователей, а функциональность была недостаточной по сравнению с конкурентами, появился риск оттока клиентов.
В результате банк принял решение – постепенно отказаться от «коробки» и разработать собственное ДБО, с микросервисной архитектурой, чтобы ускорить разработку функций и обеспечить удобство и безопасность для пользователей.
С чего мы начинали
Создание онлайн-банка началось с проектирования верхнеуровневой архитектуры, найма разработчиков в штат и подключения нашей выделенной команды. При этом архитектуру нужно было заложить с запасом прочности, в расчете на будущее расширение.
На старте наша команда Backend-разработчиков занималась реализацией отдельных базовых функций: например, денежными переводами. Однако, у нас был достаточно большой опыт работы с онлайн-банками, один из наших проектов к этому моменту вошел в отраслевой рейтинг Markswebb, поэтому мы предложили банку помощь в проектировании архитектуры – и получили «зеленый свет».
Архитектура
Вместе с владельцем продукта мы приняли решение использовать Spring Cloud, который предоставляет все необходимые функции для реализации микросервисной архитектуры: это и Service discovery – Eureka, Api Gateway – Zuul, Config server и многое другое. В качестве системы контейнеров для Docker-образов выбрали OpenShift, потому что инфраструктура банка была заточена под этот инструмент.
Также мы проанализировали, какие особенности старой «коробки» могут осложнять работу пользователей. Один из основных недостатков заключался в том, что система синхронно работала через шину данных, и каждое действие пользователей вызывало обращение к шине. Из-за больших нагрузок часто происходил отказ шины, при этом переставало работать все приложение. Кроме того, как и во многих старых банковских продуктах, накопилось легаси – «наследство» в виде старого и тяжеловесного CORE АБС, переписывать которое было бы сложно и дорого.
Мы предложили ряд улучшений:
- Версионирование
Ранее «коробка» поддерживала только одну версию, а в новом онлайн-банке мы предложили новую архитектуру, которая позволит поддерживать несколько различных версий одновременно и заменять их при необходимости.
Схема версионирования следующая: если минорная версия в сервисе изменилась, то сервис автоматически пересобирается и деплоится, заменяя устаревшую версию. Если мы ставим мажорную версию, то разворачивается новая копия сервиса с новой версией. Таким образом, разработка новых функций с изменением API сервиса не влияет на мобильное приложение, при этом сокращаются сроки тестирования. Такая система позволила обеспечить поддержку даже устаревших версий мобильного приложения, если у пользователя нет возможности обновиться.
- Асинхронность
Мы реализовали библиотеку, которую можно использовать в сервисах, где требуется асинхронная работа. Библиотека реализует выполнение асинхронных задач, подходит для использования на любом количестве копий сервисов, и они не мешают друг другу. Синхронизация между различными копиями производится с помощью очереди сообщений Kafka.
Это решение помогло повысить стабильность работы приложения. Мобильное приложение теперь не зависит от шины, необходимые пользователю данные мы дублируем в наших сервисах и обновляем их в «фоне», когда есть доступ к банковской шине. Все действия пользователя ставятся в очередь на исполнение, по мере готовности приходят PUSH-уведомления о результатах.
- Кэширование
Чтобы ускорить работу приложения и снизить нагрузку на внутренние банковские ресурсы, организовано кэширование данных с помощью Redis. В качестве кэша служит KeyDB, который показывает хорошие результаты и совместим со многими системами, использующими Redis. Данные кэшируются не после запроса пользователя, а при изменении пользовательских данных, что позволяет иметь к ним доступ независимо от внутренних банковских систем.
Что изменилось в системе
Как было отмечено выше, в старом онлайн-банке backend был выполнен в монолитной архитектуре, приложение разворачивалось на отдельной машине. При увеличении нагрузки приходилось разворачивать новые сервера. При падении сервера у некоторых пользователей полностью не работало мобильное приложение.
В новом решении использована микросервисная архитектура, что позволяет разворачивать столько копий сервисов, сколько требуется для того или иного функционала. Мы добавили кэширование данных на основе KeyDB, чтобы не только увеличить скорость получения информации, но и снизить нагрузку на базу данных.
Давайте рассмотрим пример получения данных по счетам пользователя в новой архитектуре. Запрос пользователя из мобильного приложения попадает через балансировщик на Gateway, который понимает, на какой из сервисов направить запрос. Далее попадаем на API сервис счетов. Сервис сперва проверяет, есть ли актуальные данные пользователя в Cache. При успешном исходе возвращает данные, в ином случае отправляет запрос в Middle сервис счетов.
Обновление данных в сервисе может происходить в различных случаях. Например, при непосредственном запросе от пользователя сервис создает задачу на обновление данных, которая выполняется асинхронно, и полученные из ESB данные обновляются. Также сервис получает сообщения из очереди сообщений и реагирует на них. Например, сервис получает сообщение о входе пользователя в приложение и сразу же обновляет данные по счетам, получает данные об операциях со счетом от других сервисов и обновляет у себя данные. Таким образом, пользователь всегда видит актуальные данные по своим счетам.
Среди наиболее важных изменений можно отметить следующие:
- Гибкость масштабирования
Для увеличения отказоустойчивости системы сервисы распределены по разным серверам. Это позволяет сохранять систему в работоспособном состоянии в случае падения одного из них. Для своевременного реагирования на нестандартные ситуации мы внедрили систему мониторинга, это помогло при необходимости вовремя масштабировать сервисы. Подключили DevOps для настройки с нуля CI/CD на серверах клиента, выстроили процессы развертывания и поддержки будущего приложения на нескольких серверах.
- Ускорение релизов за счет версионирования
Ранее при обновлении мобильной версии одни пользователи уже применяли новую версию, а другие нет, но число последних было минимально. При разработке нового ДБО мы реализовали версионирование и возможность выпускать релизы без риска, что приложение перестанет работать у большой части клиентов. Сейчас при реализации отдельных функциональностей в новых версиях мы не ломаем старые версии, а значит, нет необходимости проводить регресс. Это помогло ускорить частоту релизов минимум в 15 раз – теперь релизы выходят в среднем 1 раз в неделю. Команды Backend и Mobile могут одновременно и независимо работать над новыми функциональностями.
Подводя итоги
В этом примере мы рассказали о проектировании микросервисной архитектуры банка, которая пришла на смену «коробочному» монолитному решению. Над этим проектом работала распределенная команда, которая включала как штатных разработчиков, так и аутсорсеров.
При разработке онлайн-банка мы стремились к тому, чтобы реализовать в новом приложении такой же объем функций, как в коробочном, и постепенно развивать его.
Для того, чтобы не допустить оттока клиентов, нужно было наладить безотказную работу приложения, без сбоев и простоев, и регулярный выход релизов и обновлений. Осуществить это удалось благодаря улучшениям в архитектуре. В частности, после снижения нагрузки на базу данных мы добились постоянной доступности приложения, а за счет версионирования сократили сроки тестирования, обеспечили возможность независимой работы над функциональностями и выпуска релизов 1 раз в неделю.
Архитектура приложения заложена с учетом дальнейшего роста продукта и инструментов разработки, которые использует банковская инхаус-команда, чтобы владелец продукта мог самостоятельно вносить любые доработки в ДБО. Сроки активной разработки альфа-версии составили около года, еще через 3 месяца вышла бета-версия для всех пользователей.
Надеемся, что описанная схема работы может быть полезна при создании других финтех-продуктов.
Спасибо за внимание!
solver
Как будто обычно архитектуру закладывают без запаса прочности и возможности расширения, а тут вот особенный кейс такой, что надо с запасом и чтобы приложение можно было расширять)
VolCh
Видимо явное требование было, что не всегда бывает.
anonymous Автор
Запас прочности нужен всем, но на практике встречается не так уж часто. У нас достаточно много проектов в работе, и зачастую на старте новых проектов мы находим те или иные недочеты в архитектуре. На ее закладку может не хватать знаний, времени, иногда опыта. Так что считаем, что об этом надо помнить и говорить)