Как стать автором
Обновить

Комментарии 24

Поставил плюс за основательную статью.

Но из самой статьи не понятен профит разбивания коризны/каталога/шины событий на микросервисы. Будущие проблемы видны, выгоды не видны.

Очевидно, что разбивание было показано исключительно в познавательных целях. Разве что в будущем эти сервисы будут весьма толстыми, и на каждом будет сидеть своя команда, но это дискутируемо.

Например один общий микросервис корзины используют приложения на ios, android и сайт
Сегодня статья была про 6 грехов программиста, вот у вас тут как минимум 2 — оверинжиниринг и велосипед. Велосипед потому, что вы игнорируете общепринятые стандартные фреймворки для микросервисов: OpenApi для веб и grpc для внутреннего взаимодействия. Они обеспечивают валидацию, транспорт и документирование апи, создают из декларативного описания сервисов код клиента и заглушки для конечных точек (grpc к тому же обеспечивает двунаправленный стриминг) — всё это в вашем случае придётся выполнять вручную. И вы блин такое рекомендуете другим? не смешите. У вас всё взаимодействие сервисов сводится к редиректу запроса — вы серьёзно считаете, что это исчерпывающий кейс?

Кроме того, ваши измышления противоречат 12 factor apps в части логгирования. К вашему сведению, логи пишутся в консоль и никуда более, и далее транслируются в систему типа ELC. Иные решения, в стиле вашего ActivityLogger — грех.
Очевидно, Вы невнимательно прочитали статью. Я ни в коем случае не игнорирую общепринятые фреймворки, по крайней мере OpenApi упомянут, и я с ним немало работал. Мне очень нравится swagger, но не нравится идея генерировать «болванку» для сервиса на основе yml и клиента как отдельную сборку. Предлагаемое в статье решение — просто альтернатива, и разумеется не панацея. Хорошо подходит для web-приложений, где нужно предоставлять большое количество разнородных и часто меняющих структуру данных.
И насчет логирования (пишется с одним «г» :-). Я прекрасно знаю как логируются данные и что такое ELK (не ELC). Сервис ActivityLogger — не более чем пример опроса событий. Если Вы знакомы с упоминаемой книгой Хорсдала, Вы поймете, почему я привел именно этот пример.
«OpenApi упомянут» — не нашёл. Поиск по тексту в браузере ctrl+F «OpenApi» «Open Api» «swagger» и «сваггер» так же не дал результатов.

«не нравится идея генерировать «болванку» для сервиса на основе yml и клиента как отдельную сборку» — хотелось бы аргументов

«Хорошо подходит для web-приложений, где нужно предоставлять большое количество разнородных и часто меняющих структуру данных» — чем же для этого плох сваггер? Он как бы считается пром стандартом, и структур данных в спеке можно много наобъявлять, и менять их легко. Но в отличие от вашего решения сваггер унифицирует апи и предоставляет бесплатно транспорт, валидацию и документацию.

«Если Вы знакомы с упоминаемой книгой Хорсдала, Вы поймете, почему я привел именно этот пример.» — знаком. Но там имхо существует путаница между журналированием и логированием (да, спасибо за поправку). Если ваш мета сервис именно _журналирует_, то вопросов нет. Но у вас же сервис назван Logger-ом — логично предположить из названия, что он «логирует»

Кроме того остался вопрос межсервисной коммуникации — как в вашей архитектуре её осуществлять, вручную? но это не правильно.

«OpenApi упомянут» — не нашёл. Да, видимо ошибся в именовании, уже исправил.

И насчет сваггера — я не говорю что он плох. Но давайте рассмотрим процесс разработки чего-то (назовем Service) с использованием OpenApi:
1. Описать структуру сервиса и моделей данных.
2. Сгенерировать ServiceApi, реализовать в нем нужную функциональность (лучше конечно функциональность вынести в отдельный сервис и внедрить его в ServiceApi как зависимость)
3. Сгенерировать ServiceApiClient.
4. Сконфигурировать использование ServiceApiClient во всех нужных местах приложения.
5. Если планируем обращаться к ServiceApi из UI, то нужно либо как-то передать в UI конфигурации конечных точек, либо организовать редиректы, сконфигурировать CORS и т.д.

Хотя признаю, бесплатное, из коробки, документирование, валидация и другие плюшки это приятно :-)

