Комментарии 207
Отличная статья, но не могу себе не позволить шутку: «Не могу читать монолитные статьи, когда переход на микросервисные».
А так, довольно хорошо описаны случаи, когда надо и нет, и по этой теме можно провести ретроспективу: опять просто хайп, который лавиной затянул многие умы разработчиков, как обычно, в общем.
Лично я нашел имбалансный юзкейс для жс бэкенда: мега io и cpu задачи выкинуть куда-нибудь через Кафку или грпс на гошные инстансы, чтоб не словить случаем блок по загрузке на монолите.
опять просто хайп, который лавиной затянул многие умы разработчиков, как обычно, в общем.
Говоря более точно - карго-культ: ЕМНИП все началось с какой-то tech evangelistic статьи, где было написано, что Netflix так делает ))
В целом если бы сервис был написан изначально на Go, а не на Node.js, то и не пришлось бы выносить в отдельную очередь, поскольку каждый http-запрос в Go обрабатывается в отдельной горутине
Отличная статья! Наконец видно, что пишет разумный человек с опытом, а не обчитавшийся маркетинговых материалов товарищ с каким то монолитом страшилкой в голове и микросервисами спасением от всех бед.
Да вот это и было в двух словах к чему пришёл :)
Если серьезно, то я из мира java-энтерпрайза, тут если сразу не начали пилить мега-проект на 5 лет, а просто сделали MVP за полгода, это уже считай повезло. Сразу делают "солидно", с замашкой на успешный проект под рост на годы вперёд.
У нас тут обычно нет практики писать сначала на js, потому что переписывать на другом языке бизнес не готов, когда оно уже работает. Плюс команды не хотят копить техдолг, поэтому сразу делают более менее прилично. Получается правда обычно как всегда :)
И пожалуй среди джавистов мало тех, кто знает js, а ещё меньше тех, кто любит. Хотя мне в целом заходит.
Это ещё не говоря про то, что в энтерпрайзе обычно стандарты на использование языков и технологий, от которых сильно не рекомендуют отходить, плюс общие библиотеки, уже написанные на java.
М, вот сейчас понял.
В java завезли модульность почти 10 лет назад, она даёт хорошую инкапсуляцию. Но она довольно хардкорная и в обычных проектах она не особо используется, больше в каких-то инфраструктурных, где реально важно инкапсулировать часть классов модуля.
В kotlin тоже есть некоторое подобие - уровень доступа internal. Но тоже пока не встречал, где бы это юзали.
В java изначально всё получше с инкапсуляцией, чем в js, плюс js интерпретируемый, поэтому у них немного разная атмосфера в этом плане. Но общее направление на модульность последние 10 лет точно было. Может кто ещё дополнит.
Подключил как-то на относительно небольшим java-проекте модульность.
С одной стороны - это было больно. Особенно при работе со сторонними зависимостями - местами пришлось менять зависимости или вообще не добавлять модульность (например, protobuf не сумел подключить в модуль).
С другой стороны - обнаружил очень много неожиданных связей "вот этого точно локального и никому ненужного класса" и всего остального проекта. Реально было очень много неожиданных открытий. Но разбил, разнес, справился в общем. Главное - модули стали очень четко свою область использования ограничивать.
И упростилась работа над проектом в целом. Когда есть гарантия, что внутренний класс точно нигде больше не используется, то стало заметно проще. Да и сломать что-то стороннее стало гораздо сложнее. Тесты, конечно, от слома спасают (чем ближе к 100% - тем больше), но все равно стало заметно лучше в этом аспекте.
Так что модульность в java - очень крутая штука. Но к сожалению, редко используемая...
Сразу делают "солидно", с замашкой на успешный проект под рост на годы вперёд
Это потому, что в мире энтерпрайза никто не оплатит полугодовой MVP или R&D с непонятным выходом. Там правит бал планирование и KPI :)
Я сам в прошлом из энтерпрайзной интеграции, Oracle / Tibco / Websphere и прочие "платформенные" истории.
Спасибо за статью.
Любопытно, что не увидел явного упоминания двух страшных слов, вечно сопровождающих такие обсуждения (хоть они и маячат между строк): связность и запутанность)
Артефакты. Артефакты бывают разные, но в целом это те штуки, которые мы релизим.
Это точно устоявшийся термин? Почему-то мозг об него буксует.
Дааа, про связность и связанность это оно, но это какие-то магические слова. Мне они не помогают понять, а часто наоборот - как будто сказал "слабая связанность" - и всем всё понятно, выгода очевидна.
Поэтому решил их не вводить, чтобы не плодить сущности и не усложнять статью.
Хотя сами эти концепции вроде бы полезные, и их понимание помогает лучше проектировать.
Это точно устоявшийся термин?
Вряд ли, написал как понимаю, больше из головы. Тоже думаю, что здесь как-то нечётко вышло.
Артефакты. Артефакты бывают разные, но в целом это те штуки, которые мы релизим.
Это точно устоявшийся термин? Почему-то мозг об него буксует.
Такая же фигня. Когда я вижу слово "артефакт", то неизменно вспоминаются какие-нибудь ботинки лесных эльфов, дающие по +2 к скорости и удаче.
Это точно устоявшийся термин? Почему-то мозг об него буксует.
Да, термин уже достаточно давно существует в CI. Например в Gitlab:
https://docs.gitlab.com/ee/ci/jobs/job_artifacts.html
Кажется, вы его не понимаете.
В приведённом примере - это объект, полученный в результате работы job'ы. То есть "то, что осталось" - это буквальное значение слова "артефакт".
Автор же использует артефакт в смысле "единица деплоя" (подсмотрел в комментах).
Что одному единица деплоя, то другому -- результат сборки. И тут слово "артефакт" -- "искусственно сделанный", вполне уместно.
PS. То, что осталось - это реликвия.
Не, ну если мы тут в душноту играем, то деплой - это работа, артефакт - объект, не подходит.
Результат сборки, конечно, остался, но предполагается, что он и был, просто версия обновилась, так что нового артефакта не появилось. Снова мимо.
Реликвия - это артефакт, имеющий ценность (часто духовную), так что тоже мимо.
Нет, не то что осталось, а from Latin arte ‘by or using art’ + factum ‘something made’, извините.
Монолит - это когда всё приложение для бухгалтерии ТНК - один полуторагиговый жарник (без ресурсов, да - ресурсы отдельно). Запуск на вебсфере около часа. Да, внутри все разложено на модули, но это монолитная дура, запускающаяся последовательно. Если оно наворачивается - а сделать ООМ элементарно легко загрузкой любой разновидности зип-бомбы, или просто файла с кинцом на полтерабайта... Там под капотом решение третьей стороны, крупного американского вендора, которое класть файлы в свое пропиетарное хранилище стримом не умеет, только подняв файл в память полностью. Баги были заведены, но отклонены с каментом "не баг, а фича". Плюс тысяча конвертеров документов, анализаторов, преобразовалок... Навернулась нода - жди час перезапуска. Нод 50, но пользователь упрям, и продолжает грузить этот злополучный файл - половину кластера ложит легко. Сборка - два часа в мемдиске, на хардах полдня, локально не запустишь - дай от терабайта оперативки. Вот это монолит.
Микросервисы - это быстрый рестарт, stateless, и возможность сделать больше инстансов того приложения, где вероятны отказы - заливщики файлов, конвертеры, распаковщики, ... тысячи их, а стабильным аппетиты урезать. Плюс быстрый процесс сборки и раскатки, возможность моментально раскатать фичу фокус-группе, и так же быстро откатить, если что-то пошло не так. Всё остальное - от лукавого.
Еще есть наносервисы - приложение с одной единственной функцией и девизом "пох на падения" :) чаще всего это приложения, конвертирующие доки либо работающие с архивами. Пошла утеча памяти или распаковка сожрала всю оперативку? Контейнер убивается, тут же запускается новый. Заддосить почти нереально. Минусом будет тот факт, что когда наносервисов станет много - начнется ад коммуникации, запомнить какой топик в кафке чей и кто использует - не очень реально. Хорошо, если есть культура идеального документирования, но почти всегда ее нет, увы.
И самое главное. Инструмент надо выбирать по задаче, а не забивать кувалдой винтики в очках. Где-то вполне заходит монолит, где-то разные типы микросервисов, а где-то без наносервисов никак...
пользователь упрям, и продолжает грузить этот злополучный файл - половину кластера ложит легко
Это про говнокод, а не про монолит. Решается оборачиванием решения под капотом собственным кодом, который проверяет размер файла.
stateless
Как микросервисность делает ваше приложение стейтлес? Или вы имеете в виду, что некоторые микросервисы будут стейтлес?
и так же быстро откатить
Попробуйте откатить баг в микросервисе А появившийся три версии назад, с которой не совместимы последние 5 версий сервиса Б, с которыми несовместимы последние 10 версий сервиса В. Депенденси хел цветёт и пахнет в микросервисах.
Попробуйте откатить баг в микросервисе А появившийся три версии назад, с которой не совместимы последние 5 версий сервиса Б
А как это связано, если баг не задействует контракт между сервисами А и Б?
Это про говнокод, а не про монолит. Решается оборачиванием решения под капотом собственным кодом, который проверяет размер файла.
+ перехват исключений, на тот случай если что-то не предусмотрели. Поймали непонятное исключение в котроллере, записали в лог инфу о нем, отдали 500, продолжаем работать.
ИМХО, микросервисы это такая шляпа, которую надо по возможности избегать, юзать их надо только тогда, когда без них никак не обойтись (процентов в 95% всех проектов, которые у нас делают на микросервисах можно и нужно было делать монолитом)
Все верно. Депенденси хелл, повышенные требования к архитектору, к девопсам, повышенная сложность интеграционного тестирования, накладные расходы в связи с кап-теоремой, больше ресурсов на холодную систему. Это все плата за возможность независимо скалировать отдельные части системы и повышенную отказоустойчивость. Платить, или не платить - надо считать. Хорошо, если есть тот, кто считать подобное умеет. Для бизнеса хорошо.
Микросервисы - это быстрый рестарт, stateless, и возможность сделать больше инстансов того приложения, где вероятны отказы
Ага. Щас.
С чего такое мнение? Через задницу написанный код хоть замикросервисируйся - стартанёт когда стартанёт и то если повезёт и не будет взаимной зависимости кольцевой.
Не помогут микросервисы. Не помогут. Если хватит квалификации написать их, то и на монолите у этого же человека(команды) не будет проблем.
Там еще вишенка на торте, девопсы под тонну микросервисов, у которых иногда "волосы шевелятся в самых неприличных местах"
Ну вот если квалификации недостаточно, то микросервисы здесь могут помочь. Так, не очень опытный сотрудник сможет "развалить" только один сервис. Еще кстати в микросервисах сложнее привносить неявные зависимости между модулями, в монолите всегда есть возможность срезать углы, нареференсать каких-нить внутренних классов из другого модуля и вот это все.
Давайте я вам подскажу куда засунуть такое приложение
Его надо сжечь и написать новое
Кода ваших программистов десятки мегабайт, остальное это мусор: фреймворки, библиотеки и даже то что вы и сами не знаете... 1.5 гига jar не считая ресурсов это страшное говно, которое вы пытаетесь спасти.
Да, при переписывании можете разделить приложение. Но эту накопленную десятилетиями энтропию нужно уничтожать.
На самом деле, все споры про монолиты и микросервисы не стоят выеденного яйца, поскольку разговор должен быть не о выборе идеологии (тупоконечники vs остроконечники), а о проектировании архитектуры, подходящей для оптимального решения задачи.
Монолитная организация исполняемого кода, модули, микросервисы, взаимодействующие процессы, паттерны и т.п. - это инструменты, которые необходимо применять с умом и на благо. И только то :)
Ноги у популярности микросервисов, разумеется, растут из веб-программирования, как и многие другие не совсем адекватные вещи. За последние годы я не раз сталкивался с последствиями такого подхода, разгребая чужие legacy-решения. В одном случае автор для решения достаточно простой задачи нагородил 6 микросервисов с отдельными БД (да-да, есть ещё секта противников "монолитных" баз). В другом программа просто не работала в контуре заказчика, изолированном от интернета, потому что "ну всегда же можно указать ссылку на фреймворк".
Так и живём.
Кажется, у тех, кто только начинает заниматься архитектурой, как раз не хватает в арсенале инструментов и опыта с ними, поэтому часто делают скорее как где-то увидели, или применяют те решения, которые на слуху. Времени и опыта для взвешенного решения не хватает, поэтому в ход идет выбор по наитию.
Сам делал так же, пока не разобрался в теме. Помню как один раз вкорячил 4 сервиса там, где прекрасно работал бы и 1, потом пришлось переделывать.
Поколение новичков, выбирающих по наитию, никогда не иссякнет, но надеюсь, что хотя бы пройдет этот консенсус в индустрии, что делать микросервисы - это стильно-модно-молодёжно, и вообще уйдет эта ложная дихотомия "монолиты против микросервисов". Может тогда будет меньше ориентира на хайп. Хотя кого я обманываю :)
6 микросервисов с отдельными БД (да-да, есть ещё секта противников "монолитных" баз)
Но микросервис же обычно подразумевает использование своей БД, куда только этот микросервис имеет доступ. Иначе зачем тогда этот микросервис нужен?
Иначе зачем тогда этот микросервис нужен?
Нужен он для выполнения некоторой относительно простой функции, как обычно и заявляется в концепции микросервисов :)
Микросервис не требует наличия собственной БД, он может вообще не обращаться к базе или работать с отдельной схемой централизованной БД. Или даже без отдельной схемы.
Разделение данных по владельцам с их передачей через API - совершенно отдельная идея, родившаяся, IMHO, в головах людей, которые не понимают, как готовить Оракл озабоченных в большей степени производительностью сервисов на выдачу данных. Распределение информации по кэшам в виде микросервисных БД именно эту проблему решает.
Проблема в том, что, во-первых, хорошая реализация такого подхода требует грамотной распределённой архитектуры данных (что редкость) и, во-вторых, не очень хороша, когда требуется централизованный анализ или источников изменения одной и той же информации несколько. В централизованных БД многие вопросы решаются проще и эффективнее.
Конечно микросервис может не использовать никакую БД, я подрузамевал что если она нужна.
Не согласен, что микросервис выполняет относительно простую функцию, он может заниматься и сложными вещами (а кто ими ещё будет заниматься в микросервисной архитектуре?).
В целом тогда нужно проводить разделение между сервисами и микросервисами в составе сервиса. Сервис должен владеть своими данными. Микросервисы могут соответственно могут шарить общие данные. Но другие (микро)сервисы могут иметь доступ к данным этого сервиса только через его API, без прямого доступа к данным.
Сервис должен владеть своими данными
Сервис - да. Вообще, очень полезно, когда разработчик понимает, для чего именно используется в системе тот или иной подход, какие плюсы и минусы он даёт на этапе разработки и эксплуатации. А архитектор прямо таки обязан это понимать.
API, кстати, тоже не обязан сводиться к HTTP/REST, в принципе, это может быть что угодно, хоть XML, доставляемый на собаках :)
Сервис должен владеть своими данными. Микросервисы могут соответственно могут шарить общие данные.
Абсолютно прекрасное определение, но кто ж его продвинет в массы.
Иначе зачем тогда этот микросервис нужен?
Вроде как, изначально, "по определению", микросервисы, как альтернатива монолиту, нужны для перераспределения вычислительных мощностей верх-вниз по стеку используемых технологий, чтоб, если один слой задыхается от недостатка ресурсов, а другой недозагружен, то у недозагруженного убавить воркеров (и через это — ядер/потоков/памяти ), а перезагруженному — добавить. Ну или в более расширенном случае не слой, а "канал".
С БД там в общем случае сложная засада — тоже оформлена как отдельный "слой", работа тоже через балансировщик, запись и чтение разделены настолько, что нет гарантии, что то, что записал, тут же сможешь прочитать (вместо предыдущей версии данных), "транзакции на уровне бизнес-логики" устаивать трудно. Логику приложения необходимо строить исходя из этого обстоятельства, что может взрывать мозг.
То есть ему пришлось разворачивать бекап 6 баз данных вместо одной? И потом кому то мониторить все это?
Да, я большой противник монолитных баз. Если вам нужна монолитная база - вам не нужны микросервисы. И да, очень часто сегодня их используют там, где они не нужны. Либо их намного больше, чем реально нужно. Но если они действительно нужны, они должны быть полностью независимы, включая источники данных. Никак иначе. Одна база на 2 микросервиса - красный флаг пересмотреть архитектуру. Если вам кажется, что 2 сервиса обязаны иметь одну базу - смело объединяйте их в один. Если вы твердо решили разделить сервис на 2 и более - сразу решайте как разделить базу. Причем в первую очередь. Если выходит плохо - см. пункт 1.
У вас прямо какое-то религиозное отношение к вопросу о базах микросервисов.
Да, возможно. Как к принципам солид, или драй. В целом можно нарушить, но если нарушение обнаружено - нужно семдесят семь раз перепроверить, не случилось ли фигни.
Нормальное отношение к БДшкам микросервисов. Если вдруг вам надо как то изменить схему бд которая пошарена между несколькими сервисами, то вам придётся следить чтобы ничего не сломалось во всех связанных сервисах. Правда в микросервисных БДшках часто страдает согласованность данных (нет общих транзакций), но это уже зависит от того как спроектирована система
Да ладно вам... Один сервис пишет в базу какие то исходные данные, другой их читает и процессит, а третий оформляет результаты и отправляет юзерам. Никаких трех баз здесь не выйдет, а вот три разных сервиса - легко
И все трое ложатся под нагрузкой, если узким местом стала запись. А зачем их вообще три? Вариантов спроектировать это вагон, нужно понимать функциональные и нефункциональные требования. Ну вот как пример:
Сервис раз принимает откуда-то данные и записывает их в базу исходников, серверлесс обработчик по событию подбирает данные, процессит их и записывает в базу с результатами процессинга, следующий серверлесс обработчик реагирует на запись результатов и отправляет телегу в брокер, где ее подбирает сервис нотификаций, у которого своя база для рассылки и истории. Два сервиса, три базы и две условные лямбды. Сервис нотификаций может также обрабатывать сообщения из разных других источников, база с результатами может использоваться для отдельного сервиса отдавать данные для статистики и графиков, например для веб-морды, все они друг от друга изолированы, их можно отдельно масштабировать (включая масштабирование базы), что собственно и есть основной задачей микросервисов.
И все трое ложатся под нагрузкой, если узким местом стала запись.
Сами по себе микросервисы не решают (и никогда на решали) вопросов производительности системы. "Высокая производительность" микросервисов основана на децентрализации и, внимание, выделении под них дополнительных вычислительных ресурсов :)
Что касается узкого места по записи, то у "больших" реляционных БД вроде Постгреса и Оракла эта проблема решается системно и, в общем, пр правильной архитектуре БД тормозом не служит. А вот синхронизация представлений одних и тех же данных в БД разных микросервисов может быть тормозом ой каким :)
Я не говорю, что микросервисы - это плохо, никаким боком. Просто не нужно делать на них ВСЁ. Например, для middleware, работающего с сотнями тысяч автономных устройств (сбор статусов и передача команд) такая архитектура просто не подходит, так как сервис там, по сути, один, а производительность должна быть адовой.
Я и не утверждал, что микросервисы должны решать вопрос производительности. Я прямо написал, что они решают вопросы раздельной масштабируемости. И устойчивости. Т.е. части и масштабируются раздельно, и "ложатся" раздельно, не влияя на другие части. И что микросервисы нужны далеко не всем и не всегда я тоже написал вроде ) Еще раньше.
Синхронизация и другие проблемы микросервисов мне тоже известны, кап теорема и вот это вот все. Микросервисы решают ряд проблем, за определенную цену, нужно понимать что именно решаем и чем именно заплатим. И боже упаси делать на них все. Самый модный тренд сегодня - разбивать монолит на микросервисы, и я навидался уже таких решений, что волосы на голове дыбом. Мне даже довелось проводить "обратную модернизацию", сливая кучу сервисов в один. Это, кстати, когда монолит поделили на сервисы, а базу оставили общую.
Тут я полностью с вами согласен. Каждое решение имеет цену, и нужно понимать область его применимости.
Это, кстати, когда монолит поделили на сервисы, а базу оставили общую.
У меня такое впечатление, что с широким распространением LAMP-стека народ разучился проектировать БД с учётом возможностей датабазных движков по управлению доступом к данным. Да и раньше это не всегда давалось легко :)))
Дело не в проектировании базы, а в проектировании системы в целом. База - это хранилище каких-то данных. Данные представляют собой сущности доменной области. Одна база имеет смысл, когда сущности в ней связаны. Вот юзер, у юзера есть какие-то ассеты, между ними связь один ко многим, форейн кей, констрейны и тд и тп. В базе присутствует какая-то нормализация, какая-то связная структура. Все это неким образом мапится на объектную модель в коде, через орм, или еще как. Объектная модель тоже получается связанная. В итоге разделение на сервисы при одной базе выходит по большей части фиктивное. В терминах ддд каждый сервис должен быть ограничен своим баундед контекстом. Можно, конечно, иметь 2 независимых и никак не связанных набора таблиц в одной базе, но тогда смысл одной базы теряется полностью. Либо проектировать базу как положено и потерять смысл раздельных сервисов, потому что сервисы оказываются хард каплед через один контекст, у них будут общие классы, общие структуры данных, вероятно какие-то общие сборки, потому что дата лэйер один на всех. Либо проектировать две логические базы в одной физической, что вообще выглядит как полная жесть.
Я могу себе представить необходимость разделить чтение и запись в базу в разные сервисы, чтобы оптимизировать нагрузку на чтение и на запись отдельно. Но тогда типовым решением является сделать 2 одинаковых по структуре базы, где один сервис пишет в базу 1, которая реплицируется в базу 2, из которой читает второй сервис. И можно тогда их по-разному оптимизировать в плане индексов, констрейнов и всего остального. Ценой некоторого лага в актуализации данных для чтения, но обычно эта цена приемлема.
Делая же несколько сервисов на одной базе, помимо проблем с организацией кода, жесткой связи через модель данных (когда для нужд сервиса 1 мы меняем структуру данных и вынуждены вносить правки и в сервис 2, потому что он использует ту же модель), мы рискуем не получить никакой выгоды. Положим узким местом будет запись данных в какие-то таблицы в сервисе 1, это с высокой вероятностью может отразиться на производительности сервиса 2, потому что он также будет простаивать из-за блокировок, все транзакции происходят в одной базе и бог знает какие связанные таблицы там участвуют.
Суть и смысл микросервисов - создать слабо связанную систему, это стратегическая цель такой архитектуры. И этого вообще и близко не происходит, когда используется одна база на несколько сервисов. Поэтому я и говорю: если вас устраивает одна база на 2 и более сервиса, скорее всего вам не надо 2 и более сервиса, вам нужен монолит. В 2 и более раз меньше проблем с деплойментом, проще архитектура, проще написание интеграционных тестов, проще локальная разработка, проще версионирование, все проще. При потенциально таких же возможностях масштабирования, хоть горизонтального, хоть вертикального.
выделении под них дополнительных вычислительных ресурсов
Следует заметить, что эта проблема имеет в совей основе мнгоядерность и параллелизацию.
синхронизация представлений одних и тех же данных в БД разных микросервисов
Вот и нужно продумывать архитектуру приложения так, чтобы по максимуму избегать нужды в такой синхронизации.
Следует заметить, что эта проблема имеет в совей основе мнгоядерность и параллелизацию.
Разумеется, и на выходе мы имеем параллелизацию и многоядерность БД микросервисов против параллелизации и многоядерности "монолитных" БД на современных движках, которые умеют это хорошо и давно, особенно на OLAP-задачах. Т.е. выигрыш именно в плоскости производительности эфемерный.
Вот и нужно продумывать архитектуру приложения так, чтобы по максимуму избегать нужды в такой синхронизации.
Эмм... Вы всё равно не избежите синхронизации данных, если один сервис занимается у вас, к примеру, аутентикацией пользователей, второй - управлением пользовательскиими эккаунтами, а третий - подсчётом статистики активности пользователей. Распил 4 нормальной формы по микросервисным квартиркам - не всегда тривиальная задача. Вся разница между микросервисами с собственными БД и микросервисами с централизованной базой, по сути, сводится к замене "контрактов" в виде прав доступа и программных механизмов (функций и представлений) центральной БД контрактами на основе REST API.
Ваш пример это классика как надо правильно разбивать сервисы.
Аутентификация с логинами и паролями это отдельный сервис. Сервера закрыты на отдельный замок, доступа к проду нет ни у кого. Да, прямо вообще ни у кого.
Управление аккаунтами это обычный сервис по работе с персональными данными. Все, кроме пароля, хранит у себя. Доступы зарезаны максимально, но есть.
А вот статистика пишется по анонимизированным идентификаторам и спокойно обрабатывается. Доступы есть, особо не паримся.
Три разные базы и три разных сервиса это лучшее решение этой проблемы.
А теперь расскажите мне, как в этой схеме без синхронизации БД происходит добавление пользователя :)
Легко.
Вызов бекенда ПерсДанных: Создай юзера с такими-то данными. Ответ бекенда: Готово id нового юзера 42.
Вывоз бекенда авторизации: Создай юзера с id=42 логином таким-то паролем таким-то. Ответ бекенда: Готово.
Ну и какой-нибудь клинер который будет неторопясь в свободное время чистить недосозданных юзеров. Пятисотят все иногда.
Если хочется реалтайма, то бекенду авторизации надо ходить в бекенд персданных и говорить что логин-пароль установлены и юзер полностью досоздан.
При этом из браузера юзера может уйти один запрос. Тогда его должен принять сервис относящийся к авторизации и удалить пароль. Остатки без пароля идут в сервис персданных, а пароль в бекенд авторизации.
Реализаций может быть много разных. Важно что пароль никогда не попадает ни на один хост или сервис не относящийся к скоупу сервиса авторизации.
Ну, то есть, вы предлагаете заменить одну операцию в центральной БД довольно сложной схемой взаимодействия бэков по сети ради незыблимости концепции?
Если что, в том же Оракле с начала нулевых существует механизм Fine Grained Access Control, решающий проблему доступа процессов к данным с ограничением по полям. Каждый экканут БД, соответствующий сервису, получат свой набор полей в общей хорошо оптимизированной таблице users из нашего примера. Ну а скоупы... штука виртуальная. Если у вас есть административный доступ к системе, вам всё равно, выгребать одну центральную базу или несколько микросервисных, задача усложняется совсем немного.
На самом деле, меня сильно расстраивает, когда разработчики относятся к реляционным СУБД как к экселю, просто хранящему таблички. Обычно это не от большого знания функциональных возможностей датабазных движков.
Ну, то есть, вы предлагаете заменить одну операцию в центральной БД довольно сложной схемой взаимодействия бэков по сети ради незыблимости концепции?
Ради безопасности и разделения доступов.
Если у вас есть административный доступ к системе, вам всё равно, выгребать одну центральную базу или несколько микросервисных, задача усложняется совсем немного.
Это важно и плохо. И это надо исправлять для любой более-менее развитой системы.
Это исправимо. Система при этом усложняется, да.
На самом деле, меня сильно расстраивает, когда разработчики относятся к реляционным СУБД как к экселю, просто хранящему таблички. Обычно это не от большого знания функциональных возможностей датабазных движков.
Оракл, как и любое другое хорошее энетерпрайз левел решение, умеет всякое. Когда оно вам подходит и у вас на него хватает денег, то это отлично. А вот если нужно что-то неподходящее или денег не хватает у вас проблемы. А еще регуляторы бывают. И даже санкции, как мы сейчас знаем.
В общем завязывание на вендора имеет свои особенности. Надо их понимать и верно оценивать плюсы и минусы такого завязывания. Я пришел к мнению что сейчас любую критичную систему надо строить или на решении вендора из вашей основной юрисдикции или делать две взаимозаменяемые системы на двух вендорах и разных юрисдицкий. Один из Америки, второй из Китая ок.
Яркий пример сети. Половину большого железа берем от Циски, половину от Хуавея. Инженеров учим работать и с тем и с другим. И будет хорошо.
В общем завязывание на вендора имеет свои особенности. Надо их понимать и верно оценивать плюсы и минусы такого завязывания.
Разумеется. Но я писал несколько о другом. Разделение доступа может обеспечиваться различными механизмами, микросервисы с изолированными БД лишь один из них, оптимальный не во всех случаях.
Механики, аналогичные проприетарным column-level security фичам оракла есть и во вполне бесплатном Постгресе, и даже в простигосподи mySQL :) Просто ими мало кто пользуется, предпочитая разделять данные на уровне отдельных баз.
Тем более, что мода на микросервисы с изолированными БД зародилась вовсе не в период санкций и вообще не в России.
Да как и мода на примерно все современные языки программирования из актуального топ-50 и вообще мода на любой кундштюкен в мире айти который сходу может прийти в голову )
А можно вас спросить о вашем основном стеке технологий? Просто любопытно. Возможно он тоже служит своего рода призмой восприятия.
Просто в современном мире энтерпрайза и облаков заниматься разделением доступа к разным колонкам таблицы будет заниматься примерно никто из тех, кого я знаю. Тут про шардинг многие не слышали и живут не тужат. В мире засилья орм, где даже хранимки с вьюхами сравнительная редкость, на такие вещи может решиться только матерый ДБА, да только кто даст добро? Я вот, как архитектор, не дам ) Стоимость и скорость разработки и поддержания кода это первый пункт в смете, а я сейчас даже сходу не соображу на кого бы подобную задачу можно было повесить и как потом организовать хранение сих скрижалей, чтобы оно еще и в пайплайны деплоя органично встроилось.
А можно вас спросить о вашем основном стеке технологий? Просто
любопытно. Возможно он тоже служит своего рода призмой восприятия.
Основной стек во времена работы в "тяжёлом энтерпрайзе" - Oracle (как RDBMS и Data Integrator, так и прикладные продукты - CBRM, OFA, EBS, Siebel и много другого), TIBCO BW, IBM WebSphere, DB2, Postgres, Neo4j, J2EE, Apache Camel, разные MOM-ы. Там я работал в качестве архитектора интеграции всего энтерпрайзного зоопарка и ряда своих компонентов. Область бизнеса - TELCO, авиация, аналитика разного рода.
Сейчас занимаюсь системами массового обслуживания, в которых основной абоонент - не человек, а устройства (электронные ценники, умные вещи). Текущий стек - Postgres, Redis, C/C++, NodeJS и Angular (для web-интерфейсов с относительно небольшим количеством пользователей-людей). Концепция федеративной реляционной БД на уровне ядра и оперативной NoSQL на уровне middleware тут работает "на ура", а микросервисы с собственными БД избыточны. В то же время, поддерживается модульность API, а изменчивость и согласованность обеспечивается через централизованное управление метаданными.
Time-to-market, конечно, суровая реальность современного бизнеса, но я всегда был сторонником закладывания правильной основы на этепе раннего дизайна, потом отыгрывать ошибки очень дорого. У меня есть пара долгоживущих проектов, которые очень тянет переписать полностью, так как за время их жизни стало понятно, что надо было делать "не так".
Архитектура данных - важная часть общей архитектуры, требующая детальной проработки, а не "мы сейчас по-быстрому накидаем через ORM". Но, возможно, это профессиональная деформация, растущая из пачки сертификатов DB Admin/Architect :)
Однозначно профдеформация ) В современном энтерпрайзе больше засилье джавы с дотнетом, с небольшими вкраплениями того и сего. Плюсы это очень нишевая вещь, когда ты точно знаешь зачем тебе такой спец. Нода странный зверь. Вроде едва ли не самая (а может самая?) распространенная технология бэкэнда, но я не могу даже придумать как с ним микросервисы разрабатывать, а главное зачем. Разве что есть команда с определенной экспертизой и надо ее использовать. У меня до сих пор ощущение, что ноджс это когда надо сделать простой бэкэнд для веб-морды, а у тебя на руках только фронтэнды ) Наверное неправильное, как и большинство ощущений, но так уж сложилось.
Да, сейчас намного чаще подход когда хранилище данных дизайнится ближе к концу, как лоу-левел, абстрагируется и просто служит для хранения сущностей доменной модели. Исключения это когда данные имеют специфическое назначение и собираются для обработки, ну например статус-сообщения от разных девайсов на производственных линиях, или набор параметров с каких-нибудь датчиков для построения статистики и такого рода обработки, наукоемкие данные (был как-то проект где днк секвенировали, интересно было жуть...). Тогда имеет смысл зайти со стороны базы и продумать дизайн от данных, потому что они так или иначе уже заданы. В противном случае даже в высоконагруженных системах дешевле задизайнить объектную модель, отмапить ее на базу и затем оптимизировать узкие места, если появятся.
Плюсы это очень нишевая вещь, когда ты точно знаешь зачем тебе такой спец
Плюсы у нас появились ровно в тот момент, когда стали понятны требования по нагрузке и задержкам. Прототипирование выглядело совсем иначе. Что касается ноды, то в текущем основном проекте она оправдана в силу несложного, в общем-то, бэка веб-интерфейса.
В команду набирали изначально "широких" спецов с 2-3 языками, ибо проект в 2019-м был стартапный и шёл "от R&D", многое придумывалось и менялось по ходу исследований.
В целом, по моему опыту, проработка структур данных от базы во многих случаях оказывается хоть более затратным, но и более эффективным подходом, если, конечно, вы не добавляете в системе по 3 новых класса в день. Но тут всё зависит от задач и жизненного цикла системы.
А потом всё тормозит, и персональные данные всё равно утекают. :)
Зачем так всё усложнять?
Управление аккаунтами это обычный сервис по работе с персональными данными. Все, кроме пароля, хранит у себя. Доступы зарезаны максимально, но есть.
Какая разница где хранить пароль, в одной базе или в другой если этот пароль всё равно хранится в виде стойкого к перебору хеша, например Argon2 с десятком раундов? Типа персональные данные можно потерять, а хеши паролей надо хранить под тремя замками? И ради этого городить несколько бэкендов, 3 базы и т.д. Ну смешно же.
Вся надежность хешей разбивается о рост вычислительной мощности и слабые пароли юзеров. Наступило время огромных видеокарт и асиков, я бы не стал закладываться на медленные хеши. Они внезапно могут оказаться не такими медленными. Но делать их все равно надо. На случай утечки хешей будет какое-то время чтобы всем сменить пароли.
Сейчас можно заставить пользователей делать достаточно стойкие пароли для удаленного перебора, но не для локального подбора хеша.
Это я еще не усложнил. На самом деле можно хеши хранить и сверять в специальных железках. Откуда хеш вообще не достать. Я описал довольно несложную и при этом надежную систему. С ней можно работать и при этом шансы утечки критичной информации сведены к минимум на этапе проектирования.
Для обычных сайтов с паролями вообще лучше не связываться. Для них это сложно. Делать авторизацию через Гугл, Яндекс, Сбер и далее по вкусу. Надежно и просто.
Стойкость системы к взлому дожна коррелировать с ценностью хранимой там информации. Грубо говоря, нет смысла бороться bruteforce-взломом паролей на асиках, если защищается набор картинок с котиками, стянутый из интернета.
Для банка двухфактор - маcт хэв, а если сделать двухфакторную авторизацию на блог-платофрме, будет отток пользователей в сторону сервисов, где всё попроще.
Для обычных сайтов с паролями вообще лучше не связываться. Для них это
сложно. Делать авторизацию через Гугл, Яндекс, Сбер и далее по вкусу.
Надежно и просто.
И, главное, перекладывает вопрос защиты паролей (и возможных манипуляций, включая действия органов власти) с вас на Гугл, Яндекс, Сбер и далее по вкусу :)
Люди могут ставить одинаковые пароли на разные сайты. Пусть не банк, но условный Ашан с парой тысяч баллов и сайт с котиками вполне. Вроде мелочь, но зачем добавлять риски?
В то что госорганы будут требовать у Гугла/Яндекса и далее по кругу скрафтить авторизационную куку юзера чтобы по ней зайти на какой-то сайт я даже в теории не верю. Хеши из них вероятнее всего выгрузить нельзя, там могут себе позволить дорогие железки с невытаскивающимися хешами. В сложную операцию с разбором железки за много денег для теоретического вытаскивания хеша я тем более не верю.
Так что от передачи авторизации юзеров внешнему большому ресурсу одни плюсы. Для контакта с юзером стоит попросить его почту. И, блин, не спамить на нее рекламой. Только для контакта в случае чего.
Вариантов спроектировать это вагон, нужно понимать функциональные и нефункциональные требования.
да никто и не спорит что вагон. Спорят как раз с утверждением:
Если вам нужна монолитная база - вам не нужны микросервисы.
Ну, вы сказали изначально что в этом конкретном примере никаких трех баз не может быть, я привел пример обратного. Если согласны, что может быть сколько угодно баз - окей.
Если спорят с утверждением в цитате, то я не вижу где это оспаривается. Аргументы против - где? Что можно создать в теории кучку сервисов с одной базой это понятно, но моя позиция в том, что это бэд дизайн в 99% случаев. У меня конкретная претензия к такому дизайну: микросервисы должны быть физически и логически изолированы друг от друга. Общая база данных их соединяет жестким образом, превращая де-факто в один юнит, то есть это в принципе не микросервисы. И практически наверняка, если ваши несколько сервисов работают с одной и той же базой, их будет лучше объеденить в одно приложение, это будет дешевле и с точки зрения инфраструктуры, и с точки зрения разработки.
Вы обобщаете необобщаемое. Вот вам пример из жизни:
Сервис принимает картинки DICOM. В достаточно малом количестве (10000 в день максимум что мы видели). Кладет их в базу. А дальше - нейросети процессят эти картинки по несколько минут в сотнях нод с выделеными видяхами. Результат - опять картинка с красными кружочками которые выделяют найденные проблемы и небольшое описание - кладется назад в базу. Далее по готовности неторопясь отправляется клиенту. И далее ничего больше не храниться потому что PHI и HIPPA
Сервис приема, сервис отправки и сервиса обработки - разные. Стоило ли здесь городить каждому сервису базу? Ну только если хочется дизайн ради дизайна, чтобы залетный рецензент не увидел "бэд дизайн". Но если не адепт карго-культа - 3 базы здесь вообще не встали никак.
Так что утверждать что "если вам нужна монолитная база - вам не нужны микросервисы" или "это бэд дизайн в 99% случаев" - как минимум опрометчиво.
В вашем примере абсолютно неясно для чего вообще разделять эти сервисы, что вы выигрываете от того, что у вас физически разные сервисы будут принимать и отправлять данные. Я не вижу как ваш пример опровергает мой принцип. У сервиса может вообще не быть базы, это факт. Но и в чужую он лазить напрямую не должен. Если сервис - это какой-то процессинг данных, у него должен быть вход и выход. Данные подаются на вход, забираются с выхода (эндпоинты, месседж брокер, что угодно), базы у него может и не быть если он в процессе ничего не сохраняет и ему не нужны никакие дополнительные данные, конфигурации или тому подобное. То же и с остальными сервисами. У них может быть база, может не быть базы, может быть несколько баз и вообще разных источников данных. Но шарить одну между двумя разными сервисами - идея плохая. Она плохая на первый взгляд, на второй она ужасная, а на третий и далее чаще всего просто катастрофа. Это не опрометчиво, это вообще-то требование к микросервисной архитектуре, это ключевой ее паттерн. Если у вас база на несколько сервисов, то это что угодно, но не микро-сервисы. Это не я выдумал, это вытекает из назначения и требований к микросервисам, каждый микросервис должен иметь свою доменную модель, иметь независимый цикл разработки и деплоймента. Это азы микросервисной архитектуры как таковой, в ней расшареная база это анти-паттерн.
Еще раз, это не карго-культ, я привел очень четкую и конкретную причину почему так, это не дизайн ради дизайна, это многолетняя практика работы с микросервисами. Это солид микросервисного дизайна. Даже если вы на 100% уверены, что в данном конкретном случае вы должны нарушить солид, вы должны подумать, подумать и еще раз хорошенько подумать. И лучше его не нарушать, если все же возможность есть.
Ладно, тут все понятно. Если паттерн и солид нарушен то нарушитель изгоняется из секты микросервисов.
Там выше в самой статье написана умная мысль - не рассматривать двумерные ситуации. Или-или. А вы ровно это сейчас и делаете. Если база одна значит это не микросервис... Ну ок. Значит у нас макросервисы и можем делать что хотим, ура.
В реальной жизни решают задачи наиболее оптимальными способами, а не следуют догмам. Все эти ваши вход-выход-брокер-эндпоинт разобьются в дребезги, когда вам скажут что инфа должна лежать именно в такой то базе, потому что она одобрена HIPPA, вход должен быть сертифицирован таким то образом, а выход сделан на таком то языке потому что он уже сделан. И еще множество нюансов из той же области. И как вы будете после всего этого расказывать аудиторам про солид и многолетнюю практику
Я 23 года в разработке, 6 лет архитект, вы хотите мне рассказать как оно в реальной жизни? Хорошо, я вас услышал.
По-вашему выходит, что все принципы, практики, архитектурные паттерны - все фигня, ничего не формализуемо, не обобщаемо, везде и всюду импровизируем на пальцах по принципу "я художник, я так вижу"? Позволю себе не согласиться.
Если вас "в реальной жизни" заставляют писать, или дизайнить что-то не то, это не аргумент в пользу игнорирования принципов и паттернов, это аргумент против вашего текущего места работы.
Я в разработке дольше и званий имею больше. И сказать бы мог еще чего то, но раз в ход пошли аргументы в виде возраста и минусов к постам - разговор заканчиваю
Минусы ставлю не я, у меня и возможности такой нет.
Возраст не аргумент, а лишь указание на несостоятельность ваших "в реальной жизни". Я прекрасно знаю как оно в реальной жизни, не нужно мне этого рассказывать. И для этого совершенно не нужно меряться званиями. Тем более что я никаких званий своих не приводил, архитект это должность, ответственного за архитектуру.
Аргументов я дал предостаточно, у вас не было ни одного, кроме того что обстоятельства могут вынудить нарушать принципы. Сомневаюсь что к этому ничего вы можете добавить что-то по существу.
Человек вам говорит про правило, а вы пытаетесь его опровергнуть отдельным частным случаем. Если вы сделали архитектурно плохое решение из-за сертификации, оно от этого не становится архитектурно хорошим. Вы согласились получить некоторые архитектурные проблемы в обмен на сертификацию, а в других проектах, где сертификация не требуется, будут только архитектурные проблемы. Это и есть причина, по которой такой подход считается неправильным.
инфа должна лежать именно в такой то базе, потому что она одобрена HIPPA
Вам это никак не мешает передавать данные из этой базы в процесс, которому они нужны, не через прямое подключение его к БД, а через любой другой сетевой протокол.
вход должен быть сертифицирован таким то образом, а выход сделан на таком то языке потому что он уже сделан
Это не создает необходимость лазить напрямую в чужую БД.
Ок, все так. Берем и пишем новый сервис который принимает на вход задачи по обработке от входного сервиса, кладет их в свою личную базу, и отдает задачи взлетевшим сервисам по обработке. А сервиса обработки отдают резултаты еще одному сервису который пишет эти результаты в свою базу.
Итого имеем входной сервис, промежуточный сервис с базой, сервиса обработки без базы, сервис результатов со своей базой.
Теперь все по феншую?
Вмсето 3х сервисов, один из которых (сервис обработки) маштабируется в больших количествах - имеем 4 сервиса и 2 базы. Причем промежуточный сервис является точкой отказа для остальных (кроме выходного). А выходной тоже является точкой отказа для сервисов обработки.
Получаем красивую архитектуру с точки зрения адептов микросервисов и как минимум х2 гемороя для девопсов,
Вопрос - что получил бизнес, кроме следования абстрактным паттернам (на которые бизнесу пофиг)?
Еще раз напомню что база здесь не является узким местом, 10 тыщ записей в день неспособны нагрузить никого. И ее выбор ограничен только требованиями сертификации
Теперь все по феншую?
Нет. Я же написал в предыдущем комментарии, какой подход будет более правильным.
Получаем красивую архитектуру с точки зрения адептов микросервисов
Нет, не получаем. Это неправильная архитектура. Если бы вы не ерничали, а пытались понять собеседников, то сами бы это поняли.
Берем и пишем новый сервис который принимает на вход задачи по обработке от входного сервиса, кладет их в свою личную базу, и отдает задачи взлетевшим сервисам по обработке.
Зачем?
Входной сервис принимает данные, кладет в свою базу. Обрабатывающий сервис читает их не напрямую из базы, а через API. Или из очереди, в которую пишет тот же входной сервис. После обработки отдает обратно первому тоже через API или через очередь. Выходной сервис тоже читает через API или через очередь. Те же 3 сервиса, только протокол взаимодействия другой. Любые компоненты масштабируются в любом количестве.
С очередью в среднем удобнее, потому что можно отправлять события, что появились новые данные, ретрай делается автоматически, если принимающий сервис в данный момент недоступен, и т.д.
Вопрос - что получил бизнес, кроме следования абстрактным паттернам
Отсутствие ситуаций типа "Блин, мы в базе поле переименовали, в первом сервисе переименовали, а во втором забыли. Потому что его разрабатывает другая команда, и никто им не сообщил. А отсутствие поля в базе у них приравнялось к NULL, и теперь у нас результаты обработки за последние 3 дня неправильные. Надо исправлять все результаты, сообщать клиентам, платить компенсации. Пока исправляем, все другие задачи откладываются. Бизнес из-за этого потеряет деньги, ну что теперь сделаешь.".
Очедь нельзя.
Все остальное - просто входной/выходной сервис становится еще и намордником для базы, в которую обработчики пишут уже не напрямую а через апи, предоставляемое входным/выходным сервисом. Тем самым нагружая входной/выходной сервис дополнительной функциональностью и увеличивая количество точек отказа.
Отсутствие ситуаций типа "Блин, мы в базе поле переименовали, в первом сервисе переименовали, а во втором забыли. Потому что его разрабатывает другая команда, и никто им не сообщил. А отсутствие поля в базе у них приравнялось к NULL,
та же ситуация если в новом апи произойдут изменения. Проблемы с версионингом апи те же самые что и с версионингом базы.
Тем самым нагружая входной/выходной сервис дополнительной функциональностью и увеличивая количество точек отказа.
Точка отказа как была так и осталась - один входной сервис.
Нагрузка по вашим словам и так небольшая, а эта дополнительная функциональность дает независимость изменений.
та же ситуация
Да, только при изменениях базы API можно не менять, соответственно и его клиенты менять не нужно. А если кроме базы ничего нет, то менять придется везде.
Тут еще есть такая ситуация. Сделали миграцию для переименования поля в базе из "abc" в "def", переименовали в исходном коде во всех сервисах, выкатили на прод, миграция применилась. А в проде в момент выкладки было запущено 100 инстансов второго сервиса, которые обрабатывают данные, в них поле еще называется "abc". Они завершили обработку, пытаются записать в поле "abc", а его нет. Они падают с ошибкой, данные потерялись. В API можно оба поля поддерживать, а как они в базу пишутся, это детали реализации сервиса. В базе тоже теоретически можно, но надо городить огород с триггерами и прочим, это требует больше работы.
Точка отказа как была так и осталась - один входной сервис.
нет. Сервиса обработчики не смогут отдать свой результат если выходной сервис ляжет. Или не смогу получить задачу если лежит входной.
Да, только при изменениях базы API можно не менять, соответственно и его клиенты менять не нужно. А если кроме базы ничего нет, то менять придется везде.
Да, только при изменениях АПИ базу можно и не менять. Абсолютно зеркальная ситуация
Тут еще есть такая ситуация. Сделали миграцию для переименования поля в базе из "abc" в "def", переименовали в исходном коде во всех сервисах, выкатили на прод, миграция применилась. А в проде в момент выкладки было запущено 100 инстансов второго сервиса, которые обрабатывают данные, в них поле еще называется "abc". Они завершили обработку, пытаются записать в поле "abc", а его нет. Они падают с ошибкой, данные потерялись. В API можно оба поля поддерживать, а как они в базу пишутся, это детали реализации сервиса. В базе тоже теоретически можно, но надо городить огород с триггерами и прочим, это требует больше работы.
вы описываете ситуацию с zero downtime, там что в апи поддерживать два поля, что в базе - одинаково сложно. Апи позволяет немного сгладить этот процесс, но в целом - прямой доступ к базе это тоже своего рода АПИ.
В обеих ситуациях возможны похожие проблемы.
Или не смогут получить задачу если лежит входной.
Если база лежит, то тоже не смогут, с базой тут нет преимущества.
Если входной сервис лежит, новые задачи в базе вообще не появятся в любом варианте.
только при изменениях АПИ базу можно и не менять
Ну да, это ещё одно преимущество скрывания базы за API. Непонятно, почему вы подаете это как возражение. Вы-то говорите про вариант, когда API нет.
одинаково сложно
Да нет, добавить поле во входную структуру проще, чем добавить колонку в базу, заполнить ее данными, и сделать триггер для новых записей.
В обеих ситуациях возможны похожие проблемы
Нет, без прямого доступа к базе нет проблемы "Поменяли базу для внутренних целей, и другой сервис сломался". API по определению нужно только для внешних клиентов, у него нет внутренних целей.
Особые случаи можно найти везде, но правило от этого не становится неверным. В среднем такие решения требуют меньше поддержки, поэтому правило и появилось.
Если база лежит, то тоже не смогут, с базой тут нет преимущества.Если входной сервис лежит, новые задачи в базе вообще не появятся в любом варианте.
если база лежит то ничего не будет работать в любой конфигурации. Хоть как хочешь делай.
Если входной сервис лежит, новые задачи в базе вообще не появятся в любом варианте.
если лежит входной сервис, то никто не мешает обработчикам и выходному сревису работать над уже полученными задачами.
Да нет, добавить поле во входную структуру проще, чем добавить колонку в базу, заполнить ее данными, и сделать триггер для новых записей.
в общем случае - абсолютно одинкаово. Частные случаи могут иметь любую сложность как с апи так и с базой. И изменения в апи никоем образом не исключают изменения в базе. Что вы тут пытаетесь усложнить я не понял
Нет, без прямого доступа к базе нет проблемы "Поменяли базу для внутренних целей, и другой сервис сломался". API по определению нужно только для внешних клиентов, у него нет внутренних целей.
мы ходим по кругу. Ситуация - поменяли апи и другой сервис сломался такая же.
В общем случае спор свелся к теме - нужен ли на базу намордник в виде апи или проще работать с ней напрямую.
Если на базу надеть апи, то это апи превращается в микросервис со своей внутренней базой и все становится по феншую.
Если не надеть, то все становится просто проще.
Вопрос - надевать или нет, и где этот намордник физически расположить - в каком то уже имеющимся сервисе или отдельно, как его назвать и в скольких экземплярах хостить - лежит в плоскости абстрактных рассуждений. Без знания конкретных условий, выделенных ресурсов, всех требований и прочего - беспредметный разговор. Тем более что автор статьи уже про это написал:
И есть же ещё куча вариантов где-то между, этими двумя, где N модулей могут лежать в M репах и деплоиться в P образов. Если вы видите только монолиты и микросервисы, вы не видите кучу вариантов между ними.
в общем случае - абсолютно одинаково
Нет, в общем случае не одинаково. Для API в общем случае это просто одна строка в исходном коде с новым полем. И еще одна, которая пишет ее в то же поле базы. Всё.
работать над уже полученными задачами
Ну так потом-то они закончатся, а новых нет.
Ситуация - поменяли апи и другой сервис сломался такая же.
Я уже про это сказал. Да, она такая же, только API нужен исключительно для других сервисов, и для внутренних целей его менять не будут. А базу в основном для этого и меняют. Кроме того, 2 версии API поддерживать не так уж сложно, а 2 версии базы со всеми данными и с разной структурой полей практически невозможно.
Если не надеть, то все становится просто проще.
Нет, примеры сложностей я приводил в первых комментариях.
Без знания конкретных условий, выделенных ресурсов, всех требований и прочего - беспредметный разговор.
Естественно, и именно поэтому это правило это не догма, как вы утверждаете. Если у вас есть причины в виде условий и требований сделать по-другому, делаете по-другому, потому что получаете какой-то профит. Если же после оценки всего этого от общей базы профита нет, то делать общую базу не надо. В этом и заключается обсуждаемое правило.
Ворвусь с середины. Какой-то спор о терминах.
Допустим у нас одна база, значит у нас не микросервисная архитектура и, соответственно, не микросервисы.
Но нам понадобилось вынести нагрузку на отдельные сервисы с общей БД. Берём и выносим, в чём проблема то? Да, это плохая микросервисная архитектура, но это хорошая архитектура, исходя из предъявляемых к ней требований.
Но, опять таки, всё не так однозначно. Из статьи по последней ссылке:
A shared database is considered an anti-pattern. Although, it’s debatable.
Проблема в том, что это плохая архитектура. По причинам, озвученым выше и так до сих пор аргументированно не опровергнутым. Да, все в мире программирования обсуждаемо и debatable, все без исключения принципы. Но они существуют.
When a shared database seems to be the best option for the microservices project, we should rethink if we really need the microservices. Maybe the monolith would be the better choice.
Это буквально то, что я написал в самом начале. И до сих пор все аргументы "против" сводятся "не, ну а почему бы и не сделать одну базу, это ж может работать?" и "жизнь может вас заставить поступиться принципами". Ни то, ни другое, аргументом не является.
Плохой/хороший - это оценочные суждения, всегда важен контекст.
Причины выше - это про ссылки на паттерны? Не совсем понимаю, что там нужно опровергать.
Ну вот не подходит человеку монолит, нужно ему множество экземпляров. Чем это архитектура плоха, кроме того, что содержит некоторые риски с точки зрения микросервисов, которые никогда ни сыграют?
что вы выигрываете от того, что у вас физически разные сервисы будут принимать и отправлять данные
Очевидно независимое масштабирование и использование разных языков и конфигураций машин.
Независимое масштабирование с расшареной базой невозможно, потому что как минимум через базу зависимость остается.
Причины выше - это причины выше, там они подробно объяснены, про изолированную модель, контекст, цикл разработки, деплоймент и масштабирование. А по ссылкам детально описано почему и отчего. Если человеку обязательно нужно нарушить принцип инверсии зависимостей, единой ответсвенности, или опен/клоуз - ради бога, пусть нарушает. Но это плохо заканчивается. Обычно. Поэтому и существуют эти принципы и паттерны, которые называются принципами и паттернами. Они сформированы путем обобщения большого количества совокупного опыта и объединенных теоретических знаний поколениями программистов и архитекторов. И их лучше не нарушать без очевидной необходимости. Которую вы можете четко обосновать, почему именно в вашем случае нужно пойти против сформировавшейся бест практис. Как еще понятнее донести я не знаю. Считаете, что в вашем случае риски никогда не сыграют и вас пронесет? Да пожалуйста, но эти риски и объективные причины никуда не делись, они обоснованы и описаны, они не эфемерны и не с потолка взяты и никем не опровергнуты. Поэтому я о них написал, и в силу этих причин я и являюсь противником монолитных баз для разных сервисов. О чем еще вы хотите поспорить? Что можно изолентой ремонтировать мебель? Ну можно, почему ж нельзя, кто может вам запретить. Может у вас и опыт положительный имеется. Я вообще не против изоленты, у меня у самого лежит на всякий пожарный. Но я заговорил о принципах проектирования, как следует, и как не следует проектировать архитектуру микросервисного решения, об одном из принципов. Принцип существует, обоснованный, описан в каждой первой книге и мануале по микросервисной архитектуре, подробно обоснован и обсосан с разных сторон. Не является моей прихотью, карго-культом, забавным проявлением эксцентричности или просто необоснованным модным трендом.
Независимое масштабирование с расшареной базой невозможно, потому что как минимум через базу зависимость остается.
Вот это не понял. Ну будут обработчики со своей базой, при их масштабировании база будет точно таким же узким горлышком. Можем мы как-то по разном масштабирование понимаем. Я имел ввиду, что у нас 2 экземпляра апи и 100 экземпляров обработчиков. Захотим, сделаем 10 экземпляров на ночь.
Вообще, меня смущает некий догматизм. По поему опыту серебряной пули не существует, а все принципы противоречат друг другу. И когда человек говорит, что только так и не иначе, то я отношусь к этому настороженно. Скорее всего есть опыт заточенный под конкретные условия и в других условиях будет либо фигня, либо оверинженеринг.
Вопрос в тем, что такое правильно и хорошо? Вот оно зависит от контекста. И архитектура зависит от контекста. Собственно вся статья об этом.
Из смешного: если бы у меня была возможность, я бы сервисы обработки тоже делал стейтлес (:
Отдельную базу можно масштабировать отдельно. Ну если это какой-то клауд, то можно выбрать тир для базы повыше - например. И сам сервис полностью изолированно масштабируется от другого.
Это не догматизм, догмат - это убеждение без рациональных объяснений. Например о непорочном зачатии. А я привожу рациональные объяснения, которые к тому же не я лично один придумал, а о них можно почитать где угодно. Почему вам не нравится аналогия с другими принципами? Принципы существуют, бест практисез существуют, архитектурные приемы тоже сформированы не на пустом месте. Я не говорю только так, и никак иначе, я говорю что существует такой принцип и я его склонен придерживаться, а если мне требуется его нарушить - я к такому случаю отнесусь очень и очень настороженно и подозрительно.
Так в этом примере точно так же масштабируем базу и всё работает. Вообще никаких преимуществ не вижу.
я говорю что существует такой принцип и я его склонен придерживаться
Вот в такой формулировке звучит нормально. Осталось добавить ещё "в таких-то обстоятельствах". Т.к. у каждого принципа есть недостатки. Но было сказано:
Если вам кажется, что 2 сервиса обязаны иметь одну базу - смело объединяйте их в один. Если вы твердо решили разделить сервис на 2 и более - сразу решайте как разделить базу. Причем в первую очередь. Если выходит плохо - см. пункт 1.
Звучит, если не догматично, то категорично. Такой подход иногда будет звучать так: мы потратим больше денег/времени, нам будет сложнее поддерживать и деплоить без какого-либо профита для бизнеса, но зато будет правильно (по нашему мнению).
Она плохая на первый взгляд, на второй она ужасная, а на третий и далее чаще всего просто катастрофа. Это не опрометчиво, это вообще-то требование к микросервисной архитектуре, это ключевой ее паттерн. Если у вас база на несколько сервисов, то это что угодно, но не микро-сервисы.
Это не я выдумал, это вытекает из назначения и требований к микросервисам, каждый микросервис должен иметь свою доменную модель, иметь независимый цикл разработки и деплоймента. Это азы микросервисной архитектуры как таковой, в ней расшареная база это анти-паттерн.
А вы никогда не рассматривали базу данных как сервис, который хранит данные? Уберите это неоднозначное слово "микро", потому что вообще не понятно, что такое "микро" сервис и чем он отличается от "нано" сервиса или "мини" сервиса.
База - это просто ещё один сервис, с которым взаимодействуют другие сервисы, у каждого сервиса своя ответственность, каждый может как-то масштабироваться. И не надо никаких догм и карго-культов и рассуждений про "азы микросервисной архитектуры".
Если удобнее сделать, чтобы один кусок вашей распределённой системы писал в базу, а другой читал, ну нет в этом никакой проблемы пока у вас нет никаких проблем. Если появляются проблемы, надо думать дальше.
База - это не сервис. Это хранилище данных, часть инфраструктуры. Как редис кэш, брокер сообщений, или цдн с файлами. Сервис - это логический юнит вашей системы, набор доменных сущностей, бизнес-логика и какие-то интерфейсы для взаимодействия. Сервис может использовать базу для хранения каких-то сущностей, может не использовать.
Да, пока нет проблем, то нет проблем. А как проблемы появляются всегда можно сменить проект. Но еще существует подход, когда проблем пытаются избежать, заранее продумав подходящую архитектуру системы.
"Если удобнее сделать" - чем удобнее? 2 сервиса это всегда не так удобно, как 1. Один всегда намного удобнее, проще и дешевле. Чтобы разделить вашу систему на 2 независимых куска, работающих раздельно, нужна веская причина. И если у вас есть эта причина, существуют определенные, неплохо зарекомендовавшие себя подходы, как это лучше делать. Можно запихнуть всю бизнес-логику вашего приложения в один класс. И пока у вас нет никаких проблем, то в этом нет никакой проблемы. А когда проблемы появятся, можно подумать. А можно подумать зарание, и тогда вероятность появления проблем снизится.
База - это не сервис.
База - это просто ещё один кусок вашей системы, не важно как вы её назовёте, у неё есть точно такой же интерфейс для взаимодействия и есть логика хранения данных на уровне хранения данных. Сервис - это просто сущность, которая оперирует данными на входе и на выходе. Нет данных, нет системы, нет ничего.
А можно подумать зарание, и тогда вероятность появления проблем снизится.
Если бы это работало, все бы думали заранее и программы, написанные однажды, никогда не переписывали, и все были бы довольны. Но это не работает. Современные программы и проекты никогда не заканчиваются. Вы можете год проектировать архитектуру, а можете год колбасить "говнокод" на коленке. Всё равно кто-то будет всё это дописывать, переписывать, переделывать, перепроектировать и не один раз, если этот код будет хоть кому-то нужен. Я не видел ни одного проекта, который бы постоянно не пилили, и те, которые были спроектированы заранее, и те, которые писались на коленке "просто, чтобы показать MVP". Выкатываются новые требования и всё начинается снова. Перепиливается архитектура, вставляются костыли, убираются костыли и так до бесконечности.
И смотря на всё это 10 лет я подумал: да нафиг надо, делай проще, как можно проще, всё равно всё выкинут и перепишут заново, как бы ты ни пыжился. Ну вот и делай так, чтобы это было хотя бы проще переписать или не жалко выкинуть, когда появятся очередные требования, повёрнутые на 180 градусов от первоначальной идеи. Я не говорю, что надо писать говнокод и вообще не заниматься проектированием системы, но пытаться всё сделать идеально и правильно заранее никогда не выйдет. Поэтому даже и пытаться не стоит.
На счёт того, что 1 сервис - это всегда проще чем два, то я бы сказал, что почти всегда, но бывает, что проще/удобнее/необходимо сделать два. Всегда есть исключения, всегда есть нюансы.
В монолитных базах как раз узким горлышком идет база. Это либо количество подключений, либо блоки при транзакция.
"Можно писать на любом языке" и "2-pizza team" это все selling points для недоверчивых технарей, а я расскажу, почему на самом деле бизнес выбирает микросервисы. Причин всего две:
1. Быстрая проверка гипотез, которые в 9 из 10 случаев проваливаются - да, продакт-менеджеры тоже не боги. В случае монолита вы стоите перед непростым выбором: или вкладываться по полной в эксперимент (дизайн, код, тесты), который, скорее всего, будет выброшен, или на коленке слепить то, что рискует выстрелить, и тогда с этим поделием придется жить вечно в монолите. Какой вариант хуже? Оба хуже. В случае с микросервисами эксперименты не сильно трогают ядро системы, которая кормит всю компанию и их семьи.
2. Найм. В ситуации, когда средней компании найти хорошего разработчика за праздник, в случае микросервисной архитектуры можно нанимать вообще любых программистов, которые подвернулись, а не те, которые подходят по стеку или согласны работать с легаси и т.п. Они не испортят сильно, и они всегда найдут, где приложиться.
Эти две причины пересиливают (как будто бы) все сложности, связанные с МСА. А сложностей немало, от оркестрации до смены парадигмы владения системами.
Все, кроме этих двух причин на самом деле ни зачем не надо. А, еще маленькое замечание: проще нанимать людей, потому что "у нас такие же крутые технологии, как в Гугле (так что мы будем платить поменьше)".
Быстрая проверка гипотез
Решается не микросервисами, а специальными инструментами: будь то отдельная инфраструктура для AB-тестирования или feature toggle. То же самое может быть организовано и в монолите. По вашему что, под каждую гипотезу пишется свой микросервис, а потом дропается?
в случае микросервисной архитектуры можно нанимать вообще любых программистов
у нас такие же крутые технологии, как в Гугле (так что мы будем платить поменьше)
Какие-то влажные фантазии. Наверное, поэтому зарплаты Golang (основной язык для этих ваших микросервисов) в ТОП-5 на бекенде?
Кажется, ваш обидел какой-то адепт микросервисов и вы теперь вымещаете зло на всех. Не стоит: человек может быть просто не очень, независимо от того, на чём пишет.
Никогда не понимал этого "можно нанимать любых программистов потому что у нас микросервисы". Сегодня наймем джависта, завтра дотнетчика, а послезавтра питониста. А кто весь этот зоопарк потом подлерживать будет? Или микросервисы - это всегда write-only код?
найти хорошего разработчика за праздник
Любой программист - это про уровень навыков. Тут как-то чувак жаловался на яндекс, что понаделали микросервисов в которых 80% кода генерируется тулами, а 20% пишет кто угодно по контракту аналитиков. Типа там они платят меньше и легче заменяют программистов.
Если подумать, программисты пытаются построить систему из ненадёжных частей, а менеджеры - надёжный процесс разработки из ненадёжных сотрудников.
Дык, у них write-only - основное рекламное преимущество, похоже. Чтоб не влом было любой взять и целиком переписать за вменяемое время на любой новой технологии. Но так никогда не получается, ИМХО.
Одно из топовых требований к микросервису - чтобы 1 команда могла переписать его целиком за 1 спринт. Так что да, write-only.
Компании, для которых актуальны приведённые вами преимущества, составляют очень узкую прослойку ИТ рынка. Я в таких не работал, например, а только слышал и читал о них.
Я работал там, где 9 из 10 гипотез подтверждаются, а продакт должен просто бэклог приоритезировать правильно.
Спасибо что не побоялись сказать то, что у многих уже накипело.
Самый важный аспект упустили: микросервисы deploy fast. Это и хорошо и плохо.
Допустим, у вас продукт, над которым работают 5 команд, каждая отвечает за свой модуль/микросервис. Одна команда сделала синюю кнопочку зелененькой и менеджмент хочет прям завтра видеть ее зеленой на проде, потому что поднимет продажи, конверсию все дела. Если выкатим послезавтра - потеряем миллионы, а менеджер годовую премию.
В случае монолита очень сложно сделать быстрый релиз: ведь в той же единице деплоймента(монолит) находятся текущие изменения остальных 4х команд. Соотвественно, во первых надо согласовать со всеми что код готов к выкатке, во вторых сделать полную регрессию чтобы убедиться что все таки работает. И затем выкатить. На завтра не получится никак, ну или тестеров наручниками к батарее на ночь.
В случае с микросервисами, изменение внесены в куда более меньшую единицу деплоймента, за которую отвечает одна команда. Соотвественно не надо никаких согласований с другими, обьем регресионного тестирования в 5 раз меньше и выкатить завтра выглядит вполне себе реальной задачей.
Аналогично, облегчается задача 0-downtime deployment для асинхронных воркеров: в ряде случаев их можно передеплоивать с даунтаймом, при условии гарантированной доставки им сообщений.
Но весь этот прекрасный мир работает до тех пор, пока нет изменений в контрактах между микросервисами.
В случае с монолитом все внутренние контракты входят в одну единицу деплоймента, соотвественно поменяли, задеплоили.
В случае с микросервисами, это не так. У каждого микросеврсиа свой релизный цикл. И если команда А поменяла контракт, то у команды Б(которая вызывает микросервис команды А), свои планы, свои задачи и тд. У команды В, которая тоже дергает микросервис команды А - своя история. И на практике команде А надо поддерживать 2 версии контракта, старую и новую, пока клиенты не перейдут на новую. Это может занять время, и новое изменение контракта уже в планах... 3 версии....
There is no silver bullet к сожаление.
В случае монолита очень сложно сделать быстрый релиз: ведь в той же единице деплоймента(монолит) находятся текущие изменения остальных 4х команд.
Но весь этот прекрасный мир работает до тех пор, пока нет изменений в контрактах между микросервисами.
Все просто - если у вас хорошие контракты - либо между модулями (монолит), либо между сервисами (микросервисы), то вы можете деплоится быстро и независимо - потому что дотестировать изменение контрактов не нужно. Монолит пересобирается с обновленными модулями/библиотеками, сервисы выкатываются и перезапускаются.
А если у вас контракты постоянно меняются, то проблемы будут что на монолите, что на микросервисах.
В любом случае упор в качественную архитектуру с хорошей изоляцией и контрактами.
потому что дотестировать изменение контрактов не нужно
Если монолит деплоится в разные контейнеры, то это уже не монолит. Вариант деплоя отдельных библиотек даже не рассматриваю.
Текущая версия монолита пересобирается с обновленными библиотеками (которые пилятся разными командами как раз) и деплоится.
Тогда надо делать полную регрессию, это вам любой QA скажет.
Что мне скажет QA, меня мало интересует. Меня интересует, будет работать или нет.
Если вы фиксите багу без изменения контрактов - можно перезапустить что сервис, что передеплоить монолит - почти без последствий, и в большинстве случаев будет работать (и на практике так и делают для хотфиксов)
Если меняются контракты - что монолит, что микросервисы склонны к проблемам из-за некогерентности, даже если все "мамой клянутся, что все заработает".
Что мне скажет QA, меня мало интересует.
Я думаю что ваше мнение мало интересует ПМ-а, который рулит разработкой 5 команд. У него банально нет времени идти в код и смотреть историю мерж реквестов, нарушились ли контракты или нет. За качество отвечают QA и именно их будут спрашивать какие тест сеты надо заранать.
Если меняются контракты - что монолит, что микросервисы склонны к проблемам из-за некогерентности
Микросервисы этим страдают гораздо больше, потому что нет возможности атомарного деплоя. В монолите зачастую солюшн просто не соберется локально, если контракты поломались - соотвественно все фиксы до выкатки на энвы.
Микросервисы этим страдают гораздо больше, потому что нет возможности атомарного деплоя. В монолите зачастую солюшн просто не соберется локально, если контракты поломались - соотвественно все фиксы до выкатки на энвы.
Ну, вот с этим согласен, да. Поэтому я в своей собственной практике больше на монолит с модулями опираюсь ))
А так, конечно, по-любому нужен QA, вне зависимости от способа разработки софта.
Соглашусь с тем, что если настроить метрики отслеживания изменений контрактов(например вынести контракты в отдельную либу и настроить алармы на мержи), то наверное можно будет настроить процесс и договориться что если контракты не поменялись - то не нужно полной регрессии. На практике такого не видел и имха в общем и целом это тежи микросервисы, вид сбоку. Есть свои бенефиты в виде выкатки всего сразу, и соотвественно не нужно поддерживать несколько версий контрактов. И есть недостатки - высокая инженерная культура в компании и хорошо налаженный процесс. В моей практике, 5 команд - это под сотню вовлеченных людей, включая субподрядчиков, большинство из которых хотят просто написать код побыстрей и закрыть таску. Все, работа сделана.
И есть недостатки - высокая инженерная культура в компании и хорошо налаженный процесс.
Согласен, это под хороших инженеров отличный воркфлоу.
С распределенными под сотню человек дела не имел, и подозреваю, что да, там другие проблемы, и пусть закрываются задачи хотя бы на отдельных сервисах (откуда и любовь к сервисам)
Согласен, это под хороших инженеров отличный воркфлоу.
И идеальные менеджеры :)
С распределенными под сотню человек дела не имел
А вот тут начинается вся та веселуха. Независисмый релиз цикл и независимый деплоймент модулей(микросервисов) решает очень много организационных проблем. Больше чем привносит, и опять таки фокус скорее на процессе, а не на технических решениях. Соглашусь, в команде из 10 высокоскиллованых профи, которую не собираются в течении года увеличить в 10 раз, микросервисы скорее не нужны чем наоборот
в той же единице деплоймента
@Captain_Jack, тут хорошая формулировка, как мне кажется.
В случае с микросервисами, изменение внесены в куда более меньшую единицу деплоймента
- так-то да, но если они вдруг поменяли контракт или просто вкрутили проверку типов, могут повалиться все остальные единицы деплоймента. Или сервис стал вдруг кушать в два раза больше памяти, на тестовом стенде может и норм, а на сервере с ещё 5-ю другими микросервисами в проде критично
Cоотвественно не надо никаких согласований с другими, обьем регресионного тестирования в 5 раз меньше и выкатить завтра выглядит вполне себе реальной задачей.
- и упасти от вышенаписанного может только полноценный регресс
но если они вдруг поменяли контракт
Об этом написано в том же комментарии, который вы цитируете, абзацом ниже.
Или сервис стал вдруг кушать в два раза больше памяти
Если монолит стал кушать в 2 раза больше памяти то проблемы ровно такие же - это совсем другой аспект. Деплойтесь в клауда, там обычно надо очень постараться чтобы выжрать в лимиты. И да, регресс в этом случае не поможет потому что регресс - это функциональное тестирование на вашем же "тестовом стенде". Для решения проблем с перфомансом и выжиранием ресурсов давно придумали перфоманс тесты на энве максимально приближенном к проду(некоторые делают прям на проде). Но это совсем другая проблема, которая может возникнуть и в монолите, и в микросервисах и в серверлес.
А дальше никто не запрещает эти N модулей начать деплоить в M артефактов вместо 1. Если вы не нарушали границы между модулями, то просто пошли, обмазали это всё контроллерами или кафкой, поменяли конфиг сборки - и готово.
Звучит так, словно с вызовов на кафки перейти раз плюнуть :) Хотя при проектировании изначально под асинхронные обмены ряд решений и даже базовых понятий могут оказаться совсем другими.
По какой-то совершенно неизвестной мне причине первое часто приравнивается ко второму, хотя это как сладкое и мокрое, вообще разное
Это называется плохая репутация.
У нас тут на хабре олды с 20+ лет опыта любят рассказывать, как божественно они писали 10-15 лет назад. А мой личный опыт таков, что самый всратый код - это как раз с культурного слоя "конец нулевых, начало десятых" и написан он нынешними архитекторами и си-грейдами. Причина проста: не хватало еще коллективного опыта плюс над ними не было старших товарищей с этими же 20+ годами. Если говорим про джаву, то в нулевых годах это был еще молодой язык с растущей экосистемой. Писали кто во что горазд.
Следующее поколение пришло, взглянуло на эту хтонь, ужаснулось и выработало ассоциацию "монолит == говнокод, только микросервисы, только хардкор". Говнокода в микросервисах тоже хватает, но опять же по моему опыту, работать с ним не настолько больно. Потому что у этого поколения уже есть опытные старшие товарищи с живительным подзатыльником.
Новое поколение приходит и видит данную дискуссию монолит vs микросервисы. Надеюсь, они будут допускать еще меньше идиотских ошибок.
Не бывает абсолютно идеальной архитектуры. И близкой к идеальной не бывает. Идеальность всегда завязана на текущие доступные вычислительные ресурсы / сетевые возможности. Java середины-начала нулевых (да, я оттуда) это весьма некислые цены на выделенные сервера и толщину канала. И если стоит задача обеспечить 300...500 rps при достаточно сложных требованиях от бизнеса, то будет использована именно та архитектура, которая это обеспечит.
Вы в целом описали как эволюционирует наша индустрия. Плохо, что ли? Хорошо.
Ну не 10-15, побольше. А точнее даже, дело вообще не в годах.
В 2005, т.е. почти 20 лет назад, вокруг меня были вполне устоявшиеся коллективы с приличным коллективным опытом.
А то что бывали и другие, ну так скажете, что сейчас их нет, тех что без опыта и без старших товарищей, которые говнокодят на передовых технологиях?
Само же предположение о репутации... оно вполне валидное.
В 2005, т.е. почти 20 лет назад, вокруг меня были вполне устоявшиеся коллективы с приличным коллективным опытом.
Да и в 1990-х были. Примеры: авиакомпания KLM или голландская государственная телефонная компания KPN Telecom.
"если тебе нравиться твой старый код, значит все это время ты не развивался" (с) не помню
Причина проста: не хватало еще коллективного опыта
Это после после 30-40 лет активного прогресса в софтвареписании? Code Complete МакКоннела была в 93м году написана Design Pattens от GoF в 94м, Patterns of Enterprise Architecture от Фаулера в 2003, Enterprise Integration Patterns от Хопа в 2003м....
Если у вас эти книги не читали - то ой, другие читали и писали нормальный код.
Мало нам было разработчиков которые спорят как нужно правильно писать код вместо того чтобы хоть что-нибудь написать. Так теперь ещё об'явились не_разработчики (судя по посылу) которые указывают разработчикам как им правильно думать на тему (и без), и о чем теперь модно спорить...
Вот эти два пункта ИМХО и есть основная причина по которой нужны микросервисы:
Когда мы хотим вообще другой релизный цикл для модуля - хотим деплоить его много, часто, и версионировать своими версиями, и не хотим, чтобы пришлось в релизы тащить все 50 модулей вместе с ним.
Ну либо у нас большая система, и какие-то модули поддерживает отдельная команда, Тогда может быть они сами хотят решать всё что описано выше, и пусть решают себе, и дайте им контроль над тем, как деплоится их код, а не мучайте в общем релизе общего артефакта. Или мучайте если уж так хотите, кто я такой чтобы вам тут указывать.
Еще хотелось бы прочитать мнение автора про проблемы с общей базы данных и разделении базы между микросервисами. Я помню, что это была основная причина уложнения когда мы выделили микросервисы из монолита.
Когда у тебя несколько монолитов. Они становятся микросервисами. Автор, конечно, смешал в кучу всё на свете.
В целом с большинством тезисов согласен.
Только один комментарий. Микросервисы - это не про технологии, микросервисы - это про бизнес, про способ организации работы большого количества разработчиков. И основной значимый критерий сервис микро или нет - одна ИТ команда (5-7 человеков) полностью отвечает за сервис, от разработки до сопровождения. Работает плохо этот сервис? Только эта команда его чинит.
Является ли микросервис - подой в кубере или OSGI-модулем в большом java-приложении - в общем случае неважно. Хотя в экстремуме микросервис должен обладать своими собственными ресурсами, которые никакой другой сервис забрать не может.
Я бы еще в статье упомянул https://ru.wikipedia.org/wiki/Сервис-ориентированная_архитектура вот это. На мой взгляд это завязано темой.
Это как раз тот самый модульный подход в общем случае.
Извините, может, я невнимательно прочитал или просто не понял. А модули разве не обладают теми же недостатками, что и микросервисы?
Ну, например, те же зависимости - в js, хотя бы.
Модули и микросервисы отличаются одной вещью точно - микросервисы вынуждены общаться по сети со всеми вытекающими, а модули нет.
Ещё микросервисы обычно имеют независимый релизный цикл, а модули могут релизиться все вместе.
Так что нельзя прямо сказать, что они обладают одинаковым набором недостатков. Хотя часть недостатков совпадает, потому что микросервисы - это тоже модули.
Зависимости действительно могут быть неприятной штукой. Но если вы не разбиваете на модули и просто имеете одну общую солянку с кодом, то зависимости никуда не деваются, они всё там же, просто вы их не видите.
Наверно всё же микросервис это изолированная часть бизнес логики которая реализует некий публичный контракт для взаимодействия с другими частями системы. По сути приставка "микро" определяет объём реализуемого контракта. Степень изолированности это условность, которая может быть выполнена как на уровне датацентров так и внутри одного процесса и она определяет механизмы взаимодействия между частями системы (по сети или как то иначе)
в js, хотя бы
В любом языке с динамической (а тем более слабой) типизацией - да. А в языке с типизацией уровня хотя бы Java/Go - во многих случах проблемы с зависимостями детектируются заметно быстрее (в худшем случае - во время сборки перед деплоем), а соответственно, и правятся проще.
Вот бы и тот, с кем мне ещё работать, тоже эту статью прочитал!
Бывало пару раз... идёшь на проект, спрашиваешь о нюансах архитектуры, а тебе - микросервис. Приходишь, начинаешь работать, а там монолит с модулями...просто почему-то пиэм вообще не в курсе разницы. Для него монолит - это как лендинг. Если есть модули, знач, уже микросервис. Я не разработчик, но мне как-то немножко обидно было))))
Мне про противостояние монолитов и микросервисов ещё никто так круто не рассказывал. Мне - потому что стиль публикации,хоть вы и указали на упрощеность языка, очень толковый. Создаёт ощущение разговора один на один. Точнее - вы говорите, а я смотрю и слушаю. Очарована и почти влюблена.
Довольно обширно расписано, спасибо за проделанную работу. Интересно было почитать! Заметен опыт практики в вопросах применения разных подходов.
hibernate ORM, который в фоне заваливает базу миллионом ненужных вам запросов
Непонятно, за что гибернейту досталось. Он же не AI, он сам запросы не выдумывает. Если у вас миллион запросов в фоне от гибернейта, значит где-то миллион запросов в фоне к гибернейту.
Я так понял речь о том, что хватило 10 запросов, а ORM по какой-то причине делает 30. И мы этого не видим. Правда мы этого не видим и когда руками запросы делаем. Кто может поручиться, что у него точно нигде нет N+1 запроса?
У меня много вопросов к гибернейту. Например, почему eager/lazy указываются в модели, когда мне для решения вот этого N+1 надо пару раз eager, а потом мне не надо лишний джоин. Почему нельзя было ситуативный выбор сделать, как в EF? Или почему нельзя в полях одновременно получать сам объект и его ID. ID же лежит в колонке, вот он. Ан нет, либо крестик, либо трусы.
Там ещё заморочка была с композитными ключами, сейчас не помню...
Много вопросов, много. Но как-то цепляет, когда его обвиняют в самостоятельной генерации спами в БД.
Нууу... и да, и нет. Запросы он всё-таки генерирует сам под капотом. Например, мы в коде пишем post.getComments().get(1), а в фоне у нас генерируется и выполняется запрос в БД на получение первого коммента.
Конечно же hibernate не виноват, что всё в итоге тормозит. Но имеем что имеем, иногда чтобы исправить такие проблемы, приходится в сервисе вообще всё взаимодействие с БД рефакторить.
Опять же, нужны знания, чтобы эффективно пользоваться инструментом, и не пользоваться им там, где не надо. Я на собесах бывает спрашиваю, где hibernate использовать не стоит, и очень редко люди это понимают.
То есть претензия к тому, что гибернейт выполняет запрос в БД, когда вам нужны данные из БД?
Или к тому, что слишком сильно упрощается доступ к БД и котята не понимают, что они лезут в базу, а не в прощающий всё List<T>? Так вроде ORM для этого и нужен.
В 2024 году актуальный вопрос это на кой его вообще хоть где-то использовать.
А что его нишу сейчас заняло?
Spring Data JPA же на нём работает, и спринг сейчас очень много где.
Не сказал бы, что прям кто-то занял. В вакансиях хибера полно. Просто это артефакт из времен, когда модно было оверинжинирить. Его авторы пляшут от предположения, что разработчик боится SQL. Чтобы спасти несчастного, они накурили оверхед. А потом Pivotal еще сверху своей спринговой черной магии бахнули. А я в общем-то не боюсь SQL. Мне нравится самому писать запросы и думать над их оптимизацией.
В общем случае для своего условного нового сервиса я возьму JOOQ. Если много аналитических запросов, то MyBatis. Если упарываться по Kotlin, то можно Exposed попробовать. Нафига мне эти хибер и спринг дата, я просто не знаю.
Так жук это тот же самый ORM. У него есть свой собственный язык запросов, который транслируется в SQL. И точно также он не покрывает все нюансы SQL и точно также не должен. Фрукт-фрукт.
Про MyBatis уже был спор с кем-то. Утверждали, что он не ORM. Ну да, он просто маппер.
Нафига вам спринг дата я не знаю. Она и мне, если честно не нужна, вместе с жавой. Шарп как-то вкуснее мне оказался. Но то, что есть большая проблема управления сложностью в больших проектах - это факт. Внедрение ORM хорошо помогает с ней справиться, отделяя слой работы с БД от бизнес-логики. Для меня ещё очень важно, что полностью исключаются ошибки маппинга.
Если он сам разбирается в связях 1:М или M:M, он таки выдумывает запросы, что бы это ни значило. Просто его API - он не настолько гибкий (ну если не считать написания SQL самому) чтобы он их выдумал не просто правильно, но и всегда эффективно.
Так задача ORM - это маппинг сущностей в первую очередь. Если вы ожидаете от него покрытие всех возможностей генерации SQL, то зря. ORM вообще не про это. В моей ORM вообще можно было через LINQ генерить запросы, а если мало - пиши ручками SQL, орм просто замапит результат.
В типах связей ORM обычно разбирается. Тут нет ничего сложного - есть PK, есть FK на другую сущность. Обычно из этой информации следует единственно возможный вариант джойна.
ORM хорош для 95% запросов, где дальше джойна и простого WHERE ничего не надо. То, что остальные 5% запросов больно делать через ORM не значит, что ORM не нужен
Так я не говорил, что он не нужен. У меня были проекты, где я его использовал, и были где писали на голом SQL, и вообще ничего никуда не мапили.
есть PK, есть FK на другую сущность
Ну к сожалению не всегда. Видел кучку проектов, где не было ни FK (что еще бы ладно), ни даже PK.
ни даже PK
Я вызываю полицию!
ну это уже зря. Хотя это и странно, но бывают например таблицы, где хранятся просто логи. последовательность у них есть, а вот ключа нет. Это правда странно, работа с ними очень специфична, и я бы может быть сгенерировал бы длинный целочисленный ключ - но эти таблицы что мне попадались, при этом были еще и огромные. Так что создавать большущий индекс тоже не очень хочется.
Не, не зря. В спецификации той же MySql написано, что корректная работа без PK не гарантируется. Подозреваю, что у всех остальных так же.
Логи записывать в БД - это ещё один повод вызвать полицию. Вот зачем? Есть же тот же самый NLog и ещё куча решений. Выборка логов нужна примерно раз в никогда лет. Ротация нужна по переполнению. БД это тупо не умеет. В файловых логах это мало того, что проще, так ещё и меньше диска занимает и можно выделить хранилище как раз для данных такого рода ценности.
Создавая таблицу без ключа, люди ставят под сомнение сам факт, что тут нужна реляционная система хранения данных. Ну действительно. Нет ключа - нет реляционности. Нет апдейта, нет делита, просто потому, что не за что зацепиться.
Нет апдейта, нет делита, просто потому, что не за что зацепиться.
Ну я же вроде ясно написал - логи аудита (или не написал что аудит?). То что у вас в аудите нет удаления и обновления - это плюс, а не минус. Ибо нефиг обновлять документ.
Ротация нужна по переполнению. БД это тупо не умеет.
Все практические случаи что я видел, были партиционированы. Это в общем все, что от них как правило нужно (храним N лет по требованиям регулятора, через год сбрасываем на ленту партиции, и все). И это были ораклы и MS SQL, так что две эти СУБД вполне нормально работают с такими таблицами (объемы - терабайты). MySQL же в моем мире встречался один раз, и я бы сказал, что многовато у него своей специфики, чтобы считать его эталоном.
Ну то есть, я в целом скорее согласен, что решение странное (практически по всем пунктам вашего списка), но так как оно никогда не было мое - мне остается только считать его странным, не более того. И да, мне такие таблицы встречаются хорошо если одна на 10000 обычных, а у меня чужих СУБД для интеграции сотни.
Редко в наше время статья попадает в раздел "здравый смысл". Эта точно попала. Спасибо автору!
Микросервисы это по определению - архитектурный паттерн распределенного приложения.
И да, что часто забывают это то, что "распределенное приложение" это всегда сложно.
Независимо от того микросервисы это или какие-нить CORBА/RPC/SOAP или еще что там у нас в прошлом было модно.
Это все уже давно не новый опыт и всегда одни и те же трудности: отладка, логи, сложный рефакторинг, многошаговые транзакции, производительность, сеть и трафик и т.д. и т.п. Специфические засады поджидают где угодно и часто бывают крайне сложно уловимы.
Здравый смысл подсказывает, что во весь этот ад лезть изначально и по умолчанию - такая себе идея. Нужно хорошо осознавать что полученные преимущества в конкретной ситуации перевешивают радикально возросшую техническую сложность.
p.s. Собственно даже евангелисты типа Фаулера давно говорят что начинать прям с микросервисов не надо: Monolith First типа...
Да, прямо сегодня трогаю монолит (возрастом более пятнадцати лет наверное по грубым оценкам), и таки да, он ужасен.
Яркая иллюстрация того как слово "говнокод" зачем то заменяют на "монолит"
Там всё несколько сложнее. Но объяснять по-нормальному долго, скучно, и наверняка нарушит NDA.
Таки с кодом там тоже проблемы, но это не главное, они менее критичны. Я про архитектуру.
Волшебной таблетки не существует, просто взять и сделать как надо за пару дней всё равно невозможно. Дешевле (и менее рискованно) аккуратно трогать этот монолит палочкой. =) И аккуратно распиливать частями.
Классная статья. Покуда команда работает на одном языке модули/библиотеки+моно-репка рвут микросервисы. Просто потому что необходимость коммуникации между ними по сети отпадает. Однажды кто-то это окрестил термином "Квантовый-сервис" (Моно-репа, в которой все технологические вещи выпилены в свои собственные бибилотеки/компоненты, то есть что мы делаем отделено от того как мы это делаем. А сверху это всё рождает столько единиц деплоя, сколько хочется, обычно разделение по DDD или как то ещё чтобы на уровне API были чёткие границы ответственности). Но термин так и не прижился.
Если спросить разработчика на интервью, кто такие эти ваши микросервисы, и нафига козе баян, то ответы будут однообразные и грустненькие.
Дык а в итоге, какой ответ был бы красивым и правильным? Растекание мыслью по древу, что "it depends, разбираться в задачах надо...῞?
Да, справедливо замечено.
Для меня красивый и правильный ответ - это иметь собственное понимание, а не слепо повторять какие-то услышанные фразы.
То есть, даже если я сейчас напишу красивый ответ и вы его повторите мне на собесе, я всё равно буду недоволен, хотя возможно чуть меньше - когда человек повторяет не супер-странные тезисы, а что-то имеющее отношение к действительности, то это уже чуть лучше, хоть и не сильно. Как я это проверяю? Всё просто: я спрашиваю вопросы "а почему так?", "а когда эта штука может пригодиться?", "а когда так делать не надо?". Потому что это как раз важно, когда принимаешь решения в работе. И нагуглить такое в моменте обычно непросто, когда это нужно. Нужно заранее потратить время, чтобы разобраться в инструменте.
Я не считаю, что знаю всё. У других людей может быть другой опыт. Я открыт его принять, если он есть и не совпадает с моим.
Но что я хожу вокруг да около, на такой вопрос я бы ответил коротко так:
Микросервисы - это такой архитектурный стиль, в котором мы разбиваем нашу доменную и техническую логику на довольно мелкие модули, каждый модуль имеет свою осмысленную ответственность и выносится в отдельный сервис. Сервисы инкапсулируют свою внутреннюю реализацию и общаются через выставленный API. По классике это JSON over HTTP, но сейчас это целое поле разных вариантов, синхронных и асинхронных. При этом каждый микросервис является самодостаточным - он разрабатывается, релизится и эксплуатируется как отдельная независимая единица. Микросервисные системы являются распределёнными, и каждый микросервис реализован с пониманием, что его зависимости могут быть периодически недоступны, а данные могут быть неконсистентны.
Нафига оно надо? Главная причина для многих компаний - чтобы эффективно строить разработку с большим количеством команд, при этом имея хорошую скорость поставки изменений. Если у вас 2-3 команды, вам это будет не так инетерсно, если 10 - то уже очень вероятно.
И в целом возможность эксплуатировать микросервисы независимо друг от друга даёт много профита в прозрачности эксплуатации - можно предъявить к сервисам разные требования по SLA, защите персональных данных, отдельно бэкапить данные, тестить нагрузку, собирать логи, обвешивать мониторингом и алертингом.
Третья причина, она важна не так часто как первая, но если у вас сложная разнообразная нагрузка, то легче подстроить микросервисы под профиль этой нагрузки, и в тех местах, где у вас хайлоад, потратить больше денег на более дорогих программистов и другие фреймворки и подходы.
Но я предлагаю смотреть на вопрос шире, и понимать, что микросервисы - это только одна из возможных конфигураций, мы можем X модулей разрабатывать в Y репозиториях и деплоить в Z артефактов в зависимости от нашей потребности, такой взгляд позволяет нам более точно соответствовать требованиям в разных плоскостях.
Самое главное, что я могу пояснить за базар и в каждый вопрос углубиться, объяснить почему так.
Дальше можно разбирать ещё разные плюсы и минусы, их не меньше десятка. Просто для большинства бизнесов они не так важны, сами бизнесы же разные, и какие-то могут получить нехилый бенефит от какой-то особенности микросервисов. Но большинству интересны вот эти 3 - возможность подружить команды разработки между собой, эксплуатировать системы независимо с разными требованиями, и разрабатывать под разную нагрузку.
Лет 8 работал с IBM iSeries (AS400, System I). И был там у нас монолит.
Но, ИМХО, монолит частично «здорового» человека: там ось обмазана фиксированным ABI, поэтому из программы на одном любом языке ты непосредственно без плясок вызываешь программу на другом (если нужно).
Разные модули — наборы текстовых файликов, которые компилируется независимо друг от друга. Что-то где-то поменял, и если внешний API не меняется, то просто перекомпилируешь — и всё.
А чтобы типы не ползли, есть конструкция like
— сделай переменную того же типа, что и другая.
Вот этой мега-компиляции проектов на java, C++, rust там просто нет. Но правда другие, свои, проблемы и сложности есть :)
наверное можно добавить еще парочку измерений до полного хаоса: облака и кубернетес
Вы знаете, ужасные монолиты таки наверное существовали. Скажем, возьмем то, что называлось J2EE. Вот где-то до версии 3 создание модулей в этом фреймворке было сделано ужасно неудобно. Но даже в этом случае модули все равно всегда были, их можно было по отдельности деплоить, обновляя часть функциональности, запускать и останавливать.
Ну т.е. я могу в принципе представить, что кто-то, кто застал это краешком, считает что это и есть монолит, и что монолит это что-то ужасное. В то время как уже году к 2005 появились фрейморки и другие инструменты, которые сняли лишнюю когнитивную нагрузку с разработчиков, и модули стало писать если не совсем легко, то хоть быстро.
Ну холивар о том что лучше - монолиты или микросервисы - и правда давно прошел. Однако эти три пункта о чем думает индустрия сейчас - модули/репы/артефакты - полный баян. Индустрия всегда думала о таких вещах, это просто дизайн и архитектура проектов и физическая/логическая организация кода. Все это всегда имело место с тех пор, как зародилась разработка ПО как индустрия.
Берите мегатрон, там все, о чем вы говорите, уже есть. Быстрее нгинкса на пару процентов, быстрее усервера в 17 раз. Eсть даже телнет, парой строчек можете организовать консоль управления процессом.
https://github.com/akakist/megatron
крошка сын к отцу пришёл и спросила кроха
а что такое монолит и что такое плохо
если поц пришел в проект и увидел овнокод
умный в гору не пойдет, умный модуля найдет
....
а из нашего окна, роль у модуля видна
я из нашего окошка, только легаси немножко
...
если дорого и тесно, надо как то утрястись, будет вместе ...
Я бы добавил ещё одно измерение на месте автора - вопрос изоляции (корутина, поток, процесс, контейнер, ...). Но тогда статья была бы гораздо больше :)
Заканчиваю курсы по Веб-программированию, пишу итоговую работу. Читал статью как-будто на китайском, вообще ничего не понял. Нас чему-то не тому учат?
Просто не всё сразу, я только лет 5 поработав стал этими темами интересоваться. Ни в какие курсы и вузы не впихнуть те знания, до которых доходишь, набираясь опыта и экспертизы.
Если "веб-программирование" = "программирование для браузера", то это нормально. Вопрос архитектурного разбиения всё-таки больше бэкэндовый. Ну и да, согласен с комментатором выше, микросервисы - это в целом продвинутая тема, большинству проектов (и, как следствие, большинству разработчиков) они не особо-то и нужны.
У вас там микро-фронтенды должны были упомянуть )))
В вебе (фронтэндех) этого почти не нужно. А вот в бэкенде в полный рост встаёт и знание врхитектур, и структура данных, solid и прочие штучки. Но вы не переживайте -на фронтэндеров и мобильщиков сильно больше спрос. По прежнему сайты и мобилу нужны многим - от банкиров до тндивидуальщиуов по ногтевому сервису. И там это хайлрадовские навороты встречаются крайне редко. А бекенды можно и уже готовые брать и подключаться к ним по API
Еще есть зависимость от размера организации, точнее штата инженеров. Если у нас, допустим, 1000 инженеров, то им будет проще работать с микросервисной архитектурой, когда по одному нажатию кнопки ты можешь создать новый репозиторий, БД, конфиги деплоя на dev и prod, чтобы быстро начать писать код, деплоить и тестировать гипотезы уже сегодня, а не завтра, когда пайплайны в монорепе аккуратно поправят, чтобы не было
И ещё чтобы всё это не толкалось между собой и билды не занимали несколько часов из-за простоя в очереди.
С посылом согласен. Только хочу заметить, то что у разработчиков каша в голове - это еще половина беды. Настоящая беда - это каша в голове у архитекторов и IT руководителей. Которые и принимают ничем не мотивированные решения "пилить монолит", потому что это модно.
Как по мне - самое сложное это понять что есть модуль, какого он размера, и сделать так что б он был независим от других частей программы.
много лет висит как фон десктопа/зума
И тут 1Сники с 5 годами опыта - всегда разрабатывали в монолитах
Отличная статья ! И без воды. Но представляю как сейчас пукан порвет у всякого рода менеджеров продукта, проекта и самоназванных сениоров , сколотивших на этом хайпе бабки. Именно так, поэтому считаю что проблемой № 1 в микросервисах что эта обычная в общем то технология написания распределенных систем заинтересовала инвестиционных банкиров, которые решили на этом погреть руки. И разогнали огромный пузырь ожиданий. Цена продуктов стала не соответствовать их полезности, но в отрасль за дурными деньгами полезли сотни тысяч охотников за удачей. Но надо понимать - что в любой "золотой лихорадке" не столько искатели золота обогащались, как продавцы "тайных карт сокровиш", продавцы лопаток, владельцы салунов с виски, казино, блекджеком и шлюхами..
Микросервисы в представлении среднего разработчика, и как всё на самом деле