Feathers: Microservices: moyen recommandé de refactoriser une application en fractionnant les services?

Créé le 19 mai 2016  ·  27Commentaires  ·  Source: feathersjs/feathers

J'essaie de trouver un moyen pratique / recommandé d'extraire les services, en les séparant en leurs propres instances, en suivant le style des microservices. Dans cette affaire, il y a une déclaration intéressante sur la page de destination des plumes:

Orienté service: plumes vous donne la structure pour créer des applications orientées service dès le premier jour. Lorsque vous avez finalement besoin de diviser votre application en microservices, c'est une transition facile et vos applications peuvent évoluer sans douleur.

Mais je n'ai toujours pas trouvé d'informations sur la façon de gérer ce cas d'utilisation dans les plumes.

Concrètement, je me concentre dans un premier temps sur deux sujets de base:

  • Communication: Je pense que cela devrait être un moyen d'extraire un service et de permettre à l'application d'origine de continuer à communiquer sans avoir besoin d'un gros effort de réécriture, par exemple, en remplaçant les appels au service par des requêtes HTTP, par exemple.
  • Authentification: clarifications sur la façon dont les plumes gèrent l'authentification pour la communication interservices après la division du service.

Merci d'avance!

Documentation Question Scaling

Commentaire le plus utile

Vous avez raison, il n'y a pas encore trop de documentation sur le marché et nous avons créé https://github.com/feathersjs/feathers/issues/157 il y a quelque temps pour en garder une trace. Voici quelques-unes de mes réflexions sur les deux sujets que vous avez mentionnés:

Supposons que nous ayons initialement un serveur avec deux services, peut-être quelque chose comme

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

Le service utilisateurs reçoit plus de trafic que le serveur ne peut en gérer, nous souhaitons donc le déplacer vers un autre système en créant une autre application pour lui:

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

Pour que le service /todos communique maintenant avec le service distant, nous pouvons utiliser Feathers comme client pour s'y connecter (les Websockets sont rapides et bidirectionnels, alors pourquoi ne pas les utiliser pour la communication de serveur à serveur?):

// 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'));

Cela passerait fondamentalement de manière transparente le service utilisateur au service distant via une connexion Websocket. Tout ce qui utilise le point /users terminaison d'origine

En ce qui concerne l'authentification, il existe de nombreuses options différentes. Dans le scénario ci-dessus, le moyen le plus simple serait pour server1 de simplement mettre en liste blanche l'adresse IP des autres serveurs puisque server2 est toujours le seul point de communication pour les clients. Finalement, server2 pourrait simplement devenir une passerelle qui gère l'authentification des utilisateurs, puis passe simplement les appels de service à d'autres serveurs (qui n'ont pas à se soucier de l'authentification autre que la vérification de l'adresse IP d'origine).

Tous les 27 commentaires

Vous avez raison, il n'y a pas encore trop de documentation sur le marché et nous avons créé https://github.com/feathersjs/feathers/issues/157 il y a quelque temps pour en garder une trace. Voici quelques-unes de mes réflexions sur les deux sujets que vous avez mentionnés:

Supposons que nous ayons initialement un serveur avec deux services, peut-être quelque chose comme

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

Le service utilisateurs reçoit plus de trafic que le serveur ne peut en gérer, nous souhaitons donc le déplacer vers un autre système en créant une autre application pour lui:

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

Pour que le service /todos communique maintenant avec le service distant, nous pouvons utiliser Feathers comme client pour s'y connecter (les Websockets sont rapides et bidirectionnels, alors pourquoi ne pas les utiliser pour la communication de serveur à serveur?):

// 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'));

Cela passerait fondamentalement de manière transparente le service utilisateur au service distant via une connexion Websocket. Tout ce qui utilise le point /users terminaison d'origine

En ce qui concerne l'authentification, il existe de nombreuses options différentes. Dans le scénario ci-dessus, le moyen le plus simple serait pour server1 de simplement mettre en liste blanche l'adresse IP des autres serveurs puisque server2 est toujours le seul point de communication pour les clients. Finalement, server2 pourrait simplement devenir une passerelle qui gère l'authentification des utilisateurs, puis passe simplement les appels de service à d'autres serveurs (qui n'ont pas à se soucier de l'authentification autre que la vérification de l'adresse IP d'origine).

Merci pour la réponse! Envisagez-vous de couvrir ce sujet dans des documents officiels (peut-être une sous-section des guides)? Faites-moi savoir si je peux contribuer à cet égard.

Absolument. Et nous pourrions certainement avoir besoin d'aide. Peut-être allons-nous d'abord rassembler ce que nous aimerions voir dans un guide, puis créer des applications de démonstration?

💯 @daffl est

@daffl L'approche que vous avez mentionnée en utilisant feathers-client sur un microservice backend permet une communication bidirectionnelle via des données de streaming, puisque socket.io est utilisé. Feathers a déjà une sémantique / API pour ce scénario? Je pense à une situation où un microservice publie un événement pour d'autres microservices intéressés, pas un client de navigateur.

Oui, mais pourquoi les autres services intéressés ne pourraient-ils pas également utiliser des websockets? Nous envisageons d'ajouter d'autres fournisseurs (par exemple pour différents services de messagerie) mais pour l'instant les websockets semblent être assez rapides et il n'est écrit nulle part qu'ils ne peuvent être utilisés que dans le navigateur.

@daffl @ekryski à

@daffl Je pense que je n'ai pas bien compris avant ta réponse. Tant que les services intéressés utilisent des sockets Web pour s'abonner au service producteur, en utilisant l'API d'événements réguliers pour publier de nouveaux événements sur le producteur, il suffit de l'implémenter en plumes, n'est-ce pas?

Je suis d'accord avec @justingreenberg , un autre problème à résoudre est la relecture des demandes lorsque les microservices responsables se déconnectent (crash, mises à jour, etc.). Techniquement, ce serait également une adresse en utilisant des files d'attente de messages.

Des progrès à ce sujet? J'aimerais vraiment voir de la documentation / un exemple fonctionnel. Surtout en ce qui concerne la façon dont l'authentification est gérée.

@imns nous y travaillons. J'ai commencé à travailler sur l'exemple et à diviser une application et nous avons réalisé qu'il y avait des limites à la configuration de l'authentification. Nous refactorisons donc actuellement auth pour mieux supporter cela. Ça devrait prendre environ une semaine pour que ça débarque.

Oh mec, je pourrais tellement utiliser ça maintenant: D

Par curiosité, retravaillez-vous également l'authentification pour travailler avec plusieurs frontaux? Je pense que de nombreuses applications plus grandes utilisent de nos jours un microservice sur le backend, mais cassent également leurs applications frontales.

Si vous avez quelques dollars supplémentaires, je pense que ce livre pourrait être considéré comme une lecture recommandée: https://www.amazon.com/Building-Microservices-Sam-Newman/dp/1491950358/ref=sr_1_1 ? Ie = UTF8 & qid = 1469071253 & sr = 8-1 & keywords = Microservices

Les gars, des mises à jour à ce sujet? Merci.

@juanpujol les dernières informations seront toujours dans ce ticket. Merci d'avoir vérifié, cependant.

(marcfawzi ici)

