Комментарии 11
Такую же логику можно задать для каждого человека, и тогда получается плоский список:
Переспрашиваем один и тот же вопрос у n человек звучит довольно неэффективно, так что несколько странный пример. Как-то по всей этой саге нельзя передавать некоторый набор контейнеров, чтобы не тратить процессорные такты или подразумевается, что шаги должны быть независимы друг от друга по аналогии с облачными лямбдами?
А почему использовали такой подход, а не подход Cadence/Temporal? Сценарии при этом получаются гораздо более удобные и понятные и не нужно думать лишний раз о компенсациях (которые вообще не очень обязательны в сагах и сильно усложняют использование, особенно если в компенсации случилась ошибка).
1. Потому что Cadence/Temporal - это +1 технология, которую надо изучать, деплоить, настраивать.
2. Потому что любое сторонее решение — это всегда чужое видение фичей, чужие баги, которые не всегда легко пофиксить, а фиксы не всегда легко пропихнуть в апстрим.
3. Потому что нам надо было встроить саги в существующую систему.
Подобный выбор — это всегда баланс между «взять готовое и попасть в vendor lock» или «запилить свое и потенциально утонуть в поддержке». Кажется, простой вариант оркестратора саг не так уж и сложно сделать. Сложно было сделать так, чтобы саги было легко писать и поддерживать.
Насчет компенсаций — да, в каких-то сценариях они, вероятно, и правда не дают большой пользы. У нас не так, нам нужна транзакционность в распределенной системе.
Я нигде не предлагал поставить Cadence или Temporal, я спрашиваю только про использование подхода Cadence к реализации workflow, гораздо более удобный и универсальный, нежели показаные в статье саги.
Если уж делать свое решение - то почему бы не взять более удачные подходы и идеи?
Ну и "транзакционность в распределенной системе" никак не связана с наличием или отсутствием компенсаций. В любом случае саги не дают ACID (нет изоляции и атомарности), саги обеспечивают только eventual consistency, которую можно получить разными способами, отнюдь не только компенсациями к каждому шагу.
В статье забыли упомянуть, что плюс ко всему описанному любые (не важно, реализованные как в статье или через Temporal) саги добавляют в проект очень много дополнительной сложности. Что ещё хуже, нередко это accidental complexity, а не essential complexity:
Саги в рамках одного монолита/микросервиса обычно появляются как следствие DDD. И, вполне возможно, что DDD просто избыточен (особенно если речь о микросервисе), и если его не использовать то ясность бизнес-логики пострадает незначительно, но зато уйдут все саги и реализация станет на порядок проще.
Саги в рамках нескольких микросервисов одного проекта нередко являются признаком неудачного дизайна микросервисной архитектуры и/или чрезмерно жёстких требований бизнеса. В таких ситуациях нередко возможно согласовать с бизнесом небольшие ослабления требований к консистентности и/или передизайнить границы ответственности микросервисов чтобы появилась возможность все транзакции выполнять в рамках одного микросервиса и избавиться от всех или хотя бы большинства саг.
Саги в рамках не связанных проектов (классический пример саги: нужно купить авиабилеты в одной компании, забукать отель в другой и заказать такси в третьей) обычно являются основным кейсом, в которых без саг обойтись невозможно. К сожалению, именно в этих ситуациях нередко всё складывается ещё сложнее, потому что не все сторонние проекты предоставляют идемпотентное API. Иногда в таких ситуациях тоже получается увернуться от использования саг договорившись с бизнесом об ослаблении требований к консистентности.
Резюмируя, уметь реализовывать саги важно, но ещё важнее уметь их избегать.
Давайте возьмем бизнес который не шаверма, а нормальный такой бизнес. Который деньги делает.
Без межсервисного взаимодействия бизнес работать просто не будет. А так как обычно процессы начинаются в одном департаменте а заканчиваются в другом, то увы, тут либо саги, либо 2х фазные коммиты, либо костыли.
Или все объедините в одну базу, в монолит, и под одну транзакцию?
Понятно что крадовский апи на движок ведения блога саги не нужны.
И я не понял как ослабление консистентности позволяет избежать саг? Типа, дернем апишку, а там будь что будет? Или имеется в виду что просто не будем думать о компенсациях, но все равно будет где то трекать состояние процесса? Потому что если нет, это как-то очень плохо выглядит.
Или все объедините в одну базу, в монолит, и под одну транзакцию?
Это один из вариантов. В контексте бизнес-логики ключевое отличие микросервисов от монолита в количестве выполняющихся бинарников. Модульный монолит, реализованный внутри как набор модулей идентичных (по границам ответственности и изоляции) микросервисам, позволит сохранить приемлемую скорость разработки проекта. И при этом сохранится возможность объединять операции с БД разных микросервисов в одну транзакцию. В теории.
А на практике, полагаю, такой подход хоть и сработает для некоторых проектов, но вряд ли его получится масштабировать для действительно крупных проектов - скорее всего он просто упрётся в БД (или по производительности, или в необходимость использовать разные БД для разных задач и невозможность реализации транзакций между разными БД).
В общем, пробовать так делать можно, но реальные недостатки (и границы применимости) этого подхода мы узнаем только попробовав, не один раз и на разных типах проектов.
И я не понял как ослабление консистентности позволяет избежать саг? Типа, дернем апишку, а там будь что будет?
В целом - да. Проблема саг - именно в компенсациях. Без компенсаций саги превращаются в обычный поток событий и обработчиков этих событий, что тоже не самый простой в реализации подход, но вполне терпимый и хорошо изученный на практике (в отличие от вышеупомянутого модульного монолита).
Скорее всего в некоторых проектах этот подход окажется недостижимым идеалом, но в этом нет ничего плохого: если таким образом получится избавиться от 99% саг, и на весь проект останется буквально несколько штук саг и/или двух/трёх-фазных коммитов, то это будет непросто, но вполне реально корректно поддерживать.
Или имеется в виду что просто не будем думать о компенсациях, но все равно будет где то трекать состояние процесса?
Я бы такой подход отнёс в категорию "быстро-грязно", но да, в некоторых проектах он может сработать, особенно на начальном этапе разработки в стартапах: не пытаться реализовывать автоматические компенсации вообще, но предусмотреть возможность уведомления о любых проблемах при выполнении саги и ручного вмешательства в такие саги без ограничений (хоть вручную компенсировать хоть вручную доделать остаток саги хоть вручную доделать текущий подвисший шаг и продолжить автоматическое выполнение саги).
По большому счёту этот подход не так уж и принципиально отличается от описанного в статье - просто в статье предполагается, что разработчики смогут корректно реализовать и поддерживать часть логики компенсаций и переключаться на ручное управление только если корректно компенсировать автоматически не удалось и при этом удалось корректно такую ситуацию определить. Но лично я не верю ни в то, что разработчики в состоянии корректно реализовать и особенно поддерживать логику компенсаций, ни в то, что получится корректно определять все ситуации требующие ручного вмешательства, поэтому считаю разумным даже не пытаться лезть в эту кроличью нору в принципе.
Резюмируя: саги - это оружие последнего шанса, как ядерные бомбы. Их нельзя затаскивать в проект до тех пор, пока есть хоть какие-то другие варианты. И тем более их нельзя использовать для компенсации ошибок проектирования - лекарство окажется намного хуже болезни.
особенно на начальном этапе разработки в стартапах
---
Ну вот примерно так мы и пилили стартап, а он взял и не умер. Теперь не может выкопаться из количество проблем и тикетов от пользователей. Особенно саязаннвх с распилом монолита...
Я долго присматриваюсь с Сагам. Пока что думаю запилить их но без компенсаций. Но боюсь предлагать то в чем сам не уверен.
Слишком много у нас процессов по принципу "дернул и забыл". И даже это не самое плохое. Самое плохое это что не трэкается состояние процесса. По любой проблеме нужно лезть глубоко в логи и копаться.
Статью еще не читал, но может прояснит мне пару моментов и мне будет не так страшно предложить натянуть как-нибудь сагу на существующий код.
Статью почитайте, конечно. Но я бы рекомендовал присмотреться к Temporal - он избавит от необходимости самостоятельно реализовывать описанное в статье и позволит сразу заняться переносом бизнес-логики в саги. Ну и доклады посмотрите, конечно же - у нас на GolangConf в последние годы их по Temporal было несколько, плюс возможно и на хайлоаде тоже были.
Лучше тогда брать не саги (особенно в реализации из этой статьи), а тот же Temporal или подобные подходы. Какие-то я даже рассказывал в https://www.youtube.com/watch?v=0_ziFXXEW_M
Ну, кстати, для межсервисного взаимодействия часто достаточно не саг, а "пробуем дожать, если не получилось, просим разобраться оператора". В нормальной системе, где сервисы не падают каждый день на час, ситуация "не получилось дожать" крайне редкая и ручной разбор проблем не вызывает проблем и не требует затрат.
Да, есть отдельные бизнес-сценарии, где такой подход не проходит и там приходится придумывать что-то еще. Но таких сценариев на удивление мало.
Эпическое программирование: пишем понятные и поддерживаемые саги