Feathers: Микросервисы: рекомендуемый способ рефакторинга приложения путем разделения сервисов?

Созданный на 19 мая 2016  ·  27Комментарии  ·  Источник: feathersjs/feathers

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

Сервис-ориентированность: Feathers. Предоставляет вам структуру для создания сервис-ориентированных приложений с первого дня. Когда вам в конечном итоге потребуется разделить приложение на микросервисы, это будет простой переход, и ваши приложения можно безболезненно масштабировать.

Но я все еще не мог найти информацию о том, как справиться с этим вариантом использования в перьях.

С практической точки зрения, я изначально сосредотачиваюсь на двух основных темах:

  • Коммуникация: я думаю, что должен быть способ извлечь службу и позволить исходному приложению продолжать взаимодействие без необходимости больших усилий по переписыванию, например, путем замены вызовов службы HTTP-запросами.
  • Аутентификация: пояснения о том, как перья обрабатывают аутентификацию для связи между службами после разделения службы.

Заранее спасибо!

Documentation Question Scaling

Самый полезный комментарий

Вы правы, документации пока не так много, и мы недавно создали https://github.com/feathersjs/feathers/issues/157, чтобы отслеживать это. Вот некоторые из моих мыслей по двум упомянутым вами темам:

Предположим, у нас изначально есть сервер с двумя сервисами, может что-то вроде

app.use('/users', memory())
  .use('/todos', memory());

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

// server1
app.use('/users', memory());
// server2
app.use('/todos', memory());

Чтобы служба /todos теперь могла взаимодействовать с удаленной службой, мы можем использовать Feathers в качестве клиента для подключения к ней (веб-узлы быстрые и двунаправленные, так почему бы не использовать их для связи между серверами?):

// server2
const client = require('feathers/client')
const socketClient = require('feathers-socketio/client');
const io = require('socket.io-client');

const socket = io('http://other-server.com');
const otherApp = client().configure(socketClient(socket));

app.use('/todos', memory())
 .use('/users', otherApp.service('users'));

Это в основном прозрачно передает пользовательскую службу удаленной службе через соединение через веб-сокет. Все, что использует исходную конечную точку /users , ничего менять не должно.

Что касается аутентификации, есть много разных вариантов. В приведенном выше сценарии самым простым способом было бы для server1 просто внести в белый список IP-адреса других серверов, поскольку server2 по-прежнему является единственной точкой связи для клиентов. В конечном итоге server2 может просто стать шлюзом, который обрабатывает аутентификацию пользователя, а затем просто передает служебные вызовы другим серверам (которым не нужно беспокоиться об аутентификации, кроме проверки исходного IP-адреса).

Все 27 Комментарий

Вы правы, документации пока не так много, и мы недавно создали https://github.com/feathersjs/feathers/issues/157, чтобы отслеживать это. Вот некоторые из моих мыслей по двум упомянутым вами темам:

Предположим, у нас изначально есть сервер с двумя сервисами, может что-то вроде

app.use('/users', memory())
  .use('/todos', memory());

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

// server1
app.use('/users', memory());
// server2
app.use('/todos', memory());

Чтобы служба /todos теперь могла взаимодействовать с удаленной службой, мы можем использовать Feathers в качестве клиента для подключения к ней (веб-узлы быстрые и двунаправленные, так почему бы не использовать их для связи между серверами?):

// server2
const client = require('feathers/client')
const socketClient = require('feathers-socketio/client');
const io = require('socket.io-client');

const socket = io('http://other-server.com');
const otherApp = client().configure(socketClient(socket));

app.use('/todos', memory())
 .use('/users', otherApp.service('users'));

Это в основном прозрачно передает пользовательскую службу удаленной службе через соединение через веб-сокет. Все, что использует исходную конечную точку /users , ничего менять не должно.

Что касается аутентификации, есть много разных вариантов. В приведенном выше сценарии самым простым способом было бы для server1 просто внести в белый список IP-адреса других серверов, поскольку server2 по-прежнему является единственной точкой связи для клиентов. В конечном итоге server2 может просто стать шлюзом, который обрабатывает аутентификацию пользователя, а затем просто передает служебные вызовы другим серверам (которым не нужно беспокоиться об аутентификации, кроме проверки исходного IP-адреса).

Спасибо за ответ! Планируете ли вы освещать эту тему в официальных документах (возможно, в подразделе Руководств)? Сообщите мне, могу ли я внести свой вклад в этом отношении.

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

💯 @daffl - это

@daffl Подход, о котором вы упомянули, с использованием пера-клиента в серверной микросервисе, позволяет двунаправленную связь посредством потоковой передачи данных, поскольку используется socket.io. У Feathers уже есть семантика / API для этого сценария? Я думаю о ситуации, когда микросервис публикует событие для других заинтересованных микросервисов, а не для клиента браузера.

Да, но почему другие заинтересованные службы не могут также использовать веб-сокеты? Мы думаем о добавлении других поставщиков (например, для различных служб обмена сообщениями), но на данный момент веб-сокеты кажутся достаточно быстрыми, и нигде не написано, что их можно использовать только в браузере.

@daffl @ekryski по мере распространения приложений из перьев нам также необходимо будет решить такие проблемы, как хотя бы однократная доставка (acks), идемпотентность, транзакции, противодавление (очереди) и т. д., рассматривали ли вы что-то вроде "службы перьев" рабочий? ".. т.е. внешние процессы, которые потребляют события из постоянной очереди amqp (например, rabbitmq) или redis (с использованием, например, kue)?

@daffl Думаю, я плохо понял до вашего ответа. Пока заинтересованные службы используют веб-сокеты для подписки на службу производителя, используя API регулярных событий для публикации новых событий производителя, этого достаточно, чтобы реализовать это в перьях, верно?

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

Есть ли в этом прогресс? Мне бы очень хотелось увидеть некоторую документацию / рабочий пример. Особенно в отношении того, как обрабатывается аутентификация.

@imns, мы над этим работаем. Я начал работать над примером и разделением приложения, и мы поняли, что существуют некоторые ограничения в настройке аутентификации. Итак, в настоящее время мы проводим рефакторинг auth, чтобы лучше поддерживать это. Должно пройти около недели, чтобы он приземлился.

Ой, я мог бы использовать это так плохо прямо сейчас: D

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

Если у вас есть лишние деньги, я думаю, эту книгу можно было бы рекомендовать к прочтению: https://www.amazon.com/Building-Microservices-Sam-Newman/dp/1491950358/ref=sr_1_1 ? Ie = UTF8 & qid = 1469071253 & sr = 8-1 & ключевые слова = микросервисы

Ребят, есть обновления по этому поводу? Спасибо.

@juanpujol, самая свежая информация всегда будет в этом билете. Тем не менее, спасибо за проверку.

(здесь Маркфавзи)

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

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

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

Но Feathers является более общим, чем фреймворк микросервисов, так что здесь все хорошо. Спасибо, Дэвид! Чем больше я вникаю в это, тем лучше и лучше выглядит! Отличная работа со всех сторон!

Просто подумал, что упомяну об этом здесь, так как это решает некоторые проблемы, возникающие при использовании Feathers в среде микросервисов. Это только первая реализация, но если у вас есть что добавить, не стесняйтесь здесь https://github.com/zapur1/feathers-rabbitmq/issues/1

@ zapur1 выглядит многообещающе ... Я опубликовал комментарий, чтобы начать обсуждение

Вы также можете использовать https://github.com/feathersjs/feathers-sync с rabbitMQ, Redis или MongoDB в качестве брокеров сообщений между службами, чтобы синхронизировать их все.

@ekryski feathers-sync решает немного другую проблему: что, если вы хотите, чтобы событие было получено только один раз в области именованной службы (не службы Feathers, а службы стиля микросервисов)? Если у вас было несколько экземпляров одной службы, получающей события от одного приложения API, каждый из них получит событие, вероятно, дублирующее действия, предпринимаемые при получении этого события несколькими экземплярами одного и того же кода.

@ekryski Я только что снова взглянул на репо, и zapur1 / перья-rabbitmq решает именно ту проблему, которую вы упомянули в «Предостережениях».

если я подключаю службу 1 к службе 2 с помощью socketClient, поэтому, если моя служба 2 имеет несколько экземпляров, как я могу реализовать баланс нагрузки :(

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

Я добавляю свои 2 цента к этому с https://github.com/kalisio/feathers-distributed , он направлен на развертывание N приложений перьев, в которых разные службы взаимодействуют вместе, чтобы вы могли разрабатывать каждое из них независимо. Он отличается от https://github.com/feathersjs/feathers-sync, который, насколько я понимаю, направлен на развертывание N приложений с одинаковыми сервисами. Все это вызывает ряд вопросов, например:

  • управление аутентификацией
  • API-шлюз и балансировка нагрузки
  • вызов удаленных хуков
  • ...

@daffl в приведенном вами примере с участием сервера 1 и сервера 2, как бы вы /users на сервере 2? Если бы у нас была эта служба, определенная на сервере 2, мы могли бы использовать перехватчики в конкретном файле перехватов службы, но, поскольку мы делаем app.use('/users', otherApp.service('users')); , как бы мы могли убедиться, что вызовы этой службы с сервера 2 будут выполняться только если пользователь аутентифицировался первым?

РЕДАКТИРОВАТЬ:
Nvm, я думаю, у меня есть идея: мы могли бы сделать что-то вроде const usersService = app.service('users') а затем usersService.hooks(hooks) где у хуков есть хуки авторизации, необходимые для защиты конечной точки, правильно?

Я написал больше о том, как можно выполнить распределенную аутентификацию, в https://stackoverflow.com/questions/41076627/evaluating-featherjs-authentication-needs/41095638#41095638 :

Существует несколько способов разделения услуг, каждый из которых имеет свои преимущества и недостатки. Для Feathers важно то, что сеансов нет, есть только веб-токены JSON. JWT не имеют состояния и могут быть прочитаны любым сервером, который использует один и тот же секрет, поэтому нет необходимости в центральном хранилище сеансов. Я могу придумать два основных варианта:

  1. Имейте основное приложение, которое обрабатывает авторизацию и управляет всеми подключенными клиентами, но вместо служб, которые взаимодействуют с базой данных, они подключаются к отдельным простым индивидуальным серверам API во внутренней сети. Это более простая настройка, а преимущество состоит в том, что внутренние серверы API могут быть очень простыми и вообще не нуждаться в аутентификации (поскольку основное приложение может делать все и будет делать запросы в соответствии с ограничениями аутентифицированных пользователей). Недостатком является то, что основное приложение по-прежнему является узким местом (но с меньшей нагрузкой, поскольку оно в основном действует как прокси для внутренних API).

my50m

  1. Каждый клиент подключается к каждому серверу API, который ему нужен, с помощью JWT. JWT создается отдельным аутентификационным (или пользовательским) API. Это более масштабируемое решение, поскольку единственное узкое место - это получение самой последней информации о пользователях из службы обычных пользователей (что может даже не всегда быть необходимым). Недостатком является то, что на стороне клиента сложнее управлять, и аутентификацию (по крайней мере, для JWT) придется настраивать на каждом сервере. Однако из-за отсутствия состояния JWT нет необходимости в каких-либо общих сеансах.

lw1bg

Была ли эта страница полезной?
0 / 5 - 0 рейтинги