Теперь с использованием описанного в статье подхода:
1. Разработать интерфейс IService
2. В микросервисе разработать реализацию этого сервиса и опубликовать как конечную точку (пара строк в Setup)
3. Зарегистрировать IService как зависимость во всех нужных местах и использовать ее привычным образом (в общем-то для ServiceApiClient нужно сделать ровно то же самое, но в отличие от OpenApi мы можем все интерфейсы собрать в одну сборку)
4. Ну с собственно редиректы на микросервисы из главного приложения (если нужно).

Наше приложение Microcommerce с использованием OpenApi получается несколько более громоздким, не так ли?
Разработать интерфейс IService
Зарегистрировать IService как зависимость во всех нужных местах и использовать ее привычным образом


Тут на сцену выходит .NET Remoting, оказывается MS уже в 2000 году придумала фреймворк для микросервисов в внедрила его в рантайм .NET по самые помидоры.

Ох, история развития ПО действительно идёт по спирали.
оказывается MS уже в 2000 году придумала фреймворк для микросервисов — .NET Remoting в то время позиционировался как средство междоменного взаимодействия, но по сути это то же самое. Но собственно идея генерировать прокси по интерфейсу не так уж плоха, я бы даже сказал весьма продуктивна. Главное — чтобы это было просто и гибко. Согласитесь, это гораздо менее трудоемко, чем расписать структуру в yml, сгенерировать по ней заготовку сервиса и клиента, наполнить сервис функционалом и т.д.
Так ведь нет, не получается.

Разрабатывать интерфейс IService не нужно, он генерируется из спеки и является своего рода низкоуровневой деталью реализации апи, используемой фреймворком.

Публиковать реализацию так же не нужно, она сама «публикуется».

ServiceApi и ServiceApiClient генерирует тулза — бесплатно, для этого не нужно прилагать умственных усилий. Вся конфигурация сервера сводится к запуску хттп листенера с указанием урла и прописывания миделварей точно так же как у вас (CORS и т.п ), ни какие редиректы не нужны. Банально прописывается реализация для сгенерированных заглушек и всё. При этом архитектура самого сервера не завязана на DI, а доменную модель можно делать как вам больше нравится — на DI или глобальных переменных или как-то ещё.

Что касается клиента, то ServiceApiClient на C# в данном случае (я пишу на другом ЯП, раньше писал на C#) нужен исключительно для интеграционных и функциональных тестов на апи. И его конфигурация так же сводится к указанию корневого урла сервера.

Далее, если мы не планируем обращаться к ServiceApi из веб приложения браузера, а планируем его юзать из внутренних сервисов, мобильных клиентов и, например, дектопа — то нам нужен не сваггер, а grpc как более универсальная, мощная, надёжная и простая технология. Сваггер — только для веба.

Конкретно для веба генерируется fetch-клиент и типы структур данных сервиса на typescript. Поэтому фронтенд программисту не нужно думать о конечных точках, обработке ошибок хттп и т.п. вещам касательно транспорта. Он получает полностью типизированный и рабочий апи, сгенерированный из спеки OpenApi, так же как и ServiceApiClient для тестов — ServiceApiClient.Foo(Bar). Фронтенд программист так же участвует в разработке спеки, внося в неё требуемые ему фичи. В вашем же случае типизация апи на стороне клиента и транспорт делаются вручную и поддерживаются в актуальном состоянии через боль и слёзы.

В вашем же случае типизация апи на стороне клиента и транспорт делаются вручную и поддерживаются в актуальном состоянии через боль и слёзы.

Ну на самом деле не все так печально с типизацией на стороне клиента
habr.com/ru/post/266899
Это не слишком впечатляет, поскольку фронтенд программисту всё ещё нужен готовый вызов сервиса с актуальными эндпойнтами, валидацией и обработкой ошибок хттп. А не только серверные структуры данных.

Вы попробуйте всё же в rpc фреймворки — сразу оцените насколько они упрощают жизнь

вы просто взрыв из прошлого, удивлен что не вспомнили генерации прокси из webservice в VS2008

OpenApi, в 2015 появившаяся в виде стандарта — взрыв из прошлого, а писать всё руками — модно и современно? ну ну

Вы забыли упомянуть про WCF — какое это старое г-но. grpc делает в сущности примерно то же самое и поэтому не нужен по вашей логике
На проекте которым я сейчас занимаюсь более 200 рабочих сервисов. Они одинаковые, но каждый занимается обработкой своей группы данных. Так как это все крутится на выделенных серверах, иногда возникает ситуация когда некоторые сервисы сгруппированные на одном сервере необходимо перемещать на менее загруженные сервера или резервный сервер. Ситуация редкая но встречается.

