Это понятно. Но тут же нет задачи "поставить блокировку на первую (первые) незаблокированную запись", а SKIP LOCKED предполагается именно для такой схемы, для реализации очередей с несколькими воркерами. Если не нужно ждать блокировки, то лучше уж NOWAIT?
Ну и очень, очень много вопросов к архитектуре. Не совсем понятно, почему "наличие нескольких ДЦ" приводит к "одновременному приходу одного и того же запроса". Вообще-то вполне можно решить эту проблему (и множеством разных способов). Валера так и не смог отличить "идемпотентность" от "безопасной логики". Идемпотентность - это характеристика запроса. А в данном случае правильно говорить не об идемпотентности, а о корректном процессе обработки изменений статуса платежа. Но, судя по всему, эта задача так и не была решена до конца (и даже не была корректно поставлена). И подобных вопросов очень много (
Написание платежных шлюзов - достаточно простая задача, но да, желательно, чтобы ее (хотя бы первый раз) реализовывал сеньор с хоть каким-то опытом в финтехе. Иначе будет так, как написано (и это далеко не худшее из того, что может быть, мне доводилось встречать и гораздо более неприятные истории при эквайринговых интеграциях)
А почему задачу по платежной интеграции поручили джуну без опыта? И при этом его решение даже миддл не посмотрел? И почему вообще нет стандартного шаблона для платежных интеграций? Обычно он появляется после третьей попытки...
Если быть совсем точным, то даже в 60х в США были политические движения, считающие себя неонацистами и к которым эпитет "фашистские" вполне применим (в его современном значении). Впрочем, даже тогда они воспринимались не слишком серьезно, но в фильм "Blues Brothers" они умудрились попасть (как комедийные персонажи, разумеется).
О, про зависимости при обмене через брокер весело. 1. У тебя для сценария с кафкой продюсер зависит от реализации консюмера, так как должен формировать ключ партиционирования в зависимости от требований консюмера. 2. Если ты хочешь что-то изменить на продюсере для одного консюмера, ты обязан убедиться, что все прочие консюмеры эту правку правильно отработают. Т.е. у тебя изменения одного консюмера зависит от всех прочих консюмеров, это очень жестко. Для http/grpc можно иметь несколько версий endpoint, а для брокеров это не пройдет ( 3. С брокером ты не можешь обновить "события в пути", т.е. тебе придется как-то реализовывать сложную логику, ээ, договора между всеми консюмерами и продюсером о смене версии события. Я знаю только один гарантированный сценарий для этого, но его никто не использует, так как слишком сложно )
Обычно обновить один сервис намного проще десятка сервисов
Не, без разницы. Всегда нужно думать про миграцию данных, фичафлаги, совместимость и так далее. И когда вокруг этого сделан тулинг - то обновление делается тривиально. А если нельзя договориться с соседними командами - то это проблема культуры и она не решается техническими средствами и будет проблемой вообще всегда. Впрочем, в твоем сценарии "прокси к данным" она будет сказываться вообще постоянно, так как любое изменение логики реконсиляции потребует (с большими шансами) изменение этого "прокси-сервера". А это происходит гораздо чаще, чем, ээ, переход с одной СУБД на другую. И, кстати, нет никакой проблемы выкатывать весь указанный функционал кусочками, с чего бы что-то не получилось?
О, я понял, где у тебя иллюзии. Нет, в современных БД в IO уже довольно сложно уткнутся, проблема обычно в ядрах и в оперативке. И тут гораздо дешевле сделать выборку прямо из БД и потом сделать массовый update, нежели прокинуть десятки миллионов записей через какой-нибудь микросервис. На сериализацию-десериализацию уходит очень, очень много ресурсов, поэтому любые массовые выборки стоит делать из своей БД, а не через микросервис. Попробуй протащить через сеть protobuf на 10 млн. записей (даже кусочками по 10k) и замерь, сколько у тебя уйдет ядер на это развлечение. Увы. но все современные протоколы обмена микросервисов не очень быстрые и с кучей дополнительных проблем (но почему gRPC почти всегда плохой выбор - отдельная тема). Ну и в конкретно этом случае у тебя еще и логика "сервиса доступа к базе" будет зависеть от всех сценариев реконсиляции, что увеличит зависимость.
И это не какой-то уникальный случай, это как раз нормальный кейс, который возникает всегда при работе со сколь-нибудь большими объемами данных и пристойной нагрузкой.
Смотря как делать. Если сделать общий Redis для всего проекта - так и получится, но так делать не нужно, у каждого микросервиса Redis должен быть свой собственный.
Почему должен? Если Redis используем для взаимодействия (pub-sub, общие блокировки и т.п.), то как раз нужен общий Redis. А если это локальный кэш, то зачем Redis?
контрактами и версионированием формата передаваемых сообщений
А ты пробовал это делать корректно? Там сразу вылезает взаимозависимость всех консюмеров по деплою и версионированию, это не лучше любой интеграции через view, только еще и миграцию хранимых данные сделать нельзя, что сильно все усложняет. То, что ты описываешь - обеспечивает потерю порядка и невозможность отката, так делать не надо ) На БД обеспечить совместимость гораздо проще, чем на очередях )
Хм, а какой один сервис ты написал бы что для первой задачи, что для второй? Да, в первой задаче нужно пропускать несколько миллионов записей за десятки минут на относительно дешевом железе. Во второй - общее число дочерних сервисов для отчетности - десятки с БД до терабайта. Да, при изменении схемы совместимым образом - нет проблем. При добавлении шардирования - вообще с реконсиляцией будет все нетривиально, проблемы работы с БД там будут вторичными (да, я знаю, пробовал). Замена одной СУБД на другую - всегда дорогая операция, для аналитических запросов - всегда требует их переписывать. Просто потому что все СУБД очень разные и с разными особенностями реализации. Кейсы, которые делаем на PG - нельзя сделать на CH и наоборот. А вот обновление пяти-десяти сервисов - это весьма тривиальная задача, кстати. Что там сложного-то? Точно проще, чем с помощью PG научить CH притворяться Вертикой )
Хм, например задача "реконсиляции" при обработке платежей. У тебя есть история эквайринговых транзакций банка (т.е. прошедших через банк транзакций магазинов, интернет-сайтов и так далее). И есть представление об этой истории у контрагентов (тех же магазинов, платежных систем и так далее). Раз в сутки нужно сверить твои представления о реальности с пришедшими от контрагентов файлами. Форматов файлов много, процессы сверки тоже заметно отличаются. По факту сверки нужно пометить транзакцию как "проверенную". Одно из решений - каждый тип сверки делается отдельным сервисом, но при этом все эти сервисы смотрят в одну общую базу "истории транзакций". Сами транзакции пишутся процессингом, а вот сервисы реконсиляции умеют только читать из конкретной вьюшки и изменять одно поле. Получается удобная интеграция через базу, с очень понятным и легко контролируемым контрактом (в том числе и через гранты). Прочие решения будут на порядок менее удобные.
Второй популярный кейс - аналитическая база. Куда пишут (через разные варианты ETL) куча разных сервисов и читают оттуда данные тоже куча разных сервисов для отдачи в bff или для долгосрочного хранения или для отчетности. Собственно, в МСА без этого вообще UI нормальный не сделать, не будешь же джойны и сложные фильтры делать ручками на bff?
А с распределенными базами типа YDB интеграция через базу вообще становится еще и масштабируемой по производительности. Ну и, если честно, kafka, redis или hazelcast - это тоже все про интеграцию через общее хранилище (общую базу). А используются все эти паттерны для обмена между сервисами очень широко.
"Изложите свой вариант, хотя бы тезисно?" Вариант чего? Проблемы взаимодействий в MSA? У меня минимум три доклада разных на эту тему - и это все равно про весьма поверхностный подход к теме.
Хм, а где там усиление связи? Какая разница, контракт описывает entrypoint или view или вообще strored procedure - это все описание контрактов. И версионирование для view сделать не сложнее, чем для http calls (и, в среднем, проще, чем для gRPC).
И чтение - это совсем не мелочь, подход с кэшированием данных в своей базе (то, что ты называешь подпиской) - очень сложный, очень трудоемкий (при обеспечении минимальных гарантий), очень сильно повышающий связность, почти никак не версионируемый и, в большинстве случаев, вообще антипаттерн.
Общие транзакции для разных сервисах, разумеется, не реализуемы. Но и подобных потребностей при "интеграции через БД" несколько меньше, так как не нужно инвалидировать кучу кэшей в других сервисах, достаточно поменять данные только в одном месте.
Автор статьи, подозреваю, вообще никогда не видел ни MSA, ни монолита. Так как при наличии хоть какого-то опыта в статье было бы хоть что-то содержательное )
MSA это, в первую очередь, про упрощение арх.контроля и, реже, про возможность работать с разными НФТ для разных частей продукта (скорее про безопасность и надежность, чем про масштабируемость). Других плюсов там особо и нет. Но какой-нибудь ArchUnit вполне решает задачу контроля.
Вообще, при современных распределенных БД не совсем понятно, в чем проблема в общей БД для множества сервисов. Контракт интеграции, особенно для чтения, легко реализуется через view и, при этом, будет много эффективнее, чем тот же gRPC.
Впрочем, в статье столько всякой чуши написано, что нет смысла даже критиковать. Как будто плохую книжку по сисдизайну пересказывают, еще и десятилетней давности...
По DDD лучше всего читать собственно Эванса (первую книжку). Ну и Хорикова (но там больше статьи). Но книжки по DDD не помогут нарезать домены, тут лучше что-нибудь базовое по теории систем (хоть вузовский учебник, хоть Акоффа).
Какие еще языки для корпоративной разработки вы пробовали? В каких у вас есть серьезные компетенции? Без разнообразного опыта сложно говорить про "хороший" или "плохой" язык. А вот те, у кого есть достаточно разнообразный опыт - обычно относятся к Python с большим сомнением, тем более при использовании динамической типизации.
Это понятно.
Но тут же нет задачи "поставить блокировку на первую (первые) незаблокированную запись", а SKIP LOCKED предполагается именно для такой схемы, для реализации очередей с несколькими воркерами.
Если не нужно ждать блокировки, то лучше уж NOWAIT?
Ну и очень, очень много вопросов к архитектуре.
Не совсем понятно, почему "наличие нескольких ДЦ" приводит к "одновременному приходу одного и того же запроса". Вообще-то вполне можно решить эту проблему (и множеством разных способов).
Валера так и не смог отличить "идемпотентность" от "безопасной логики". Идемпотентность - это характеристика запроса. А в данном случае правильно говорить не об идемпотентности, а о корректном процессе обработки изменений статуса платежа. Но, судя по всему, эта задача так и не была решена до конца (и даже не была корректно поставлена).
И подобных вопросов очень много (
Написание платежных шлюзов - достаточно простая задача, но да, желательно, чтобы ее (хотя бы первый раз) реализовывал сеньор с хоть каким-то опытом в финтехе. Иначе будет так, как написано (и это далеко не худшее из того, что может быть, мне доводилось встречать и гораздо более неприятные истории при эквайринговых интеграциях)
А зачем SKIP LOCKED? Тут же как раз нужна блокировка.
SKIP LOCKED сделан для очередей, а не для попыток установить лок.
А почему задачу по платежной интеграции поручили джуну без опыта? И при этом его решение даже миддл не посмотрел?
И почему вообще нет стандартного шаблона для платежных интеграций? Обычно он появляется после третьей попытки...
Если быть совсем точным, то даже в 60х в США были политические движения, считающие себя неонацистами и к которым эпитет "фашистские" вполне применим (в его современном значении). Впрочем, даже тогда они воспринимались не слишком серьезно, но в фильм "Blues Brothers" они умудрились попасть (как комедийные персонажи, разумеется).
Ага, автор не очень разобрался в понятии исключений и ошибок в Java, увы.
О, про зависимости при обмене через брокер весело.
1. У тебя для сценария с кафкой продюсер зависит от реализации консюмера, так как должен формировать ключ партиционирования в зависимости от требований консюмера.
2. Если ты хочешь что-то изменить на продюсере для одного консюмера, ты обязан убедиться, что все прочие консюмеры эту правку правильно отработают. Т.е. у тебя изменения одного консюмера зависит от всех прочих консюмеров, это очень жестко. Для http/grpc можно иметь несколько версий endpoint, а для брокеров это не пройдет (
3. С брокером ты не можешь обновить "события в пути", т.е. тебе придется как-то реализовывать сложную логику, ээ, договора между всеми консюмерами и продюсером о смене версии события. Я знаю только один гарантированный сценарий для этого, но его никто не использует, так как слишком сложно )
Обычно обновить один сервис намного проще десятка сервисовНе, без разницы. Всегда нужно думать про миграцию данных, фичафлаги, совместимость и так далее. И когда вокруг этого сделан тулинг - то обновление делается тривиально. А если нельзя договориться с соседними командами - то это проблема культуры и она не решается техническими средствами и будет проблемой вообще всегда. Впрочем, в твоем сценарии "прокси к данным" она будет сказываться вообще постоянно, так как любое изменение логики реконсиляции потребует (с большими шансами) изменение этого "прокси-сервера". А это происходит гораздо чаще, чем, ээ, переход с одной СУБД на другую.
И, кстати, нет никакой проблемы выкатывать весь указанный функционал кусочками, с чего бы что-то не получилось?
О, я понял, где у тебя иллюзии. Нет, в современных БД в IO уже довольно сложно уткнутся, проблема обычно в ядрах и в оперативке. И тут гораздо дешевле сделать выборку прямо из БД и потом сделать массовый update, нежели прокинуть десятки миллионов записей через какой-нибудь микросервис. На сериализацию-десериализацию уходит очень, очень много ресурсов, поэтому любые массовые выборки стоит делать из своей БД, а не через микросервис. Попробуй протащить через сеть protobuf на 10 млн. записей (даже кусочками по 10k) и замерь, сколько у тебя уйдет ядер на это развлечение. Увы. но все современные протоколы обмена микросервисов не очень быстрые и с кучей дополнительных проблем (но почему gRPC почти всегда плохой выбор - отдельная тема).
Ну и в конкретно этом случае у тебя еще и логика "сервиса доступа к базе" будет зависеть от всех сценариев реконсиляции, что увеличит зависимость.
И это не какой-то уникальный случай, это как раз нормальный кейс, который возникает всегда при работе со сколь-нибудь большими объемами данных и пристойной нагрузкой.
Смотря как делать. Если сделать общий Redis для всего проекта - так и получится, но так делать не нужно, у каждого микросервиса Redis должен быть свой собственный.Почему должен? Если Redis используем для взаимодействия (pub-sub, общие блокировки и т.п.), то как раз нужен общий Redis. А если это локальный кэш, то зачем Redis?
контрактами и версионированием формата передаваемых сообщенийА ты пробовал это делать корректно? Там сразу вылезает взаимозависимость всех консюмеров по деплою и версионированию, это не лучше любой интеграции через view, только еще и миграцию хранимых данные сделать нельзя, что сильно все усложняет.
То, что ты описываешь - обеспечивает потерю порядка и невозможность отката, так делать не надо )
На БД обеспечить совместимость гораздо проще, чем на очередях )
Хм, а какой один сервис ты написал бы что для первой задачи, что для второй? Да, в первой задаче нужно пропускать несколько миллионов записей за десятки минут на относительно дешевом железе. Во второй - общее число дочерних сервисов для отчетности - десятки с БД до терабайта.
Да, при изменении схемы совместимым образом - нет проблем. При добавлении шардирования - вообще с реконсиляцией будет все нетривиально, проблемы работы с БД там будут вторичными (да, я знаю, пробовал). Замена одной СУБД на другую - всегда дорогая операция, для аналитических запросов - всегда требует их переписывать. Просто потому что все СУБД очень разные и с разными особенностями реализации. Кейсы, которые делаем на PG - нельзя сделать на CH и наоборот.
А вот обновление пяти-десяти сервисов - это весьма тривиальная задача, кстати. Что там сложного-то? Точно проще, чем с помощью PG научить CH притворяться Вертикой )
Хм, например задача "реконсиляции" при обработке платежей. У тебя есть история эквайринговых транзакций банка (т.е. прошедших через банк транзакций магазинов, интернет-сайтов и так далее). И есть представление об этой истории у контрагентов (тех же магазинов, платежных систем и так далее). Раз в сутки нужно сверить твои представления о реальности с пришедшими от контрагентов файлами. Форматов файлов много, процессы сверки тоже заметно отличаются. По факту сверки нужно пометить транзакцию как "проверенную".
Одно из решений - каждый тип сверки делается отдельным сервисом, но при этом все эти сервисы смотрят в одну общую базу "истории транзакций". Сами транзакции пишутся процессингом, а вот сервисы реконсиляции умеют только читать из конкретной вьюшки и изменять одно поле.
Получается удобная интеграция через базу, с очень понятным и легко контролируемым контрактом (в том числе и через гранты). Прочие решения будут на порядок менее удобные.
Второй популярный кейс - аналитическая база. Куда пишут (через разные варианты ETL) куча разных сервисов и читают оттуда данные тоже куча разных сервисов для отдачи в bff или для долгосрочного хранения или для отчетности. Собственно, в МСА без этого вообще UI нормальный не сделать, не будешь же джойны и сложные фильтры делать ручками на bff?
А с распределенными базами типа YDB интеграция через базу вообще становится еще и масштабируемой по производительности.
Ну и, если честно, kafka, redis или hazelcast - это тоже все про интеграцию через общее хранилище (общую базу). А используются все эти паттерны для обмена между сервисами очень широко.
"Изложите свой вариант, хотя бы тезисно?"
Вариант чего? Проблемы взаимодействий в MSA? У меня минимум три доклада разных на эту тему - и это все равно про весьма поверхностный подход к теме.
Хм, а где там усиление связи? Какая разница, контракт описывает entrypoint или view или вообще strored procedure - это все описание контрактов. И версионирование для view сделать не сложнее, чем для http calls (и, в среднем, проще, чем для gRPC).
И чтение - это совсем не мелочь, подход с кэшированием данных в своей базе (то, что ты называешь подпиской) - очень сложный, очень трудоемкий (при обеспечении минимальных гарантий), очень сильно повышающий связность, почти никак не версионируемый и, в большинстве случаев, вообще антипаттерн.
Общие транзакции для разных сервисах, разумеется, не реализуемы. Но и подобных потребностей при "интеграции через БД" несколько меньше, так как не нужно инвалидировать кучу кэшей в других сервисах, достаточно поменять данные только в одном месте.
Автор статьи, подозреваю, вообще никогда не видел ни MSA, ни монолита. Так как при наличии хоть какого-то опыта в статье было бы хоть что-то содержательное )
MSA это, в первую очередь, про упрощение арх.контроля и, реже, про возможность работать с разными НФТ для разных частей продукта (скорее про безопасность и надежность, чем про масштабируемость). Других плюсов там особо и нет. Но какой-нибудь ArchUnit вполне решает задачу контроля.
Вообще, при современных распределенных БД не совсем понятно, в чем проблема в общей БД для множества сервисов. Контракт интеграции, особенно для чтения, легко реализуется через view и, при этом, будет много эффективнее, чем тот же gRPC.
Впрочем, в статье столько всякой чуши написано, что нет смысла даже критиковать. Как будто плохую книжку по сисдизайну пересказывают, еще и десятилетней давности...
По DDD лучше всего читать собственно Эванса (первую книжку). Ну и Хорикова (но там больше статьи).
Но книжки по DDD не помогут нарезать домены, тут лучше что-нибудь базовое по теории систем (хоть вузовский учебник, хоть Акоффа).
Какие еще языки для корпоративной разработки вы пробовали? В каких у вас есть серьезные компетенции?
Без разнообразного опыта сложно говорить про "хороший" или "плохой" язык. А вот те, у кого есть достаточно разнообразный опыт - обычно относятся к Python с большим сомнением, тем более при использовании динамической типизации.
А у автора есть реальный опыт проектирования и защиты сайзинга для сколь-нибудь сложных систем? А то тут что не пункт - то ошибка проектирования (