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

От монолита к микросервисам: ускорили банковские релизы в 15 раз

Время на прочтение7 мин
Количество просмотров9.5K
Всего голосов 7: ↑7 и ↓0+7
Комментарии34

Комментарии 34

При этом архитектуру нужно было заложить с запасом прочности, в расчете на будущее расширение.

Как будто обычно архитектуру закладывают без запаса прочности и возможности расширения, а тут вот особенный кейс такой, что надо с запасом и чтобы приложение можно было расширять)

Видимо явное требование было, что не всегда бывает.

Запас прочности нужен всем, но на практике встречается не так уж часто. У нас достаточно много проектов в работе, и зачастую на старте новых проектов мы находим те или иные недочеты в архитектуре. На ее закладку может не хватать знаний, времени, иногда опыта. Так что считаем, что об этом надо помнить и говорить)
День добрый! Спасибо за интересную статью.

Ряд вопросов:
1. Как именно вы поддерживаете совместимость мобильного и веб клиентов с логикой бэка (совместимость старых версий через подмену статусов и логики из новых)?
2. Как идет разработка и поставка мобильного клиента и интеграции в бэке (отдельная ветка в Git для каждой версии клиента и описание интеграции в бэке под каждую версию или как-то иначе)? Сюда же неплохо было бы пояснение про стабильные релизы и вашу версионность — тема не раскрыта.
3. Как именно идет обработка счетов (так как счета нужны практически для любых продуктов банка)? Что за логика под Middle сервисом счетов?
4. Как у вас организовано получение данных клиента (так как данные клиента нужны для любых продуктов банка)? Все хранится в какой-то БД и подгруажется в кэш? Или внешняя система -> кэш? Шина -> кэш? Как обеспечивается отказоустойчивость?
5. В случае критической ошибки на минорной версии (например, берется не тот счет для операции, что не противоречит автотестам, но противорчит логике) — она у вас сразу деплоится с ошибкой? Не слишком ли это рискованно?
6. Как у вас организован процесс электронной подписи? Вы храните подпись где-то или клиент каждый раз для каждого сервиса должен подгружать ключ?
Спасибо за ваши вопросы, уточним некоторые данные и вернемся с ответом.
Сразу отметим, что базы данных для микросервисов изолированы друг от друга, что позволяет конфигурировать серверы баз данных для обеспечения требуемой доступности и скорости работы. Просим извинить, если по тексту сложилось другое впечатление.
Как и обещали, мы уточнили эти вопросы с командой, постараемся ответить по пунктам.
1. Новый бэк пока используем только для нового мобильного приложения.
2. Мобильное приложение завязывается на определенный протокол взаимодействия с API сервера. На gateway указывается, какие версии сервисов соответствуют этому протоколу. Таким образом backend может релизить новые версии сервисов по их готовности, а когда мобилка, в свою очередь, готова с ними работать, мы выпускаем новый протокол.
3. Не совсем понятен вопрос, вы не могли бы конкретизировать?
4. Есть сервис, ответственный за данные клиента, который получает из АБС актуальные данные и хранит у себя в БД. При недоступности АБС данные могут браться из БД сервиса, если мы понимаем, что они актуальные (обновлялись недавно).
5. Есть несколько стендов, в том числе тест/предпрод. Такие ошибки выявляются на этапе тестирования.
6. К сожалению, не можем раскрыть эти подробности о проекте.
Уточняю по третьему вопросу: если в системе используется интеграция с несколькими вендорами (такими, как BankMaster) — идет типизация и перетипизация счетов для продуктов запросами во внешние системы. Из-за этого никаких адекватных (быстрых) вариантов с кэшем быть не может. Как реализовано у вас?

Уточняю по второму вопросу: как именно вы обходите конфликт версий? Если версия 1.4.123, к примеру, использовала адрес клиента одной строкой, а в новой версии 1.5.0 необходимо использовать две строки, то как вы это обходите? Делаете костыль для склеивания строк для старой версии (соответветственно, это идет адаптация под старые версии), дублируете данные (для старой и для новой версии), изначально предусматриваете в старой версии гибкость (дозагрузка атрибутов и ключей с бэка — в приложении просто абстрактная логика работы с тремя-четырьмя типами полей), предусматриваете более жесткие меры (отключение функционала для старых версий)?
1. Таких кейсов не удалось вспомнить, поэтому подсказать, к сожалению, не можем.
2. Разные версии сервисов имеют разный API, соответственно МП работает со «своим» сервисом.
Здесь вопрос доработки таблиц базы данных для разных версий. В большинстве кейсов разные версии одного сервиса работают с одной таблицей. Есть кейсы, когда новый сервис будет использовать новые поля. Мы добавляем их в таблицу. Старый сервис продолжит только считывать данные и отправлять их пользователю. А новый сервис будет обновлять данные. Принцип немного похож на CQRS.
Судя по вашим ответам (без конкретики по ускорению и стабильности — не указаны статистические данные при заявленном ускорении в 15 раз; так и не получил никаких конкретных пояснений по версионности и веткам в Git, только общие пояснения), у вас SOA, а не микросервисы (увидел только одно место, где может быть микросервис); очень скромный функционал (только мобильный клиент со скромным для универсального (без жесткой специализации — кредитный или обменный) банка функционалом, если судить по описанным сервисам), который можно и монолитом с мажорной версионностью делать быстро и просто без особых трудностей. Как вывод, с учетом ваших ответов, использование микросервисов и ряда представленных решений здесь экономически и технически нецелесообразно.
NDA накладывает на нас определенные ограничения. Нам очень жаль, что мы не можем раскрыть подробности в достаточной степени для более детального обсуждения. Огромное спасибо за проявленный интерес и ваши комментарии. Желаем вам интересных проектов и вызовов в работе!