Есть ситуация когда управляющий сервис, а с ним общается вся пачка из 200-т воркеров на постоянной основе, надо обновлять не останавливая работу. Мы поднимаем обновленный сервис и переводим на него работу всех воркеров.

Таже самая ситуация в обратную сторону, при переносе сервиса-воркера на другой сервер или виртуалку сервисы работающие с фермой должны отслеживать их перемещение. Если это один сервис, то еще ничего, а если их десяток?

У вас есть N ДЦ, в которых подняты идентичные системы, но обслуживают разные регионы. Например Европа-США-Азия, очень распространенный вариант размещения для увеличения отзывчивости. Предположим падает сервис или хостер уронил виртуалку или произошел непредвиденный сбой. Самый простой способ чтоб на время сбоя сервисы поднятые в других ДЦ перехватили работу павшего собрата, до момента его подъема.

А как Вы решаете проблему передачи данных на несколько сервисов, со сложным роутингом, размещением сервисов в региональных ДЦ? В случае постройки работы проекта на WebApi разворот потоков данных фермы достаточно не простая задача.
Для такой системы взаимодействие через WebApi плохо подходит. В такой архитектуре нужно заботиться о предоставлении конфигураций каждому микросервису, плюс к тому же нужно как-то решать вопрос балансировки нагрузки.

Мне кажется в вашем случае нужна звездообразная архитектура. Как вариант — использование какого-либо MQ-сервера, RabbitMq или ApachMq. Я разрабатывал подобные системы взаимодействия приложений, и даже есть Nuget-пакет для этого, хоть меня и критикуют за велосипеды :-). Если Вам интересно — пишите в личку, я поделюсь наработками.
Поэтому и спросил как Вы решаете подобный вопрос используя WebApi. В частности я для данной задачи использую NATS, он подошел лучше всего по производительности.
Опыта использования NATS у меня нет. Я немного почитал доки по Вашей ссылке, насколько я понял это message oriented система. Собственно, MQ-сервисы тоже из этой линейки, и да, я абсолютно согласен что такое решение хорошо решает проблему балансировки нагрузки.
Получается микросервисы завязаны на один общий пакет но при этом общаются между собой через http? А подход с API Gateway чем не устроил?
Эта статья — дополнение к книге Хорсдала, упомянутой во введении. Рассмотрен единственный вопрос — упрощение разработки микросервисов. В книге описывается использование Nancy, я предлагаю альтернативный подход, позволяющий оставить вопросы предоставления конечных точек, генерирования web-клиентов, переадресации «под капотом».

Мне иетересно, пробовали ли вы Microsoft Orleans? Как на меня отличнейшее решение для 90% случаев. Но тут я пока только как теоретик, пару раз кластер подымал — проще ничего нету.
Первое что в голову приходит


  • Строгая типизация реквестов через интерфейсы со скоростной сериализацией
  • Автоматическая балансировка вплоть до миграции воркера на другую машину с состоянием (естественно надо persistanse писать)
  • Автоматический failover
  • Поддержка кластерного singleton по умолчанию. Удобно, знеаете ли, знать что три машины не колбасят ту же задачу или данные.
  • Distributed cache в силу того что работает предыдущий пункт
  • Встроенные события/потоки/таймеры/remainders
  • Discovery

Можно еще покопать, но как на меня профит очевиден: пишите себе на чистом .NET забыв о swagger. Расслабляетесь от балансировки "микросервисов", от толпы не нужных инстансов. Не конфигурируете кеши, очереди (ну без них не всегда можно).


Сумбурно как-то так

Нет, это я не пробовал. Для балансировки нагрузки и масштабирования я имею опыт использования ApacheMq. В общем-то те же фичи что описаны Вами для Microsoft Orleans, но плюс еще кросс-платформенность
Для балансировки нагрузки и масштабирования я имею опыт использования ApacheMq

Посмотрел, что-то больно на Java мир завязано. И разве это не брокер сообщений?
Я бы его больше к этому проекту сравнивал: https://github.com/dapr/dapr


В общем-то те же фичи что описаны Вами для Microsoft Orleans, но плюс еще кросс-платформенность

.NET Core давно кросплатформенный как бы.

Это действительно брокер сообщений, но особенности amq протокола позволяют организовать весьма причудливые сценарии взаимодействия, в т.ч. обработку очереди несколькими сервисами для распараллеливания обработки.
А насчет кросс-платформенности — я имел в виду взаимодействие с приложениями на java, php и т.д. Хотя Вы правы, лучше использовать чистый .Net Core, если нет каких-то экстраординарных кейсов.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории