Feathers: Microsserviços: forma recomendada de refatorar um aplicativo dividindo serviços?

Criado em 19 mai. 2016  ·  27Comentários  ·  Fonte: feathersjs/feathers

Estou tentando encontrar uma maneira prática / recomendada de extrair serviços, separando-os em suas próprias instâncias, seguindo o estilo de microsserviços. Sobre este assunto, há uma declaração interessante na página de destino das penas:

Orientado a serviços: penas Fornece a estrutura para criar aplicativos orientados a serviços desde o primeiro dia. Quando você eventualmente precisa dividir seu aplicativo em microsserviços, é uma transição fácil e seus aplicativos podem escalar sem dor.

Porém, ainda não consegui encontrar informações sobre como lidar com esse caso de uso em penas.

Em termos práticos, estou me concentrando inicialmente em dois tópicos básicos:

  • Comunicação: Acho que deve ser uma forma de extrair um serviço e permitir que o aplicativo original continue se comunicando sem a necessidade de um grande esforço de reescrita, por exemplo, substituindo as invocações de serviço por solicitações HTTP, por exemplo.
  • Autenticação: esclarecimentos sobre como as penas tratam da autenticação para a comunicação entre serviços depois que o serviço foi dividido.

Desde já, obrigado!

Documentation Question Scaling

Comentários muito úteis

Você está certo, não há muita documentação por aí ainda e criamos https://github.com/feathersjs/feathers/issues/157 há pouco tempo para manter o controle disso. Aqui estão alguns dos meus pensamentos sobre os dois tópicos que você mencionou:

Vamos supor que inicialmente temos um servidor com dois serviços, talvez algo como

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

O serviço de usuários está recebendo mais tráfego do que um servidor pode suportar, então queremos movê-lo para outro sistema criando outro aplicativo para ele:

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

Para que o serviço /todos se comunique agora com o serviço remoto, podemos usar Feathers como o cliente para se conectar a ele (Websockets são rápidos e bidirecionais, então por que não usá-los para comunicação servidor a servidor?):

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

Isso basicamente passaria de forma transparente o serviço de usuário para o serviço remoto por meio de uma conexão de websocket. Qualquer coisa que use o endpoint /users não terá que mudar nada.

Quanto à autenticação, existem muitas opções diferentes. No cenário acima, a maneira mais fácil seria server1 apenas colocar na lista de permissões o endereço IP dos outros servidores, já que server2 ainda é o único ponto de comunicação para os clientes. Eventualmente server2 poderia simplesmente se tornar um gateway que lida com a autenticação do usuário e então apenas passa as chamadas de serviço para outros servidores (que não precisam se preocupar com a autenticação além de verificar o endereço IP de origem).

Todos 27 comentários

Você está certo, não há muita documentação por aí ainda e criamos https://github.com/feathersjs/feathers/issues/157 há pouco tempo para manter o controle disso. Aqui estão alguns dos meus pensamentos sobre os dois tópicos que você mencionou:

Vamos supor que inicialmente temos um servidor com dois serviços, talvez algo como

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

O serviço de usuários está recebendo mais tráfego do que um servidor pode suportar, então queremos movê-lo para outro sistema criando outro aplicativo para ele:

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

Para que o serviço /todos se comunique agora com o serviço remoto, podemos usar Feathers como o cliente para se conectar a ele (Websockets são rápidos e bidirecionais, então por que não usá-los para comunicação servidor a servidor?):

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

Isso basicamente passaria de forma transparente o serviço de usuário para o serviço remoto por meio de uma conexão de websocket. Qualquer coisa que use o endpoint /users não terá que mudar nada.

Quanto à autenticação, existem muitas opções diferentes. No cenário acima, a maneira mais fácil seria server1 apenas colocar na lista de permissões o endereço IP dos outros servidores, já que server2 ainda é o único ponto de comunicação para os clientes. Eventualmente server2 poderia simplesmente se tornar um gateway que lida com a autenticação do usuário e então apenas passa as chamadas de serviço para outros servidores (que não precisam se preocupar com a autenticação além de verificar o endereço IP de origem).

Obrigado pela resposta! Você planeja cobrir este tópico nos documentos oficiais (talvez uma subseção dos Guias)? Deixe-me saber se posso contribuir nesse sentido.

Definitivamente. E definitivamente precisamos de alguma ajuda. Talvez vamos reunir primeiro o que gostaríamos de ver em um guia e depois fazer alguns aplicativos de demonstração?

