Почему мне нравятся эти шаблоны проектирования

Поработав некоторое время с Node.js, я пришел к выводу, что лучшего инструмента для написания микросервисов нет. Конечно, это мое мнение, полностью основанное на моем предпочтении JavaScript как языка. Но послушайте, даже если я не навязываю вам свое мнение, держу пари, вы не можете сказать, что Node.js - не лучший инструмент для создания микросервисов.

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

И хотя Node.js сам по себе является отличным инструментом, он будет зависеть от того, как вы в конечном итоге его используете. Имея это в виду, вот несколько полезных и интересных шаблонов проектирования для ваших микросервисов. Идея в том, что вы перестаете создавать единую службу для всех своих проектов, есть много способов разделить их в зависимости от типа выгоды, которую вы хотите получить. Итак, давайте взглянем на них.

Шаблон агрегатора

Основная идея этого шаблона - создать сервис на основе других, второстепенных и индивидуальных сервисов. Служба агрегатора - это служба, предоставляющая общий общедоступный API, который используется клиентами.

У него будет только необходимая логика, необходимая для использования всех других сервисов, которые, в свою очередь, будут иметь самую высокую нагрузку на бизнес-логику.

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

Такой подход дает несколько преимуществ:

  1. Расширять архитектуру проще и прозрачнее для конечного клиента. В конце концов, API никогда не изменится, и если он изменится, нужно будет настроить только один URL. Однако в фоновом режиме вы можете добавлять, удалять или любую комбинацию того и другого столько, сколько захотите. Фактически, если вы не меняете общедоступный API, вы можете настраивать внутреннюю архитектуру сколько угодно, не затрагивая своих клиентов.
  2. Безопасность, как правило, проще. Основное внимание во всех ваших усилиях по обеспечению безопасности на основе API должно быть направлено на общедоступный API. Остальные могут находиться за VPN, доступной только агрегатору. Это значительно упрощает взаимодействие между API.
  3. Вы можете масштабировать эти микросервисы по отдельности. Измеряя использование ресурсов, вы можете определить, какие из них больше всего затронуты текущей рабочей нагрузкой, и создать больше ее копий. Затем поместите их всех за балансировщик нагрузки и убедитесь, что каждый, кто взаимодействует с этой службой, попадает в балансировщик нагрузки. Пока вы сохраняете свои сервисы без состояния (например, если бы вы использовали REST), механика связи не пострадает.

Такие небольшие микросервисы могут быть построены, например, на основе Restify, который предоставляет все необходимое для создания микросервиса REST. Он отлично работает, а его API очень похож на API Express, который также является очень хорошо известным и простым в использовании фреймворком, который можно использовать для создания этих сервисов.

Цепочка ответственности

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

Основное отличие здесь в том, что ваша бизнес-логика - по какой-то божественной причине - требует, чтобы вы последовательно связали несколько сервисов вместе. Это означает, что для взаимодействия Client-Main API запрос должен перейти от Main API к Service 1, затем от Service 1 к Service 2, от Service 2 к Service 3, затем он должен начать заново с Service 3. к Сервису 4 только для Сервиса 4, чтобы предоставить фактический ответ, который, в свою очередь, вернет сервис за сервисом на весь путь к основному API.

Объяснять долго, но выполнять - НАМНОГО дольше. Этот тип взаимодействия не рекомендуется, если вы не измените канал связи на более гибкий. Вы можете использовать REST через HTTP для взаимодействия Client-Main API, а затем переключиться на сокеты для межсервисного взаимодействия. Таким образом, дополнительная задержка от HTTP не будет складываться при каждом запросе. У сокетов уже будут открытые и активные каналы связи между внутренними микросервисами.

Этот подход обеспечивает те же преимущества, что и предыдущий, однако у него есть один огромный недостаток: чем длиннее вы сделаете цепочку, тем больше задержки она добавит к ответу. Вот почему уверенность в том, что вы используете правильный протокол связи, имеет решающее значение для успеха этого шаблона.

Взгляните на Socket.io, если вам интересно, как управлять обменом данными между микросервисами через сокеты. Это де-факто библиотека для работы с сокетами в Node.js.

Асинхронный обмен сообщениями

Интересный способ улучшить механику схемы цепочки ответственности - сделать все это асинхронным.

Мне лично нравится этот узор. Создание архитектуры на основе микросервисов для обхода асинхронных событий может дать вам большую гибкость и повышение производительности.

Это непросто, так как общение может стать немного сложным, а проблемы с устранением неполадок еще более усложняются. Поскольку сейчас нет четкого потока данных от Сервиса 1 к Сервису 2.

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

Также обратите внимание, что моя диаграмма выше показывает, что клиент напрямую взаимодействует с очередью сообщений. Это может быть отличным решением, если вы предоставляете простой интерфейс или если ваш клиент является внутренним и управляется командой разработчиков. Однако, если это общедоступный клиент, который может кодировать кто угодно, вы можете предоставить им библиотеку, подобную SDK, которую они могут использовать для связи с вами. Абстрагирование и упрощение коммуникации поможет вам обезопасить рабочий процесс и обеспечит гораздо лучший опыт разработчика для тех, кто пытается их использовать.

Однако альтернативой может быть предоставление службы, аналогичной шлюзу, которая взаимодействует с клиентом. Таким образом, клиента беспокоит только шлюз, а все остальное для него прозрачно. Однако это не отменяет требования от клиента знать об асинхронном характере связи. Вам все еще нужно предоставить возможность подписаться на события и отправлять новые в очередь. Имейте в виду, это будет через шлюз, но это все равно должно произойти.

Основные преимущества такого подхода:

  • Намного более быстрое время отклика. Связь открывается с начальной подпиской на события, а затем каждый последующий запрос запускается и забывает. Это означает, что ему не нужно ждать завершения всей бизнес-логики, чтобы закрыть соединение и предоставить ответ своему пользователю. Данные поступят, как только они будут готовы, и именно так пользовательский интерфейс должен их обрабатывать.
  • Информацию труднее потерять из-за проблем со стабильностью. Если один из микросервисов не работает для других архитектур, текущие активные запросы завершатся ошибкой и вызовут потерю данных. Однако, пока очередь сообщений остается в рабочем состоянии, этот подход гарантирует, что данные не только сохраняются, но и после восстановления неисправных микросервисов ожидающие запросы могут быть завершены.
  • Намного легче масштабировать. Наличие нескольких копий одного и того же микросервиса больше не требует балансировщика нагрузки. Теперь каждая услуга становится индивидуальным потребителем / производителем, а события обрабатываются независимо.

Хорошие варианты очередей сообщений, которые отлично работают с Node.js, - это Redis и Kafka. Первый из них имеет такие функции, как Pub / Sub, уведомления о пространстве ключей и даже потоки, что делает его отличной и эффективной очередью сообщений. Мое предложение было бы:

  • Если у вас большой трафик и вы ожидаете генерировать сотни тысяч событий в минуту, то Kafka может быть лучшим вариантом.
  • В противном случае используйте Redis, он намного быстрее настраивается и обслуживается.

Конечно, если вы работаете в облачной экосистеме, обязательно проверьте облачные решения, такие как AWS SQS, которые также отлично работают и могут автоматически масштабироваться из коробки.

Автоматический выключатель

У вас когда-нибудь случался сбой в работе из-за очень нестабильной сторонней службы, которую вы используете?

Что, если бы вы могли каким-то образом определить, когда это происходит, а затем динамически обновлять внутреннюю логику? Было бы здорово, правда ?!

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

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

По сути, вы хотите иметь прокси-сервис для стороннего API. Таким образом, прокси может делать две вещи:

  1. Перенаправляйте сообщения от ваших сервисов к стороннему API.
  2. Отследить неудачный запрос. Если число превышает пороговое значение в течение заранее определенного промежутка времени, прекратите отправку запросов на некоторое время.

Когда появляется состояние ошибки, вам придется обрабатывать его, как вам нужно, в зависимости от потребностей вашей внутренней логики. Я добавил в свою диаграмму «ответ по умолчанию», предполагая, что вы можете предоставить какие-то данные по умолчанию, которые позволят потоку продолжаться, даже с базовой информацией. Но вы также можете отключить эту функцию на время или использовать по умолчанию дополнительную службу, которая предоставляет ту же информацию.

Альтернативы так же разнообразны, как и связанная с ними бизнес-логика, поэтому вы должны решить для себя, как лучше всего действовать. Этот паттерн только дает вам возможность понять, когда это произойдет, и что вы будете делать после этого, полностью зависит от вас.

Лучшая внутренняя архитектура для ваших микросервисов

Хотя на уровне макроархитектуры вышеупомянутые шаблоны отлично подходят для создания очень расширяемых и высокоэффективных архитектур, необходимо также учитывать внутреннюю структуру ваших микросервисов.

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

Все перечисленные здесь шаблоны показывают, как разбить шаблон монолита на несколько сервисов. Все мы знаем о преимуществах: это упрощает задачу работы с несколькими командами, расширение или обновление одного сервиса не должно влиять на остальные (как в случае с монолитным сервисом), а масштабирование отдельных сервисов также выполняется быстрее и проще.

Однако одновременная работа множества команд над несколькими микросервисами может стать настоящей логистической проблемой, если вы не примете необходимых мер предосторожности. По сути:

  • Не повторяйте код, старайтесь, чтобы усилия по кодированию между разными командами были как можно более однородными. Не заставляйте их изобретать колесо, когда оно уже есть у других.
  • Убедитесь, что все команды работают одинаково. Придерживайтесь единых стандартов в разных командах, чтобы им было проще делиться людьми.
  • Иметь простой механизм использования чужого кода. В соответствии с первым пунктом, должно быть очень просто использовать код другой команды, что упростит разработку и сократит время.
  • Убедитесь, что вам легко узнать, над чем работают другие. Когда несколько команд работают параллельно, делиться своей работой друг с другом, чтобы облегчить повторное использование, нетривиально. Иногда команды в конечном итоге реализуют одни и те же библиотеки просто потому, что не знают, что уже делают другие.

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

Как вы можете это спланировать?

Я предлагаю помнить об этом с первого дня, все ваши усилия должны быть направлены на то, чтобы предоставить вашим разработчикам необходимые инструменты, чтобы сделать это возможным.



Лично мне очень нравится использовать Bit (Github) для централизации всего, он позволяет:

  • Определите единую рабочую среду разработки, которую будут использовать все команды.
  • Делитесь общими модулями либо посредством стандартной установки, либо путем импорта полного исходного кода. Оба случая предоставят вам доступ к модулю, как и любая установка на основе npm, но второй также дает вам доступ к исходному коду на случай, если вы захотите расширить его и экспортировать обратно в центральный репозиторий. Это серьезное преимущество перед другими менеджерами пакетов Node.js, которые позволяют устанавливать только модули.
  • Узнайте, над чем работают другие команды, и можете ли вы повторно использовать их модули через центральную торговую площадку, которая может быть как общедоступной (если вы надеетесь открыть исходный код работы своей компании), так и частной, предоставляя вам точно такой же список функций. .
  • Составляйте и развертывайте микросервисы. При использовании Bit вы решаете, какие независимые компоненты являются общими и используются в микросервисах, а какие компоненты являются полноценными микросервисами, которые развертываются независимо.

С помощью Bit вы можете абстрагироваться от таких понятий, как линтер, менеджер пакетов, сборщик пакетов и другие, и сосредоточиться только на реальном рабочем процессе. Вместо того, чтобы проверять, используете ли вы npm, yarn или pnpm, просто подумайте об использовании bit install. Это устраняет разрыв между членами команды, знающими тот или иной инструмент, и стандартизирует методы работы всех команд.

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

Какие ваши любимые шаблоны микросервисов? Я их здесь прикрыл?

А как насчет внутренней архитектуры ваших микросервисов? Как вы справляетесь с работой нескольких команд, чтобы убедиться, что они не создают одни и те же общие библиотеки много раз?

Учить больше