Вопросики:


1) Я один сломал мозг представив это? Кто, кого, когда обновляет… 3 абзаца абсолютно в разные направлениях. Просто прочитайте что вы написали:


KeyDB, Данные кэшируются не после запроса пользователя, а при изменении пользовательских данных, что позволяет иметь к ним доступ независимо от внутренних банковских систем.

API сервис счетов. Сервис сперва проверяет, есть ли актуальные данные пользователя в Cache. При успешном исходе возвращает данные, в ином случае отправляет запрос в Middle сервис счетов.

Например, сервис получает сообщение о входе пользователя в приложение и сразу же обновляет данные по счетам

2) По асинхронности, "сервис получает сообщение о входе пользователя в приложение и сразу же обновляет данные по счетам". Правильно я понимаю что всё асинхронно и допустим высокая нагрузка на систему, и я быстро зайду на страницу счетов, то могу увидеть старые данные? Считаете ли вы приемлемо такое в приложениях уровня финансы?


3) Вы используете кафку, так почему вы делаете столько промежуточных лишних звеньев(балансировщики, самодельные сервисы, кэши, сигналы для обновления кэшей), а не считаете в реалтайме в кафке?
Актуальный баланс можно сразу получать с помощью kafka\ktable в реальном времени. А изменения будут в виде отправить сообщений в топик balance {userId: 1, balance: +40},{userId: 1, balance: -40}

Не один. Тут даже архитектурно у них микросервисы нарисованы, а по рисунку и описанию дальше — чистый веб SOA. Вот Middle сервис счетов — это уже не микросервис, а часть веб SOA; сервис вызывается, когда данные отличаются от хранимых в кэше, что еще раз не микросервисная реализация. При этом написано, что данные обновляются только, если они изменились, при этом: «сервис получает сообщение о входе пользователя в приложение и сразу же обновляет данные по счетам»… Могу единственно предположить, что говорится про запуск проверки актуальности данных. Так?
— В идеальном мире, конечно же, хочется видеть сразу актуальные данные на момент входа. В реальном мире можно использовать, например, систему push уведомлений, которая сообщит мобильному приложению, что счета на сервере обновились и их можно оперативно подгрузить.
— Что касается №3, нам бы это решение не подошло, как минимум из-за единой точки отказа.
>Сейчас при реализации отдельных функциональностей в новых версиях мы не ломаем старые версии

Как это отражается на необходимости и трудоемкости поддержки старых версий, апи, итп?
При этом архитектуру нужно было заложить с запасом прочности, в расчете на будущее расширение