Je n'ai pas lu l'intégralité du thread mais je suppose que nous pourrons utiliser une base de données par service (dans l'architecture Micreoservices, cette séparation est cruciale pour maintenir l'abstraction. Sinon, si tous les services partagent la même base de données, cela empêche les gens de définir des relations entre les modèles de service (une violation de l'abstraction des microservices) au lieu de composer des services à l'aide de l'API de service uniforme?

Rien n'empêche vraiment ça, je dirais que c'est à vous de ne pas faire ça. Ce ne sera vraiment un problème que si vous définissez vos modèles et relations au niveau ORM. Je ne pense pas qu'établir des relations au niveau du service en appelant un autre service viole l'abstraction du microservice.

Ouais exactement ce que je voulais dire. J'ai tendance à penser que la ségrégation des services où chaque service a sa propre base de données est un moyen sûr de forcer la composition via l'interface de service plutôt qu'au niveau ORM.

Mais Feathers est plus général qu'un framework Microservices, donc tout va bien ici. Merci David! Cela continue à paraître de mieux en mieux à mesure que je creuse dedans! Excellent travail tout autour!

Je pensais juste que je mentionnerais ceci ici, car cela résout certains des problèmes liés à l'utilisation de Feathers dans un environnement de micro-services. Ce n'est que la première implémentation, mais si vous avez quelque chose à contribuer, n'hésitez pas ici https://github.com/zapur1/feathers-rabbitmq/issues/1

@ zapur1 qui semble prometteur ... J'ai publié un commentaire pour lancer la discussion

Vous pouvez également utiliser https://github.com/feathersjs/feathers-sync avec rabbitMQ, Redis ou MongoDB comme courtiers de messages entre les services pour les garder tous synchronisés.

@ekryski feathers-sync résout un peu un problème différent, que se passe-t-il si vous voulez qu'un événement ne soit reçu qu'une seule fois dans le domaine d'un service nommé (pas un service Feathers mais un service de style microservices)? Si vous aviez plusieurs instances d'un même service recevant des événements d'une seule application API, chacune d'entre elles recevra l'événement dupliquant probablement les actions entreprises lorsque cet événement est reçu sur plusieurs instances du même code.

@ekryski Je viens de jeter un œil au repo à nouveau et zapur1 / feathers-rabbitmq résout le problème exact que vous mentionnez dans "Mises en garde"

si je connecte un service 1 au service 2 par socketClient, donc si mon service 2 a plusieurs instances, comment puis-je implémenter l'équilibre de charge :(

Si je crée une application côté serveur distincte qui se connecte via socketClient, quelle est la meilleure façon de s'authentifier afin que l'un des services soit disponible quelles que soient les restrictions qui ont été configurées.

J'ajoute mes 2 cents à ce sujet avec https://github.com/kalisio/feathers-distributed , il vise à déployer des applications N feathers contenant différents services qui parlent ensemble, afin que vous puissiez développer chacun indépendamment. C'est différent de https://github.com/feathersjs/feathers-sync qui vise à déployer des applications N feathers contenant les mêmes services pour autant que je sache. Tout cela soulève un ensemble de questions telles que:

  • gestion de l'authentification
  • Passerelle API et équilibrage de charge
  • invocation de hooks à distance
  • ...

@daffl sur l'exemple que vous avez donné impliquant le serveur 1 et le serveur 2, comment sécuriseriez-vous le service /users sur le serveur 2? Si nous avions défini ce service dans le serveur 2, nous pourrions utiliser des hooks dans le fichier de hook de service spécifique, mais puisque nous faisons app.use('/users', otherApp.service('users')); , comment pourrions-nous nous assurer que les appels à ce service à partir du serveur 2 ne seraient effectués que si l'utilisateur s'est authentifié en premier?

ÉDITER:
NVM, je pense que j'ai une idée: nous pourrions faire quelque chose comme const usersService = app.service('users') puis usersService.hooks(hooks) où hooks a les hooks d'authentification nécessaires pour sécuriser le point de terminaison, n'est-ce pas?

J'ai écrit plus sur la façon dont l'authentification distribuée pourrait être effectuée dans https://stackoverflow.com/questions/41076627/evaluating-featherjs-authentication-needs/41095638#41095638 :

Il existe plusieurs façons de fractionner les services, chacune avec ses propres avantages et inconvénients. Une chose généralement importante pour Feathers est qu'il n'y a pas de sessions, juste des jetons Web JSON. Les JWT sont sans état et peuvent être lus par n'importe quel serveur qui partage le même secret, il n'est donc pas nécessaire de disposer d'un magasin de session central. Les deux principales options auxquelles je peux penser sont:

  1. Avoir une application principale qui gère l'autorisation et la gestion de tous les clients connectés, mais au lieu d'avoir des services qui parlent à la base de données, ils se connectent à des serveurs API individuels simples séparés dans le réseau interne. C'est la configuration la plus simple et l'avantage est que les serveurs d'API internes peuvent être super simples et n'ont pas du tout besoin d'authentification (puisque l'application principale est autorisée à tout faire et fera des requêtes en fonction des restrictions des utilisateurs authentifiés). L'inconvénient est que l'application principale est toujours le goulot d'étranglement (mais avec une charge réduite car elle agit essentiellement comme un proxy pour les API internes).

my50m

  1. Chaque client se connecte à chaque serveur d'API dont il a besoin à l'aide d'un JWT. Le JWT est créé par une API d'authentification (ou utilisateur) distincte. Il s'agit de la solution la plus évolutive, car le seul goulot d'étranglement est la récupération des informations utilisateur les plus à jour à partir d'un service d'utilisateurs commun (ce qui n'est peut-être même pas toujours nécessaire). L'inconvénient est qu'il est plus complexe à gérer côté client et l'authentification (au moins pour JWT) devra être configurée sur chaque serveur. Cependant, en raison de l'apatridie de JWT, aucune session partagée n'est nécessaire.

lw1bg

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

eric-burel picture eric-burel  ·  3Commentaires

rrubio picture rrubio  ·  4Commentaires

rstegg picture rstegg  ·  3Commentaires

huytran0605 picture huytran0605  ·  3Commentaires

codeus-de picture codeus-de  ·  4Commentaires