Во-первых, блокировка всей таблицы и совсем не на секунды, а на гораздо дольше (вплоть до минут, если в таблице миллиарды записей) Во-вторых, можно вылезти за размер сегмента отката или размера WAL В-третьих, там с репликацией могут быть проблемы (но тут лучше с DBA обсудить, там все сильно зависит от конкретной СУБД и настроек).
Непонятно, почему при обновлении может быть неконсистентное состояние? При обновлении структуры СУБД нормально иметь разные записи в разных "версиях схемы" и сервисы приложений должен уметь с этим работать. Обычно достаточно иметь поле schema-version в каждой записи.
Копировать БД - это очень дорогое развлечение, которое для действительно крупных СУБД просто невозможно.
Добавление колонки требует эксклюзивной блокировки. Так что если у тебя идет длинный отчет по этой таблице и куча мелких транзакций, то они все начнут ждать конца отчета. Так что можно на пустом месте получить простой в минуты и больше.
Хм, 2000 записей очень мало, скорее всего вообще все данные будут в памяти. Возможно пробежаться по курсору в процедуре будет быстрее всего. Или вообще на бэке посчитать. Вот если 200000 employers и около 50000 подразделений - то все интереснее )
Э, а что такое "грамотный разработчик"? Вот обновлять одним update t set c1=c2 на таблице больше 100k записей - неграмотно, но многие ли это знают? Даже alter table add column часто опасно вызывать - но это вообще мало кто знает.
Если люди в монолите делают продукт 3 года, то они не начнут делать МСА с деплоем раз в неделю без обучения, увольнений, изменений орг.структуры и так далее. И тут нет разницы, МСА или монолит, логика одна и та же.
Угу. При этом иметь dba с доступом ко всем схемам - это почти всегда плохая идея. Но обеспечение безопасности работы с СУБД - тем очень отдельной статьи, там очень много неприятностей (
Эээ, ты не можешь одним sql запросом безопасно обновить миллион записей, увы. Для этого нужна сложная логика обновления небольшими батчами, с отслеживанием процесса, возможностью повтора после падения сервиса, учетом нагрузки и так далее.
А уж как сложно на liquibase работать с миграций данных в json/jsonb полей... Увы, в современных подходах работы с СУБД миграция - это просто код на языке высокого уровня.
К сожалению, тема миграции для БД раскрыта очень поверхностно. Ни один из указанных инструментов не позволяет мигрировать данные (а это необходимо для обеспечения совместимости при выкладки без останова), нет описания безопасных миграций (а очень немногие из реальных операций на СУБД безопасны), нет связи с поведением в системе (а это также нужно для обновления без останова). В серьезных проектах использование liquibase крайне неудобно, flyway с миграциями на java может использоваться, если добавить довольно много собственного кода. Но, обычно, нужно делать собственное решение.
Если релизный цикл 3 года, то это проблема не в архитектурном стиле, а совсем в других вещах и править нужно именно их. Просто переходом на микросервисы проблемы не решить (да и вряд ли получится перейти этой же командой).
Я вот вспоминаю свои монолиты. Ну, где весь код был внутри СУБД, там было грустно, сборка релиза и раскатка занимала где-то сутки (с учетом поездки к клиенту с дискеткой, это была B2B коробочка). Релизы делали раз в неделю-две, причем можно было привозить к клиенту только новые версии отдельных модулей. Где-то код был уже на Java, там сборка с автотестами занимала час-два (и да, транк был всегда с прошедшими автотестами, а модульные тесты делались локально и до коммита), развертывание на 12 серверов на 3 датацентра занимало секунд 10.
Я не понимаю, какие МСА будут быстрее и, главное, зачем быстрее...
В тот же Spring еще лет 15 назад можно было поднять монолит с подключенными только частично модулями. Балансировка по конкретным сервисам - обычный APIGW или меш, тут нет проблем особых.
При этом в микросервисах нужно еще масштабировать и взаимодействия (которые примерно на 3-4 порядка дороже для МСА) и кэши (что часто очень недешево). Если монолит писался под горизонтальное масштабирование, то его легко масштабировать, проще, чем микросервисный продукт.
Один файл локализации на проект обычно удобнее для переводчиков (которые загружают весь файл в систему перевода, смотрят дифф и корректируют автоперевод). В нескольких проектах приходилось специально писать тулинг для объединения нескольких файлов с локализациями (два фронта, бэкы, конфигурация) в один файл для переводчиков.
Ну, да, в ecom нужно еще и товар на складе заблокировать и это лучше всего делать между авторизацией средств и подтверждением (так как в этот момент дешевле всего отменить платеж). Но почти во всех сценариях получается, что двухстадийка удобнее, нежели ключ идемпотентности, поэтому ключ и используется относительно редко.
Кэш ключей тоже требует персистанса (так как неизвестно, на какой экземпляр прилетит повтор запроса), так что ключ идемпотентности не дает никаких преимуществ в реализации. Но при этом двухстадийная транзакция сильно упрощает реализацию более сложных транзакций (например, реализацию оплаты одного товара с нескольких источников средств или проверку состояния получателя и прочих сценариев). Поэтому в реальной жизни, обычно, предпочитают двухстадийные транзакции, а не ключи идемпотентности. И именно поэтому двухстадийный подход является стандартом "де-факто" для финтеха.
А почему двустадийка продиктована бизнес-логикой? Все то же самое можно сделать и в одну операцию (и, редко, так и делают), но тогда не будет как раз идемпотентности в распределенной системе. А каждая из стадий вполне себе безопасная для повторений (авторизации можно повторять много раз, реально же никакие деньги не снимаются при этом, только блокируются на какое-то время, к тому же авторизацию можно отменить; подтверждение всегда безопасно повторяемо). Вообще, для безопасных транзакций есть много разных паттернов: - ключ идемпотентности - двухстадийные операции - возможность проверить статус платежа Все они решают проблемы, описанные в статье. Все имеют некоторую стоимость. Ключ идемпотентности - самое дорогое решение по железу, но самое простое в реализации.
Идемпотентность, увы, очень дорогое решение (слишком многое нужно хранить на стороне сервера), поэтому чаще стараются использовать другие решения или как-то оптимизировать использование ключей идемпотентности (там довольно много разных паттернов есть). И именно из-за высокой стоимости прямо "из коробки" фреймворки такое не реализуют, хотя во многих готовых продуктах подобные инструменты есть (та же Kafka)
FIX все-таки для очень специфических задач используется. Для финансовых транзакций все несколько сложнее, есть куча разных протоколов, есть ISO 8583, есть ISO 20022, есть OpenBanking, но для реальных приложений они все избыточно универсальные, требуется их приземлять на конкретные кейсы. Но вообще для платежей обычно вместо ключей идемпотентности (описанных в статье) используются схема из двух шагов (авторизация и подтверждения), которые не сложнее в реализации, но дают и другие возможности.
На самом деле для решения задачи именно идемпотентность не нужна (и избыточно), достаточно безопасной повторяемости. И много неидемпотентных запросов являются вполне себе безопасно повторяемыми, например, getNextSequenceId. Но, конечно, тема безопасного повтора транзакций гораздо шире описанного в статье.
Во-первых, блокировка всей таблицы и совсем не на секунды, а на гораздо дольше (вплоть до минут, если в таблице миллиарды записей)
Во-вторых, можно вылезти за размер сегмента отката или размера WAL
В-третьих, там с репликацией могут быть проблемы (но тут лучше с DBA обсудить, там все сильно зависит от конкретной СУБД и настроек).
Непонятно, почему при обновлении может быть неконсистентное состояние? При обновлении структуры СУБД нормально иметь разные записи в разных "версиях схемы" и сервисы приложений должен уметь с этим работать. Обычно достаточно иметь поле schema-version в каждой записи.
Копировать БД - это очень дорогое развлечение, которое для действительно крупных СУБД просто невозможно.
Добавление колонки требует эксклюзивной блокировки. Так что если у тебя идет длинный отчет по этой таблице и куча мелких транзакций, то они все начнут ждать конца отчета. Так что можно на пустом месте получить простой в минуты и больше.
Вообще, я про все это рассказывал на последнем SHL:
Enterprise deploy: почему это больно / Филипп Дельгядо (lekton io) - YouTube
В задаче обновления данных много всяких нюансов. И стандартные решения, увы, работают только на домашних проектах, не в приличном продакшене.
Хм, 2000 записей очень мало, скорее всего вообще все данные будут в памяти.
Возможно пробежаться по курсору в процедуре будет быстрее всего.
Или вообще на бэке посчитать.
Вот если 200000 employers и около 50000 подразделений - то все интереснее )
Э, а что такое "грамотный разработчик"? Вот обновлять одним update t set c1=c2 на таблице больше 100k записей - неграмотно, но многие ли это знают?
Даже alter table add column часто опасно вызывать - но это вообще мало кто знает.
А почему автотесты пишет другая команда? Это часть DoD для фичи и пишется той же командой.
Если люди в монолите делают продукт 3 года, то они не начнут делать МСА с деплоем раз в неделю без обучения, увольнений, изменений орг.структуры и так далее.
И тут нет разницы, МСА или монолит, логика одна и та же.
Угу. При этом иметь dba с доступом ко всем схемам - это почти всегда плохая идея.
Но обеспечение безопасности работы с СУБД - тем очень отдельной статьи, там очень много неприятностей (
Эээ, ты не можешь одним sql запросом безопасно обновить миллион записей, увы. Для этого нужна сложная логика обновления небольшими батчами, с отслеживанием процесса, возможностью повтора после падения сервиса, учетом нагрузки и так далее.
А уж как сложно на liquibase работать с миграций данных в json/jsonb полей... Увы, в современных подходах работы с СУБД миграция - это просто код на языке высокого уровня.
К сожалению, тема миграции для БД раскрыта очень поверхностно. Ни один из указанных инструментов не позволяет мигрировать данные (а это необходимо для обеспечения совместимости при выкладки без останова), нет описания безопасных миграций (а очень немногие из реальных операций на СУБД безопасны), нет связи с поведением в системе (а это также нужно для обновления без останова).
В серьезных проектах использование liquibase крайне неудобно, flyway с миграциями на java может использоваться, если добавить довольно много собственного кода. Но, обычно, нужно делать собственное решение.
Если релизный цикл 3 года, то это проблема не в архитектурном стиле, а совсем в других вещах и править нужно именно их. Просто переходом на микросервисы проблемы не решить (да и вряд ли получится перейти этой же командой).
Я вот вспоминаю свои монолиты.
Ну, где весь код был внутри СУБД, там было грустно, сборка релиза и раскатка занимала где-то сутки (с учетом поездки к клиенту с дискеткой, это была B2B коробочка). Релизы делали раз в неделю-две, причем можно было привозить к клиенту только новые версии отдельных модулей.
Где-то код был уже на Java, там сборка с автотестами занимала час-два (и да, транк был всегда с прошедшими автотестами, а модульные тесты делались локально и до коммита), развертывание на 12 серверов на 3 датацентра занимало секунд 10.
Я не понимаю, какие МСА будут быстрее и, главное, зачем быстрее...
В тот же Spring еще лет 15 назад можно было поднять монолит с подключенными только частично модулями.
Балансировка по конкретным сервисам - обычный APIGW или меш, тут нет проблем особых.
При этом в микросервисах нужно еще масштабировать и взаимодействия (которые примерно на 3-4 порядка дороже для МСА) и кэши (что часто очень недешево).
Если монолит писался под горизонтальное масштабирование, то его легко масштабировать, проще, чем микросервисный продукт.
Один файл локализации на проект обычно удобнее для переводчиков (которые загружают весь файл в систему перевода, смотрят дифф и корректируют автоперевод).
В нескольких проектах приходилось специально писать тулинг для объединения нескольких файлов с локализациями (два фронта, бэкы, конфигурация) в один файл для переводчиков.
Ну, да, в ecom нужно еще и товар на складе заблокировать и это лучше всего делать между авторизацией средств и подтверждением (так как в этот момент дешевле всего отменить платеж).
Но почти во всех сценариях получается, что двухстадийка удобнее, нежели ключ идемпотентности, поэтому ключ и используется относительно редко.
Кэш ключей тоже требует персистанса (так как неизвестно, на какой экземпляр прилетит повтор запроса), так что ключ идемпотентности не дает никаких преимуществ в реализации.
Но при этом двухстадийная транзакция сильно упрощает реализацию более сложных транзакций (например, реализацию оплаты одного товара с нескольких источников средств или проверку состояния получателя и прочих сценариев).
Поэтому в реальной жизни, обычно, предпочитают двухстадийные транзакции, а не ключи идемпотентности. И именно поэтому двухстадийный подход является стандартом "де-факто" для финтеха.
А почему двустадийка продиктована бизнес-логикой? Все то же самое можно сделать и в одну операцию (и, редко, так и делают), но тогда не будет как раз идемпотентности в распределенной системе.
А каждая из стадий вполне себе безопасная для повторений (авторизации можно повторять много раз, реально же никакие деньги не снимаются при этом, только блокируются на какое-то время, к тому же авторизацию можно отменить; подтверждение всегда безопасно повторяемо).
Вообще, для безопасных транзакций есть много разных паттернов:
- ключ идемпотентности
- двухстадийные операции
- возможность проверить статус платежа
Все они решают проблемы, описанные в статье. Все имеют некоторую стоимость. Ключ идемпотентности - самое дорогое решение по железу, но самое простое в реализации.
Идемпотентность, увы, очень дорогое решение (слишком многое нужно хранить на стороне сервера), поэтому чаще стараются использовать другие решения или как-то оптимизировать использование ключей идемпотентности (там довольно много разных паттернов есть).
И именно из-за высокой стоимости прямо "из коробки" фреймворки такое не реализуют, хотя во многих готовых продуктах подобные инструменты есть (та же Kafka)
FIX все-таки для очень специфических задач используется. Для финансовых транзакций все несколько сложнее, есть куча разных протоколов, есть ISO 8583, есть ISO 20022, есть OpenBanking, но для реальных приложений они все избыточно универсальные, требуется их приземлять на конкретные кейсы.
Но вообще для платежей обычно вместо ключей идемпотентности (описанных в статье) используются схема из двух шагов (авторизация и подтверждения), которые не сложнее в реализации, но дают и другие возможности.
На самом деле для решения задачи именно идемпотентность не нужна (и избыточно), достаточно безопасной повторяемости. И много неидемпотентных запросов являются вполне себе безопасно повторяемыми, например, getNextSequenceId.
Но, конечно, тема безопасного повтора транзакций гораздо шире описанного в статье.
Это скорее антиреклама )