Здравствуйте, gandjustas, Вы писали:
G>Так всетаки микросервисы проще монолитов или сложнее?
Сложнее. И требуют более высокой кваливикации разработчиков, чтобы начать делать хорошо.
На архитектурном уровне вместе с микросервисами приходит eventual consistency. В монолите можно сделать большую транзакцию, в микросервисах — в целом нет. Распределенные транзакции идее микросервисов противоречат и технически вряд ли возможны (у каждого сервиса может быть свой стек технологий). Эта неконсистентность сразу вызывает вопросы надежности (reliability). Очень часто нужно уметь надежно доставлять состояние между сервисами. Или надежно знать, что данные не доставлены. А в HTTP есть состояние неопределенности. Запрос отправили, ответ не получили. И вот что это значит? Сервер запрос вообще не получил? Или получил, обработал, но ответ отправить не сумел? Поэтому практически в каждом с сервисе с зависимостями возникает необходимость повторов (retry) и соответствующих внутренних состояний. Кроме того, в сервисах с зависимостями есть проблема устойчивости (robustness). Например, сервис A вызывает сервис Б. Сервис Б обычно отвечал за 10 миллисекунд, а стал — за 10 секунд. Вопрос — что будет с сервисом A? Я видел ситуацию, когда пул HTTP-соединений между A->Б был установлен в настройки по умолчанию (и это было четыре соединения). Поэтому все операции выстраивались в длинную очередь и латентность ответов от А взлетала до небес.
Выше — это архитектурные и технические вопросы. Есть еще операционные: мониторинг (и не "как попало", а чтобы было удобно и более-менее понятно, что происходит с конкретным сервисом), CI, развертывание. Каждая команда должна уметь делать QA, performance и security на неплохом уровне. При большом количестве команд тестировать "в среде/environment" становится сложно — нужно согласовывать тестовые данные, расписания работы сервисов (а вдруг мы задеплоили и что-то сломали?), нагрузку (параллельные perf test имеют много шансов упасть). Это решается эмуляторами зависимостей, но их же кто-то должен писать. А это — время и силы.
Да, еще нужно инфрастуктуру под это поднять. Кубернетес или что положено, инструменты и так далее.
На самом деле после некоторой практики все из вышеописанного совершенно не сложно. Но вот стартовать без наработок долго. Обучать команду всем аспектам — тоже.
G> Я везде вижу один аргумент в пользу микросервисов, что они проще и масштабировать их легче. А вы пишите что нет.
Масштабировать сервисы — в целом да, проще. Микросервисы стартуют быстрее, да и масштабироваться будут только те части, на которые приходится нагрузка. Но во многих случаях узким местом является база данных. А там сервисы особо масштабировать не приходится. Если использовать асинхронность, несколько инстансов сервиса запросто упрутся именно в базу. При масштабируемом хранилище (что нужно закладывать при разработке!) — да, все чуть лучше.
А "проще" — это из-за некорректного сравнения происходит. Монолит и "микросервисы" имеют несравнимый возраст и историю. Смотрите, что происходит. Есть начальная команда, которая разрабатывает продукт. Это монолит, со внутренней модульюностью и более-менее успешной архитектурой. В течение 5 лет половина команды уходит на новые проекты. Другую половину эффективные менеджеры заменяют на более дешевых и управляемых сговорчивых разработчиков. Это поколение немножко забивает на границы между модулями и вводит ненужную связность. В коде образуется лишний coupling, но зато тикеты закрываются легко и весело. Приложение постепенно превращается в макаронного монстра (spaghetti monster). За следующие 5 лет половина разработчиков успешно фрустрирует и уходит. Другую половину эффективные менеджеры увольняют из-за снизившейся производительности (tech debt мешает, да) и нанимает еще более дешевых разработчиков. Это будет третье поколение. Новые разработчики дешевые, но существующий код читать не умеют. Про рефакторинги и приведение монолита в порядок даже и говорить не приходится. Зато они умеют писать новый код. Внешние костыли гордо называются микросервисами. Система может разиваться еще какое-то время. Еще через 5 лет организация получает уже распределенного макаронного монстра. И здесь вариантов уже совсем мало. Либо вообще закрыть продукт (через 15 лет много шансов, что он будет и так не нужен), либо нанимать специалистов за много денег приводить все это в порядок.
Т.е. "проще" — это обычно в условиях, когда монолит уже запущен и там скорее "совсем никак" с теми ресурсами, которые имеются в наличии. Еще на "проще" влияет первое впечатление. Пока сервисов мало (меньше 10) нефункциональные требования (reliability & co) не особо влияют. "Один" сервис в серднем скорее работает, чем нет. А вот когда сервисов много, начинаются отказы (просто статистически, когда сервисов много, больше шансов, что в каждый момент хоть что-то не работает). Так как про устойчивость (robustness) на начальных этапах "забывают", вся система регулярно рушится с громким грохотом.
Как SkyDance здесь уже отметил, микросервисы на раннем этапе всего-лишь позволяют предотвратить излишнюю связность. Особенно на нижнем уровне вроде базы данных. Это можно делать и в монолите, но нужна определенная политическая воля.
G>При использовании правильных средств в монолитном приложении запросы проверяются при компиляции.
Дело не в ошибках. Дело в количестве и (очень часто) черезмерной связанности (coupling). Там запросто правки вида "здесь всего в 5 местах поменять" преврашаются в приключение "оказалось, оно используется в 25 местах!". А потом через две недели вы внезапно узнаете, что этим рефакторингом еще и сорвали сроки релиза. Потому что другая команда тоже делала рефакторинг где-то в другом месте. Но несколько из этих 25 мест попали в затронутый ими код. И теперь им нужно еще несколько дней на все исправить, проверить и смержиться. Почему раньше не узнали? Да потому, что до них только сейчас дошла очередь мержится. А мержить master в рабочую ветку и гонять CI на каждое изменение там — слишком накладно. И это вполне типичная ситуация.