И поэтому вы выбрали микросервисы? Вы не видите в этом противоречие? Микросервисы это изоляция по функционалу и по данным (каждый микросервис должен хранить данные в своей базе данных иначе считается что это не настоящие микросервисы). Ок, вы построили архитектуру и разбили по микросервисам — например платежами/переводами занимается один сервис а данными юзеров занимается второй сервис. Правильно? А потом на следующий день прилетает задача — вот мы хотим добавить программу лояльности и начислять юзеру какие-то баллы за переводы. И теперь для реализации этой задачи микросервису переводов нужно общаться с микросервисом который хранит данные юзеров. А теперь вопрос — как вы будете решать race-conditions и атомарное выполнение этой бизнес-логики? Речь не только про потерю связи, логику retry-ев на транспортном уровне (https://habr.com/ru/company/yandex/blog/442762) а про более фундаментальную проблему консистентной обработки данных и serializable уровня изоляции транзакций — https://www.youtube.com/watch?v=5ZjhNTM8XU8
В общем микросервисы можно применять только когда проект уже устоялся и не планирует расширяться, иначе добавление нового функционала имеет тенденцию увеличивать связность данных а это в свою очередь требует атомарного выполнения бизнес-логики которая обращается к разным микросервисам и реализации распределенных serializable-транзакций (иначе привет race-conditions и неконсистетность данных и дыры в безопасности)

Проблема передачи транзакционного и секурити контекстов а так же калбэки — это типичная проблема микросервисов, реализованных через REST/SOAP, но, с другой стороны, никто не запрещает использовать другие протоколы, где эти вопросы решены, например RMI.
Ок, вы построили архитектуру и разбили по микросервисам — например платежами/переводами занимается один сервис а данными юзеров занимается второй сервис. Правильно?

Нет, неправильно. Нет никакого «сервиса юзеров». разные поля данных, относящиеся к юзеру хранятся в разных сервисах.

прилетает задача — вот мы хотим добавить программу лояльности и начислять юзеру какие-то баллы за перевод

теперь для реализации этой задачи микросервису переводов нужно общаться с микросервисом который хранит данные юзеров

Нет, не нужно. Данные относящиеся к программе лояльности должны лежать в сервисе программы лояльности, даже если они относятся как 1 к 1 к user_id
В общем микросервисы можно применять только когда проект уже устоялся и не планирует расширяться, иначе добавление нового функционала имеет тенденцию увеличивать связность данных

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

Как заметили выше, если микросервисы обращаются к единой БД, то это не кошерный микросервис, а скорее, просто веб сервис. В этом случае теряется смысл их разбивать, так как велико количество внутренних связей. Но это все вопросы терминологии.
Теперь было бы интересно услышать как изменилась стоимость владения и поддержки: расследование бага в микросервисной среде требует обычно в разы больше времени. Также сама философия разбиения на микросервисы предполагает создание множества отдельных БД, а значит кучу процессов синхронизации между ними, а значит кучу дополнительных тикетов в поддержку, которых в случае монолита бы не было.
В общем ждем статью "От монолита к микросервисам — месяц (или год) спустя"

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

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

Делал, но не так немного. Все копии равноправны, нагрузка на чтение распределяется по репликам базы данных. 90% SELECT — чистое чтение, а не SELECT… FOR UPDATE

Можно я присоединюсь к голосам выше?
История перехода от коробки к собственному продукту — да, она тут есть. И она вам помогла осуществить большую часть написанного. А микросервисы — разве что как аргумент моды.
Мы как-то делали монолит, который успешно выкатывался раз в день и ничего, работало

Это может быть не просто данью моды, а способом убедить начальство/заказчика вообще начать что-то делать. Манипуляция, наверное, такая.

Все верно, если команда одна, состоит из мидл+ профессионалов, а область не очень сложная, то монолит будет идеальным решением — и раскатывать можно достаточно часто.

Когда команд много, то сложно уследить за каждой. А в нашем случае было и вовсе невозможно. В такой ситуации микросервисы снижают риск написать некачественный код. Но даже если такое произойдет, то переписать 1 микросервис легче, чем распутывать цепочку связей в монолите.

Этот вопрос не был в полной мере освещен в статье, поскольку не относится к технике, больше к бизнесу.
Хорошо, когда банк один. Попробуйте промасштабировать свое решение хотя бы на десяток банков. А лучше на сотню или десятки тысяч.
Если мы правильно поняли ваш посыл, речь идет о коробке, которая обслуживает много банков. Безусловно, облачные технологии заставляют нас использовать другие подходы и другие архитектурные решения. Но рассматриваемый случай к ним не относится. В нашем случае коробочное приложение крутилось на серверах клиента и в общем случае обслуживало даже не один, а всего лишь часть банка. Это было одной из причин изменения архитектуры.

Хотелось бы получить хоть какие-то ответы от автора на вопросы выше. А то все выглядит, как рекламная статья.

Добрый день, обязательно постараемся на все ответить! У вас было много важных вопросов, некоторые из них мы решили уточнить с командой для более полного описания.
Так же стоит вопрос — а нужно ли было вам ускорять выпуск релизов до такой частоты? Одно дело когда это были бизнес-требования, а другое — когда это требования для мобильного приложения. Что там можно и нужно так часто обновлять?
Спасибо за фидбек всем, кто читает и комментирует. Как отметили выше, комментарии подсветили ряд важных вопросов, которые мы не затрагивали в материале. Над проектом работала большая команда, уточним некоторые вопросы, чтобы описать подробнее. Просим простить за задержку, обязательно постараемся всем ответить)

Первые два больших комментария с 6 и с 3(мой) пунктами, если можно ответьте

Забавно: есть огромное количество статей о том, что монолит разобрали на микросервисы (хотя чаще на микросервисный монолит), при этом скромно умалчивается о том, что пришлось заплатить за увеличившуюся сложность и стоимость коммуникаций сервисов.

одно дело заплатить трудом, поддержкой и.т.д. а другое кажется они переделали на непозволительные юзкейсы для фин проекта.
Смотрите мой второй пункт (пока они его не прокоментировали):
https://habr.com/ru/company/simbirsoft/blog/512310/#comment_21883146

Добрый день! Ответили выше на ваш комментарий, посмотрите, пожалуйста.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий