Написан пост с описанием какой-то практики вашей работы с использованием формата архитектурного паттерна (в нашем курсе приведено 13 возможных разделов, использовано не менее 8 из них).
Довольно распространенный паттерн в микросервисных архитектурах
имя паттерна
database per service
ситуация/context
микросервисная архитектура, слабая связность между модулями
проблема
выбор подхода ко владению БД в микросервисной архитектуре
соображения/влияния/силы/forces
микросервисы должны быть слабосвязанными
некоторые бизнесс-транзакции запрашивают/joined данные которыми владеют разные домены/сервисы
некоторые бизнес-транзакции меняют данные нескольких доменов/сервисов
базы данных иногда должны быть реплицированы/шардированы
разные сервисы следуют разным паттернам доступа/хранения данных SQL/NoSQL/Graph/Document/etc.
решение
держать приватное хранилище данных исключительно во владении микросервиса и предоставлять API для доступа к данным(не давать прямого доступа к БД)
есть вариации:
приватные таблицы на каждый сервис - общая БД/кластер, но таблицы находятся в исключительном доступе/владении у каждого сервиса
накладные расходы меньше, но есть опасность, что какой-то шибко умный/“очень надо” разраб на это наплюет. Нужно будет вложиться в проверки чтобы этого не было
приватная БД/кластер на каждый сервис
последствия
плюсы
слабая связность
каждый сервис может использовать что угодно свое для хранения. То что подходит лучше
минусы
бизнесс-транзакции между разными доменами это боль
мерж данных из разных источников не такой простой как один SQL запрос
сложность/стоимость менеджмента/обслуживания разных БД
SAGA - для распределенных eventual-consistent транзакций
UPDATE:
имя паттерна
database per service
ситуация/context
есть сервис А и сервис Б
сервис А появился первым, у него был какой-то API и всякие фронтенды(но не бэкенды) им пользовались
важный момент - в сервисе А модель работы была append-only, т.е. данные только создавались, но никогда не менялись/удалялись(это было нашей большой ошибкой так сделать) и до поры до времени это не было проблемой
потом понадобился сервис Б, который делает какую-то аггреграцию данных из А и сверху наворачивает данных
и поскольку сервис А работал по append-only - то в сервисе Б чтобы сократить количество API вызовов между сервисами - делали локальный кэш из трансформированных данных из А
в сервис А добавляли данные, он слал эвенты в сервис Б, сервис Б брал эти обновления, наворачивал свое, трансмформировал, кэшировал и все было хорошо и eventual-consistent со средним отставанием в ~1-2 секунды
проблема
появился use-case когда данные в сервисе А нужно было менять, а посколько Б зависит от А то и в Б по цепочке их нужно менять
при этом время между append - update может пройти часы/дни, а могут миллисекунды(т.е. две “типа-транзакции” одновременно выполняться)
соображения/влияния/силы/forces
микросервисом А все еще пользуются другие фронтенды(но не бэкенды)
все еще eventual-consistency нас устраивает(отставание в районе 1-2 минут приемлимо)
в целом у меня полная свобода что делать но времени не очень много
решение
когда что-то меняется в А - слать эвент в Б, а Б делает полную рекалькуляцию без локального кэша
У вас это как-то похоже не на описание вашей работы в предложенном формате, а пересказ содержания учебника по архитектуре, “фрагмент сборника общих паттернов”, независимо от конкретного вашего проекта. Никаких сомнений, что паттерн “из учебника” известен, может быть описан в этом формате. А надо бы заземлить: как это выглядит в конкретно вашей ситуации. Какие там конкретно боли, какие конкретно решения (понятно, как-то обезличенно, но тут вроде и разговор не про людей).
У меня препод говорит “сага это конечные автоматы для бедных”) И дело не только в том, что у нас в микросервисном аду данные запаздывают. А ещё и в том, что правильные откаты транзакций это ж целое дело. И надо разбираться какая транзакция “поворотная”, а какая нет. И каком порядке их выстроить. А потом вдруг откатывать надо данные не в одном сервисе, а в нескольких по какой-нибудь хитрой цепочке.
Да, это вот примерно так и выглядит, если от уровня рассуждений “паттерна из учебника” (метаУ-модели) перейти к конкретной ситуации в предметной области, конкретным экземплярам микросервисов. Ибо паттерн, предъявленный без контекста – а вдруг нужен был вообще другой паттерн?!
если честно звучит как наброс. Конечно можно представить SAGA как частный случай конечного автомата. Ну так чего останавливаться, давай те скажем, что SAGA - частный случай алгоритмов.
Все так, это очень непросто и лучше в это вообще не залезать))
То, что указано в “проблема” - это проблема конкретного человека (не выбран подход), но не та проблема, которая решается этим паттерном.
В целом database per service - это энкапсуляция.
Одна из проблем, котороая решается этим паттерном - это бесконтрольный доступ одного сервиса к данным другого сервиса, нарушение бизнес-правил/инвариантов.
Эта проблема может решаться через логику в БД через хранимые процедуры, что в целом считается плохим паттерном по другим причинам.
Другая альтернатива - доступ через explicit API с возможностью контролировать все запросы и то, как они работают с БД.
Другая проблема - это изменения внутренней структуры БД и возможность экранировать внешние сервисы от этих изменений с помощью явного использования API, которое сервис предлагает.
То, что написано в секции UPDATE - имя паттерна не имеет отношения к описанному решению. Можно сказать, что переход к использованию этого паттерна стало причиной проблемы, по сравнению с тем, что было раньше (при прямой записи в БД).
дельное замечание, согласен, да. Этот паттерн был призван решить какую-то другую проблему, решил ее(скорее да, чем нет), а теперь породил или был одной из причин новой проблемы - проблема распределенных транзакций.