💯 @daffl está ligado. É algo que estou planejando abordar oficialmente no próximo mês ou depois, já que me comprometi a fazer uma apresentação sobre o assunto.

@daffl A abordagem que você mencionou usando o cliente de penas em um microsserviço de back-end permite a comunicação bidirecional por meio de streaming de dados, uma vez que o socket.io é usado. O Feathers já possui semântica / API para este cenário? Estou pensando em uma situação em que um microsserviço publica um evento para outros microsserviços interessados, não um cliente de navegador.

Sim, mas por que os outros serviços interessados ​​também não podem usar websockets? Estamos pensando em adicionar outros provedores (por exemplo, para diferentes serviços de mensagens), mas por enquanto os websockets parecem ser rápidos o suficiente e não está escrito em nenhum lugar que só possa ser usado no navegador.

@daffl @ekryski à medida que os aplicativos de penas são distribuídos, também precisamos resolver problemas como entrega pelo menos uma vez (acks), idempotência, transações, contrapressão (filas) etc. você considerou algo como "serviço de penas- trabalhador? ".. ie. processos externos que consomem eventos da fila amqp durável (por exemplo, rabbitmq) ou redis (usando por exemplo kue)?

@daffl Acho que não entendi bem antes de sua resposta. Contanto que os serviços interessados ​​usem web sockets para assinar o serviço do produtor, usando a API de eventos regulares para publicar novos eventos no produtor é suficiente implementar isso em penas, certo?

Concordo com @justingreenberg , outro problema a ser resolvido é a repetição de solicitações quando o microsserviço responsável fica offline (falha, atualizações, etc). Tecnicamente, isso seria resolvido usando filas de mensagens também.

Algum progresso nisso? Eu realmente adoraria ver alguma documentação / um exemplo de trabalho. Especialmente no que diz respeito a como a autenticação é tratada.

@imns estamos trabalhando nisso. Comecei a trabalhar no exemplo e na divisão de um aplicativo e percebemos que há algumas limitações na configuração do auth. Portanto, estamos atualmente refatorando a autenticação para melhor suportar isso. Deve demorar cerca de uma semana para isso chegar.

Oh cara, eu poderia usar isso tão mal agora: D

Só por curiosidade, você está retrabalhando o auth para trabalhar com vários front-ends também? Acho que muitos aplicativos maiores hoje em dia usam um microsserviço no back-end, mas também interrompem seus aplicativos de front-end.

Se você tiver algum dinheiro extra, acho que este livro pode ser considerado leitura recomendada: https://www.amazon.com/Building-Microservices-Sam-Newman/dp/1491950358/ref=sr_1_1 ? Ie = UTF8 & qid = 1469071253 & sr = 8-1 & keywords = Microsserviços

Pessoal, alguma atualização sobre isso? Obrigada.

@juanpujol as informações mais recentes sempre estarão neste tíquete. Obrigado por verificar, no entanto.

(marcfawzi aqui)

Não li o tópico inteiro, mas presumo que seremos capazes de usar um banco de dados por serviço (na arquitetura de Micreoservices ter essa separação é crucial para manter a abstração. Do contrário, se todos os serviços compartilham o mesmo banco de dados, o que impede as pessoas de definir relações entre modelos de serviço (uma violação da abstração de microsserviços) em vez de criar serviços usando a API de serviço uniforme

Nada impede isso, eu diria que é sua responsabilidade não fazer isso. Só será realmente um problema se você definir seus modelos e relacionamentos no nível ORM. Não acho que obter relacionamentos no nível de serviço chamando outros serviços viola a abstração do microsserviço.

Sim, exatamente o que eu quis dizer. Tenho a tendência de pensar que a segregação de serviços em que cada serviço tem seu próprio banco de dados é uma maneira segura de forçar a composição por meio da interface de serviço, e não no nível ORM.

Mas Feathers é mais geral do que uma estrutura de microsserviços, então tudo bem aqui. Obrigado David! Isso fica parecendo melhor e melhor quanto mais eu cavo nele! Ótimo trabalho ao redor!

Pensei em mencionar isso aqui, pois ele resolve alguns dos problemas que surgem com o uso do Feathers em um ambiente de microsserviços. É apenas a primeira implementação, mas se você tiver algo a contribuir, fique à vontade aqui https://github.com/zapur1/feathers-rabbitmq/issues/1

@ zapur1 que parece promissor ...

Você também pode usar https://github.com/feathersjs/feathers-sync com rabbitMQ, Redis ou MongoDB como intermediários de mensagens entre os serviços para mantê-los todos sincronizados.

@ekryski feathers-sync resolve um problema um pouco diferente. E se você quiser que um evento seja recebido apenas uma vez no domínio de um serviço nomeado (não um serviço Feathers, mas um serviço no estilo de microsserviços)? Se você tiver várias instâncias de um único serviço recebendo eventos de um único aplicativo de API, cada um receberá o evento, provavelmente duplicando as ações executadas quando esse evento for recebido em várias instâncias do mesmo código.

@ekryski Acabei de dar uma olhada no repo novamente e zapur1 / feather-rabbitmq resolve exatamente o problema que você mencionou em "Advertências"

se eu conectar um serviço 1 ao serviço 2 por socketClient, então, se meu serviço 2 tiver várias instâncias, como posso implementar o equilíbrio de carga :(

Se eu criar um aplicativo do lado do servidor separado que se conecta via socketClient, qual é a melhor maneira de autenticar para que qualquer um dos serviços esteja disponível, independentemente de quaisquer restrições que tenham sido configuradas.

Acrescento meus 2 centavos a isso com https://github.com/kalisio/feathers-distributed , que visa implantar aplicativos de penas N que mantêm diferentes serviços conversando entre si, para que você possa desenvolver cada um de forma independente. É diferente de https://github.com/feathersjs/feathers-sync, que visa implantar aplicativos de penas N que mantêm os mesmos serviços, tanto quanto eu entendo. Tudo isso levanta um conjunto de questões como:

  • gerenciamento de autenticação
  • Gateway de API e balanceamento de carga
  • invocação de ganchos remotos
  • ...

@daffl no exemplo que você deu envolvendo o servidor 1 e o servidor 2, como você protegeria o serviço /users no servidor 2? Se tivéssemos esse serviço definido no servidor 2, poderíamos usar ganchos no arquivo de gancho de serviço específico, mas como estamos fazendo app.use('/users', otherApp.service('users')); , como teríamos certeza de que as chamadas para esse serviço do servidor 2 só seriam feitas se o usuário autenticou primeiro?

EDITAR:
Nvm, acho que tenho uma ideia: poderíamos fazer algo como const usersService = app.service('users') e então usersService.hooks(hooks) onde os ganchos têm os ganchos de autenticação necessários para proteger o endpoint certo?

Escrevi mais sobre como a autenticação distribuída pode ser feita em https://stackoverflow.com/questions/41076627/evaluating-featherjs-authentication-needs/41095638#41095638 :

Existem várias maneiras de dividir os serviços, cada uma com suas próprias vantagens e desvantagens. Uma coisa geralmente importante para o Feathers é que não há sessões, apenas tokens da Web JSON. Os JWTs não têm estado e podem ser lidos por qualquer servidor que compartilhe o mesmo segredo, portanto, não precisa haver um armazenamento de sessão central. As duas opções principais em que posso pensar são:

  1. Ter um aplicativo principal que lida com autorização e gerenciamento de todos os clientes conectados, mas em vez de ter serviços que se comunicam com o banco de dados, eles se conectam a servidores API individuais simples separados na rede interna. Esta é a configuração mais fácil e a vantagem é que os servidores API internos podem ser super simples e não precisam de autenticação (já que o aplicativo principal tem permissão para fazer tudo e fará consultas de acordo com as restrições dos usuários autenticados). A desvantagem é que o aplicativo principal ainda é o gargalo (mas com uma carga reduzida, pois basicamente atua como um proxy para APIs internas).

my50m

  1. Cada cliente se conecta a cada servidor API de que precisa usando um JWT. O JWT é criado por uma API de autenticação (ou usuário) separada. Esta é a solução mais escalonável, pois o único gargalo é recuperar as informações mais atualizadas do usuário de um serviço de usuário comum (o que pode nem sempre ser necessário). A desvantagem é que é mais complexo gerenciar no lado do cliente e a autenticação (pelo menos para JWT) terá que ser configurada em cada servidor. Devido à ausência de estado do JWT, no entanto, não é necessário haver sessões compartilhadas.

lw1bg

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

eric-burel picture eric-burel  ·  3Comentários

harrytang picture harrytang  ·  3Comentários

perminder-klair picture perminder-klair  ·  3Comentários

rstegg picture rstegg  ·  3Comentários

huytran0605 picture huytran0605  ·  3Comentários