Comments 77
Мы, тимлиды, сначала вдвоем, потом втроем разрабатывали функционал в этой новой архитектуре.
Что-то тимлиды не своим делом у вас занимаются.
А почему надо переходить на _микро_сервисы? Неужели, обычные сервисы уже не популярны? Почему?
А если к любому другому слову добавить приставку SI, оно станет круче?… фемто-модули (hello, leftpad).… пико-скрипты. гига-sql. кило-клиент. мили-конфиг.
А если к любому другому слову добавить приставку SI, оно станет круче?… фемто-модули (hello, leftpad).… пико-скрипты. гига-sql. кило-клиент. мили-конфиг.
Нано- забыли )
А разве приложение, порезанное на несколько сервисов, нельзя масштабировать раздельно для каждого сервиса? Например, если толстый и основательный интернет-магазин состоит из 30 сервисов, то мы можем каждый из них масштабировать согласно его значимости и нагрузке, которую он создаёт.
… Просто люди привыкли использовать слово "микросервис" как синоним слова "сервис" ("давайте порежем монолит на сервис" — думают они, "давайте порежем монолит на микросервисы" — говорят они).
При этом "микросервисная архитектура" по сравнению с обычными сервисами приносит с собой такой комплект ответственности, что редкий человек её выдержит. Взять-то возьмёт, да не сдюжит.
У некоторых есть практика, что разрезая монолит на сервисы, мы получаем несколько монолитов в итоге. Сочетая все недостатки монолитов и распределеных систем.
Некоторым именно круче надо ;)
Некоторые при слове сервис сразу вспоминают SOAP и их в дрожь бросает :(
Некоторые из практических соображений выбирают именно микро — меньше длина "линии разреза", меньше внутренних вызовов рвать на внешние
Много причин, у каждого свои, даже в рамках одной команды
Вы что-то странное говорите. Чем больше у вас сервисов (а микросервисы предполагают множество их), тем больше у вас длина разреза — тем больше у вас API и сетевого взаимодействия.
Если он плохо документированный, то это уже не микросервисная архитектура. Принцип микросервисной архитектуры — фиксация проекта на уровне API компонент. Если API едет, то уже не микросервисная архитектура.
При чём тут розовые пони? Микросервисная архитектура придумывалась для того, чтобы защитить проект от говонокода. На верху сидит толковый лид, который думает архитектуру, масштабирование и т.д., он ваяяет соглашения в API, а дальше уровень говнокода за конкретным API определяется степенью важности этого API. Если это поддержка стикеров в чате, то команда набирается сильная и толковая, которая пишет хороший сервер. Если это какая-то ерунда, типа управления стержней атомного реактора, то туда можно набрать джунов и индусов. Соблюдён контракт на API? Всё хорошо, проект живёт. Какой-то микросервис стал невыносим? Его можно переписать не ломая остальные куски.
Т.е. микросервисы были придуманы для того, чтобы партиционировать техдолг.
Но… Это работает до тех пор, пока есть толковый техлид. Если джун или просто скучающий программист for fun спроектировал микросервисы, то всё, можно закапывать. Будет кратно хуже, чем в монолите, потому что теперь все ошибки проектирования будут вылазить в сетевое взаимодействие в райнтайме со всеми вытекающими.
Микросервисная архитектура придумывалась для того, чтобы защитить проект от говонокода.
Вы что-то путаете, говнокод никак не зависит от архитектуры и является следствием неопытности и неаккуратности исполнителя.
Т.е. микросервисы были придуманы для того, чтобы партиционировать техдолг.
Отчасти это верно, но микросервисы все же придуманы не для этого.
Основная задача разбивки монолита на микросервисы — уменьшение зависимостей одного компонента от других и приведение этих зависимостей в некоторый порядок. Бонусом часто идет возможность использования микросервиса в других проектах, пример — сервис авторизаций или приема платежей.
Минусом — надо управлять зависимостями, версиями микросервисов, развертыванием. Есть существенная потеря производительности.
А мужики говорят, что микросервисы придуманы для независимого деплоя и масштабирования ) Остальное бонусы
А чем это отличается от сервисов? Сервисы так же независимо деплоятся и масштабируются. "Микро"-то тут при чём?
Я ничего не путаю. Крупные проекты невозможно защитить от появления говнокода. Задачей проекта является защита от влияния говнокода на проект (почувствуйте разницу — появление и влияние). Микросервисы — один из методов защиты. Каждый страдает в своей песочнице сам в соответствии со своей компетенцией, а архитектура проекта определена на уровне сетевого API между компонентами. Пока архитектура хороша, говнокод не может влиять на проект. (Не на "как хорошо проект работает", а на проект — на то, насколько там внутри много спагетти из зависимостей и паталогических связей).
Крупные проекты невозможно защитить от появления говнокода.
Это не так, достаточно поставленного процесса Code Review. Полно достаточно крупных Open Source-проектов, грамотно сделанных.
Микросервисы — один из методов защиты.
Если большое говно разделить на кучки поменьше, то кучки по отдельности вонять будут меньше, но в целом запах не уменьшится.
Больше они вонять будут — площадь выше при том же объёме. :)
… И все эти проекты всегда предусматривают плагины, сторонние модули, или ещё какой-то метод подгрузить код не коммитя его в основной репозиторий. Это как раз и делается для "защиты от говнокода". Если какой-то плагин плохой, то это проблема плагина, а не проекта.
Если большое говно разделить на маленькие, то будет много маленьких кучек говна. А вот если бочку мёда разделить на маленькие баночки, то появление одной баночки с говном не портит остальные баночки. А если баночки хорошо закручивать, то можно сделать вид, что вообще всё замечательно.
но можно сперва большую бочку говна разделить на маленький баночки, а потом отдельно каждую баночку подменять на баночку с мёдом.
Или, отчёрпывая из большой бочки, можно рядом сразу ставить баночку с мёдом. Но, тут главное, не забывать о гигиене после того как отчерпнул из бочки и налил мёда в баночку рядом
А вот если процесс Code Review не поставлен — тогда обычно разброд и шатание, что, впрочем, не исключает какие-то грамотные места, если отдельные личности — профессионалы своего дела.
> Но сразу перейти на микросервисы получится не у всех
А монолит в каком смысле? В том, что весь код вообще в кашу или в том, что все модули в одном сервисе и в одной базе?
А нужно прямо именно на микросервисы?
Вообще в большинстве случаев, монолит лишь "все модули в одном сервисе и в одной базе", но благодаря "продавцам" микросервисов уже стойко ассоциируется с "весь код вообще в кашу", с "большой комок грязи" и т. п. С другой стороны, если продать идею микросервисов бизнесу, то можно получить ресурсы на наведение порядка в "плохом" монолите. И продать "дайте нам год и мы всё переведём на микросервисы" гораздо проще чем "дайте нам полгода и мы наведём порядок в монолите"
В нашем случае монолит — это единая кодовая база, единая БД, одна единица деплоя.
> А нужно прямо именно на микросервисы?
Об этом и был доклад, по мотивам которого вышел подкаст. Монолит автоматом стали приравнивать к «большому комку грязи». Но это совсем не означает, что так всегда. У нас, например, таковой «ком грязи» и был. Очень много зависимостей, нет четкой структуры и принципов размещения кода, бизнес логика где попало. И на самом деле нам не нужны были микросервисы, потому что нашу проблему можно было решить и без них. Да и микросервисы не являются таблеткой в этом случае. Нам не хватало структурированности, архитектуры как таковой. А вот для случая, когда мы поймем, что какой-то наш модуль требует независимого масштабирования в связи с высокой нагрузкой, например, мы подготовили рельсы.
Да никак, оно ортогонально.
А кто сказал, что они хранятся в базе так? Вполне нормальный кейс при генерации пароля отправить его, а потом захэшировать при сохранении.
я так понял, те же люди, что и Skyeng
Skysmart это наш проект, вот недавно писали, как формировалась его команда и как он помог учителям в период карантина.
Внизу данной инструкции опять плашка с данными доступа плейн текстом.
Как верно подметили, хранить и отсылать это немного о разном. На нашей стороне все пароли пользователей хранятся в виде хэша с солью, для хэширования применяем хороший алгоритм bcrypt с рекомендованным cost-ом. Но высылаем на почту мы и правда плейн-текстом: в этом сервисе у нас нет денег, карточек, возможности повлиять на оценку и пр., а учителя не регулярно забывают пароли и не всегда на ты с онлайном (прям очень советуем почитать аналитику в оригинальной статье про Skysmart).
Спасибо за ответ. Хранение пароля в виде хэша который элементарно можно реверснуть это так себе защита, не так ли? Мне, например, претит видеть свой пароль в базах перебора паролей, даже если это что-то сгенерированное. А сколько людей используют один пароль везде?.. Оригинальную статью я читал, и сервис сам по себе замечательный. Вот только снижать требования безопасности, мотивируя это ---name it--- на мой взгляд несколько странно.
Вообще, работая с микросервисами, нужно понимать, что у них есть и достоинства и цена. Причём цена высока.
Достоинства — прежде всего масштабируемость.
Плюс, какой-то компонент может быть универсальным и использоваться совершенно различными бизнес решениями. Как пример, компонент гугл-карт.
Недостатки: многократно возросшая цена поддержки, упавшая надёжность, сложность отладки. В каком-то описании про микросервисы читал, что де отладка становится легче. Ха-ха три раза. Где же легче, когда полную инфраструктуру приложения нельзя впихнуть на один комп девелопера? В одном из проектов писались здоровые методы, которые сериализовали отклики сетевых сервисов в xml и потом локально создавали моки, которые имитировали микросервисы соседей. Дофига кода обвязки, чтобы только отладиться и найти ошибку.
В общем, do it when you need it. Don't do because it is trendy, don't do just because you can.
полную инфраструктуру приложения нельзя впихнуть на один комп девелопера?
Не для всех приложений это справедливо
Кроме прочего этот подход позволяет потрогать в продуктовой среде новые технологии не перенося на них критичные для бизнеса bounded contexts и в случае успеха плавно на них мигрировать, не переписывая на них вообще всю систему за один заход.
А нам очень хотелось DDD.
Уже есть такие примеры, что, переделывая какой-то кусочек, его стараются упорядочить и интерфейсами покрыть, чтобы оно было более-менее похоже на чистую архитектуру, чтобы было проще потом вынести.
Просто интерфейсами покрыть, чтобы было похоже на «чистую архитектуру»? По-моему опыту так делать не надо, все закончится созданием кучи никому не нужных интерфейсов и только добавит акцидентальной сложности. По-моему в прикладном проекте (не в библиотеке) интерфейсы нужно делать только тогда, когда на 100% знаешь, что будет больше одной реализации. YAGNI. А так ощущение создается, что в описываемом проекте люди только открыли для себя интерфейсы и DDD и пустились применять просто потому что это «круто». Ничего, время все расставит на свои места, набьются шишки. Лучше конечно их набивать используя прототипные проекты а не основной.
Мы решили скрестить ужа с ежом и теперь живем с двумя фреймворками.
Сейчас хитрим и читаем из чужих таблиц — это допущение, которое мы пока себе позволяем в силу того, что нет времени, ресурсов, чтобы реализовать по-нормальному. Когда есть такой сложный кейс — иногда мы отходим от правил и читаем прямо из базы данных.
Сейчас в новом коде у нас 14-15 контекстов плюс большой легаси
По-моему в проекте проблем стало еще больше. О каком разделении на контексты можно говорить, если база одна?
Интересно, решили ли они делать persistence ignorance?
интерфейсы нужно делать только тогда, когда на 100% знаешь, что будет больше одной реализации.
Моки для тестов считаются реализацией?
О каком разделении на контексты можно говорить, если база одна?
В целом одна база никак не противоречит разделению на контексты. Главное, чтобы у каждой таблицы был свой владелец, который в неё пишет. Хотя, можно и до столбца гранулировать, наверное.
Моки для тестов считаются реализацией?
Нет
В целом одна база никак не противоречит разделению на контексты.
По мне так база это часть релизации контекста, сугубо внутренняя вещь. Чтение напрямую из базы минуя интерфейсы контекста приводит к нарушению принципа сокрытия информации на уровне контекстов.
Нет
Почему? На практике это чуть ли не самая частая причина введения интерфейсов. Как без них вообще мокать на языках со строго номинативной типизации? Рефлексией на каждый чих? если она вообще позволяет создавать неиницализированные инстансы в языке — не уверен, что везде это можно.
По мне так база это часть релизации контекста, сугубо внутренняя вещь. Чтение напрямую из базы минуя интерфейсы контекста приводит к нарушению принципа сокрытия информации на уровне контекстов.
С одной стороны, да. С другой, обычно всё-таки таблицы часть реализации, а то, что таблицы нескольких контекстов лежат в одной физической базе "чисто случайно" особо на логическую изоляцию не влияет. С третьей, сама база, схемы конкретных таблиц могут быть частью интерфейса. Никого же вроде особо не смущает, чтение событий одного контекста в другом. Принципиальных различий с базой не вижу, пока только чтение идёт
Почему?
Статья о проекте на PHP. То что я говорил касается PHP. Тут все прекрасно делается моками.
С третьей, сама база, схемы конкретных таблиц могут быть частью интерфейса.
Чисто теоретически. Я думаю, что в описываемом проекте такого нет. Да и вообще, я глубоко сомневаюсь, что кто-то реально будет делать БД частью интерфейса ограниченного контекста.
Какими моками? В PHP моков на уровне языка нет, есть четыре, вроде, основных способа создания моков, работающих с тайпхинтами объектов:
- имплементация интерфейса (нужен интерфейс)
- расширение класса (класс должен быть не final, мокуемый метод не должен быть final, класс не должен быть статически "прилинкован" к внешнему миру, в общем много требований к исходному классу)
- манипуляция механизмом автозагрузки, подставляя вместо оригинальной свою реализцию, совместимую с оригинальной
- вмешательство в работу zend engine
Я что-то упустил? Самый простой — первый как по мне.
Да и вообще, я глубоко сомневаюсь, что кто-то реально будет делать БД частью интерфейса ограниченного контекста.
Да делают-то сплошь и рядом, вопрос лишь в наличии и качестве документации, тестировании, процессов изменения, прямой и обратной совместимости и т. п.
вмешательство в работу zend engine
У вас чувство юмора такое? Вы же с первого раза поняли, какие моки имеются ввиду. Все что вы написали я прекрасно знаю, зачем вы всё это перечислили?
Нет, это то, что я реально применял для создания моков на абсолютно непригодной для тестирования архитектуре, как ещё замокаешь функции стандартной библиотеки? Хотя можно манипуляцией с автозагрузчиком и генерацией кода класса аналогичного исходному, но с подменой вызов стандартных функций на свои. AOP такую технику использует.
И я нахожу, что имплементация интерфейса самый простой в общем случае, особенно если приложение соблюдает ISP из SOLID — просто чтобы не реализовывать 100500 методов, в тесте не используемых.
Принципиальных различий с базой не вижу, пока только чтение идёт
События можно версионировать. Со схемой базы это не получится.
База одна, но каждый модуль «знает» только о своих таблицах. И даже в структуре проекта схемы таблиц хранятся также «помодульно». Обращение к «чужим» таблицам происходит в единичных случаях исключительно для отображения данных, никак не в бизнес логике. Это была временная мера, которую, я думаю, мы тоже со временем решим. Приведу пример, у нас есть паджинируемый, сортируемый, фильтруемый список назначений на курсы, в котором отображаются данные по пользователям и по назначениям, это разные модули. Запрашивать данные отдельно у каждого модуля, потом их объединять, сортировать, фильтровать и паджинировать в памяти очень накладно. Тут хорошо подходит CQRS, но на момент разделения на модули, у нас не было времени реализовать именно для этого списка данный подход, поэтому пока код отображения списка читает данные напрямую из таблиц.
> Интересно, решили ли они делать persistence ignorance?
У нас в большинстве модулей используется DDD, который автоматом подразумевает этот самый «persistence ignorance». И как раз интерфейсы тут в помощь.
Я такой подход так и называю CQRS, просто разделение на потоки записей и чтения на уровне бд — один модуль пишет в неё (чтение для гидрации не считается :), другой читает как ему нужно. Можно даже оформить как View или даже materialized view, но обычно овчинка выделки с поодеожкой логики на стороне sql не стоит
И еще вопрос, переисползуете ли вы написанные модули в других проектах?
Кстати кому интересно недавно опубликовал пример приложения на DDD/SQRS на симфони
это фактичеси те же (микро)сервисы, но только имеющие общую бд (может еще некоторые инфраструктурные штуки)
А почему общая бд обязательна? Никто не мешает в каждом модуле иметь свою бд, ровно так же как в микросервисах. Вообще никто не мешает писать в монолите все тоже что в микросервисах (за исключением раздельного деплоя, конечно), даже общение по Rest можно сделать в качестве резервного канала, если планируем в ближайшее будущее выделение в микросервис.
за исключением раздельного деплоя, конечно
Исключений ещё много. Например, можно разные версии зависимостей использовать, если говорить о PHP и composer, собственно и разные версии PHP.
можно разные версии зависимостей использовать, если говорить о PHP
Мир не ограничен PHP, в Java разные версии библиотек в разных модулях вполне решается штатными методами.
собственно и разные версии PHP
Ну сомнительное преимущество (головняка с подержкой разных версий много, а плюсы не очень понятны). Когда это имеет смысл?
P.S. Да у микросервисов есть еще некоторый плюс к надежности — если случится фатальная программная ошибка, вроде исчерпания памяти — у общего рантайма упадет весь монолит и что еще хуже может упасть все инстансы монолита. У микросервисов — только часть микросервисов.
Минус — если часть реально важная (вроде модуля продаж или авторизации у инет магазина), для бизнеса это не сильно лучше полного падения (смысл в интернет магазине, в котором невозможно сделать заказ?). К тому же, у микросервисов появляется точка отказа в виде ошибок в сервис локаторе, проблемах с сетью или сериализацией/десериалицией. Для монолита проблема фатальной ошибки слегка решается наличием резервных инстансов старых версий приложения, с возможностью переключения на них.
Мир не ограничен PHP
Пост о PHP приложении.
Когда это имеет смысл?
Поддержка разных версий имеет смысл, когда обновляться пора, но обновлять всё приложение разом никто ресурсов не даст. Вроде для монолитов на Java это тоже характерно — попадалась недавно статистика, из которой следует, что с использованием актуальных версиях там ещё хуже чем в PHP.
смысл в интернет магазине, в котором невозможно сделать заказ?
Бизнес, как правило, предпочитает, чтобы в интернет-магазине хотя бы каталог работал и форма обратной связи или тупо телефон показывался, когда сломались продажи, а не 500-я выдавалась на любой странице.
Пост о PHP приложении.
PHP в посте упоминается в одном предложении, я бы сказал, тут более важен сам подход, чем язык.
Поддержка разных версий имеет смысл, когда обновляться пора, но обновлять всё приложение разом никто ресурсов не дас
А переписать на микросервисы дает? Обычно переход с монолита на микросервисы практически равнозначен созданию приложения с нуля (по крайне мере, архитетуры).
Вроде для монолитов на Java это тоже характерно — попадалась недавно статистика, из которой следует, что с использованием актуальных версиях там ещё хуже чем в PHP.
Это дикое легаси, работающее по принципу «работает — не трогай». Сомневаюсь, что если бизнес боится перехода на другую версию — он даст выкинуть все и переписать на микросервисы.
Бизнес, как правило, предпочитает, чтобы в интернет-магазине
Бизнес предпочитает, чтобы все работало нормально. Тут в любом случае, нужно чинить за считанные минуты (откатываясь на прошлую версию, разворачивая резервные сервера и т.п.) и чем быстрее, тем лучше.
Плашка «у нас техническое обновление, попробуйте зайти через 15 минут» часто лучше с точки зрения оттока клиентов, чем «я нажимаю заказать, а ничего не происходит, ничего на этом глючном сайте не работает, пойду к конкурентам».
PHP в посте упоминается в одном предложении, я бы сказал, тут более важен сам подход, чем язык.
Я, видимо, слишком в контексте, с одной стороны. С другой, если в Java проблема разных зависимостей решена, то во многих языках/экосистемах — нет.
А переписать на микросервисы дает? Обычно переход с монолита на микросервисы практически равнозначен созданию приложения с нуля (по крайне мере, архитетуры).
На удивление, да. Но не на полный единоразовом переходе, а на постепенный, о выделении частей монолита в микросервисы поэтапно, в рамках решения конкретных проблем. Именно изменений в архитектуре приложения может и не быть глобальных, новые инфраструктурные элементы могут появиться.
Это дикое легаси, работающее по принципу «работает — не трогай».
Да вроде нет. Емнип, на Java 8 вполне активная разработка идёт.
он даст выкинуть все и переписать на микросервисы.
"Так ты корову не продашь" © Переписывать на микросервисы можно и нужно, если уж решили переписывать, постепенно.
Плашка «у нас техническое обновление, попробуйте зайти через 15 минут» часто лучше с точки зрения оттока клиентов, чем «я нажимаю заказать, а ничего не происходит, ничего на этом глючном сайте не работает, пойду к конкурентам».
Переход, хоть и частичный на MSA подразумевает, что вместо «у нас техническое обновление, попробуйте зайти через 15 минут» или «я нажимаю заказать, а ничего не происходит» в случае отказа сервиса продаж появляется "у нас техническое обновление, попробуйте заказать снова через 15 минут или сделайте заказ по телефону ..." только при нажатии кнопки "заказать".
Вот провели с женой выходные на паре сайтов мебельных магазинов, кнопку "заказать" ещё не нажали, если нажмём и получим ошибку, то будем искать другие способы заказать в этих магазинах. А вот были бы 500-е или "техническое обслуживание" на страницах товаров — ушли бы к конкурентам.
К какому варианту хранения микросервисов пришли в итоге? Каждый микросервис в своем репо? Или общий?
Каждый микро сервис в микро репо на микро компьютере. Микро компьютеры объединяются в микро сеть. Каждая клавиша клавиатуры имеет собственный микро сервис для обработки. Движение мыши контролируется 4 микро сервисами: влево, вправо, вперёд, назад.
Как быть, когда все советуют растащить проект на микросервисы. А ты не готов