Feathers: Microservicios: ¿forma recomendada de refactorizar una aplicación dividiendo los servicios?

Creado en 19 may. 2016  ·  27Comentarios  ·  Fuente: feathersjs/feathers

Estoy tratando de encontrar una forma práctica / recomendada de extraer servicios, separándolos en sus propias instancias, siguiendo el estilo de los microservicios. En este asunto, hay una declaración interesante en la página de inicio de plumas:

Orientado al servicio: Feathers le brinda la estructura para crear aplicaciones orientadas al servicio desde el primer día. Cuando finalmente necesite dividir su aplicación en microservicios, es una transición fácil y Feathers, sus aplicaciones pueden escalar sin dolor.

Pero, todavía no pude encontrar información sobre cómo lidiar con este caso de uso en plumas.

En términos prácticos, me estoy enfocando inicialmente en dos temas básicos:

  • Comunicación: Creo que debería ser una forma de extraer un servicio y permitir que la aplicación original continúe comunicándose sin la necesidad de un gran esfuerzo de reescritura, por ejemplo, reemplazando las invocaciones al servicio por solicitudes HTTP, por ejemplo.
  • Autenticación: aclaraciones sobre cómo las plumas manejan la autenticación hacia la comunicación entre servicios después de que el servicio se ha dividido.

¡Gracias por adelantado!

Documentation Question Scaling

Comentario más útil

Tiene razón, todavía no hay demasiada documentación y creamos https://github.com/feathersjs/feathers/issues/157 hace un tiempo para realizar un seguimiento de eso. Estos son algunos de mis pensamientos sobre los dos temas que mencionaste:

Supongamos que inicialmente tenemos un servidor con dos servicios, tal vez algo como

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

El servicio de usuarios está recibiendo más tráfico del que puede manejar un servidor, por lo que queremos moverlo a otro sistema creando otra aplicación para él:

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

Para que el servicio /todos ahora se comunique con el servicio remoto, podemos usar Feathers como cliente para conectarse a él (los Websockets son rápidos y bidireccionales, así que ¿por qué no usarlos para la comunicación de 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'));

Básicamente, esto pasaría de forma transparente el servicio del usuario al servicio remoto a través de una conexión websocket. Cualquier cosa que use el punto final /users no tendrá que cambiar nada.

En cuanto a la autenticación, existen muchas opciones diferentes. En el escenario anterior, la forma más fácil sería que server1 incluyese en la lista blanca la dirección IP de los otros servidores, ya que server2 sigue siendo el único punto de comunicación para los clientes. Eventualmente, server2 podría convertirse en una puerta de enlace que maneja la autenticación del usuario y luego simplemente pasa las llamadas de servicio a otros servidores (que no tienen que preocuparse por la autenticación más que verificar la dirección IP de origen).

Todos 27 comentarios

Tiene razón, todavía no hay demasiada documentación y creamos https://github.com/feathersjs/feathers/issues/157 hace un tiempo para realizar un seguimiento de eso. Estos son algunos de mis pensamientos sobre los dos temas que mencionaste:

Supongamos que inicialmente tenemos un servidor con dos servicios, tal vez algo como

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

El servicio de usuarios está recibiendo más tráfico del que puede manejar un servidor, por lo que queremos moverlo a otro sistema creando otra aplicación para él:

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

Para que el servicio /todos ahora se comunique con el servicio remoto, podemos usar Feathers como cliente para conectarse a él (los Websockets son rápidos y bidireccionales, así que ¿por qué no usarlos para la comunicación de 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'));

Básicamente, esto pasaría de forma transparente el servicio del usuario al servicio remoto a través de una conexión websocket. Cualquier cosa que use el punto final /users no tendrá que cambiar nada.

En cuanto a la autenticación, existen muchas opciones diferentes. En el escenario anterior, la forma más fácil sería que server1 incluyese en la lista blanca la dirección IP de los otros servidores, ya que server2 sigue siendo el único punto de comunicación para los clientes. Eventualmente, server2 podría convertirse en una puerta de enlace que maneja la autenticación del usuario y luego simplemente pasa las llamadas de servicio a otros servidores (que no tienen que preocuparse por la autenticación más que verificar la dirección IP de origen).

¡Gracias por la respuesta! ¿Planea cubrir este tema en documentos oficiales (tal vez una subsección de Guías)? Déjame saber si puedo contribuir en este sentido.

Definitivamente. Y definitivamente nos vendría bien un poco de ayuda. ¿Quizás recopilemos primero lo que nos gustaría ver en una guía y luego hagamos algunas aplicaciones de demostración?

💯 @daffl es

@daffl El enfoque que mencionaste con el uso de feathers-client en un microservicio backend permite la comunicación bidireccional a través de transmisión de datos, ya que se usa socket.io. ¿Feathers ya tiene semántica / API para este escenario? Estoy pensando en una situación en la que un microservicio publica un evento para otros microservicios interesados, no un cliente de navegador.

Sí, pero ¿por qué los otros servicios interesados ​​no pueden utilizar también websockets? Estamos pensando en agregar otros proveedores (por ejemplo, para diferentes servicios de mensajería) pero, por ahora, los websockets parecen ser lo suficientemente rápidos y no está escrito en ninguna parte que solo se puedan usar en el navegador.

@daffl @ekryski a medida que se distribuyen las aplicaciones de plumas, también deberíamos abordar cuestiones como la entrega al menos una vez (acks), la idempotencia, las transacciones, la contrapresión (colas), etc. trabajador? ".. es decir. procesos externos que consumen eventos de la cola duradera amqp (es decir, rabbitmq) o redis (usando ie kue)?

@daffl Creo que no entendí bien antes de tu respuesta. Siempre que los servicios interesados ​​usen sockets web para suscribirse al servicio de productor, usar la API de eventos regulares para publicar nuevos eventos en el productor es suficiente para implementar esto en plumas, ¿verdad?

Estoy de acuerdo con @justingreenberg , otro problema que se debe abordar es la reproducción de solicitudes cuando los microservicios responsables se desconectan (fallas, actualizaciones, etc.). Técnicamente, esto también se solucionaría mediante el uso de colas de mensajes.

¿Algún progreso en esto? Realmente me encantaría ver algo de documentación / un ejemplo de trabajo. Especialmente en lo que respecta a cómo se maneja la autenticación.

@imns estamos trabajando en esto. Comencé a trabajar en el ejemplo y a dividir una aplicación y nos dimos cuenta de que existen algunas limitaciones en la configuración de la autenticación. Por lo tanto, actualmente estamos refactorizando la autenticación para respaldar mejor esto. Debería ser aproximadamente una semana para que aterrice.

Oh hombre, podría usar esto tan mal ahora mismo: D

Solo por curiosidad, ¿está modificando la autenticación para que funcione también con múltiples interfaces? Creo que muchas aplicaciones más grandes hoy en día usan un microservicio en el backend, pero también rompen sus aplicaciones de front-end.

Si tiene unos cuantos dólares extra, creo que este libro podría considerarse una lectura recomendada: https://www.amazon.com/Building-Microservices-Sam-Newman/dp/1491950358/ref=sr_1_1 ? Ie = UTF8 & qid = 1469071253 & sr = 8-1 & palabras clave = microservicios

Chicos, ¿alguna actualización sobre esto? Gracias.

@juanpujol la última información siempre estará en este ticket. Sin embargo, gracias por comprobarlo.

(marcfawzi aquí)

No he leído todo el hilo, pero supongo que podremos usar una base de datos por servicio (en la arquitectura de Micreoservices, tener esta separación es crucial para mantener la abstracción. De lo contrario, si todos los servicios comparten la misma base de datos, ¿qué impide a las personas? de definir relaciones entre modelos de servicio (una violación de la abstracción de microservicios) en lugar de componer servicios utilizando la API de servicio uniforme?

En realidad, nada impide eso, yo diría que es tu responsabilidad no hacer eso. Solo será realmente un problema si define sus modelos y relaciones a nivel de ORM. No creo que establecer relaciones a nivel de servicio llamando a otros servicios viole la abstracción del microservicio.

Sí, exactamente lo que quise decir. Tiendo a pensar que la segregación de servicios donde cada servicio tiene su propia base de datos es una forma segura de forzar la composición a través de la interfaz de servicio en lugar de a nivel de ORM.

Pero Feathers es más general que un marco de microservicios, así que todo está bien aquí. ¡Gracias David! ¡Esto se ve cada vez mejor cuanto más lo indago! ¡Buen trabajo por todos lados!

Pensé que mencionaría esto aquí, ya que resuelve algunos de los problemas que surgen con el uso de Feathers en un entorno de microservicios. Es solo la primera implementación, pero si tiene algo que contribuir, no dude en hacerlo aquí https://github.com/zapur1/feathers-rabbitmq/issues/1

@ zapur1 que parece prometedor ... He publicado un comentario para iniciar la discusión

También puede usar https://github.com/feathersjs/feathers-sync con rabbitMQ, Redis o MongoDB como intermediarios de mensajes entre servicios para mantenerlos todos sincronizados.

@ekryski feathers-sync resuelve un pequeño problema diferente, ¿qué pasa si solo desea que un evento se reciba una vez dentro del ámbito de un servicio con nombre (no un servicio Feathers sino un servicio estilo microservicios)? Si tuvo varias instancias de un solo servicio que recibe eventos de una sola aplicación API, cada una recibirá el evento probablemente duplicando las acciones que se toman cuando ese evento se recibe en múltiples instancias del mismo código exacto.

@ekryski Acabo de echar un vistazo al repositorio nuevamente y zapur1 / feathers-rabbitmq resuelve el problema exacto que mencionas en "Advertencias"

si conecto un servicio 1 al servicio 2 por socketClient, entonces si mi servicio 2 tiene instancias múltiples, ¿cómo puedo implementar el equilibrio de carga?

Si creo una aplicación del lado del servidor separada que se conecta a través de socketClient, ¿cuál es la mejor manera de autenticarse para que cualquiera de los servicios esté disponible independientemente de las restricciones que se hayan configurado?

Agrego mis 2 centavos a esto con https://github.com/kalisio/feathers-distributed , tiene como objetivo implementar aplicaciones N feathers que mantengan diferentes servicios hablando juntos, para que pueda desarrollar cada uno de forma independiente. Es diferente de https://github.com/feathersjs/feathers-sync, que tiene como objetivo implementar aplicaciones N feathers que tengan los mismos servicios, hasta donde tengo entendido. Todo esto plantea una serie de preguntas como:

  • gestión de autenticación
  • Puerta de enlace API y equilibrio de carga
  • invocación de ganchos remotos
  • ...

@daffl en el ejemplo que dio sobre el servidor 1 y el servidor 2, ¿cómo protegería el servicio /users en el servidor 2? Si tuviéramos ese servicio definido en el servidor 2, podríamos usar ganchos en el archivo de gancho de servicio específico, pero como estamos haciendo app.use('/users', otherApp.service('users')); , ¿cómo nos aseguraríamos de que las llamadas a ese servicio desde el servidor 2 solo se realicen? si el usuario se autenticó primero?

EDITAR:
Nvm, creo que tengo una idea: podríamos hacer algo como const usersService = app.service('users') y luego usersService.hooks(hooks) donde los ganchos tienen los ganchos de autenticación necesarios para asegurar el punto final, ¿verdad?

Escribí más sobre cómo se podría realizar la autenticación distribuida en https://stackoverflow.com/questions/41076627/evaluating-featherjs-authentication-needs/41095638#41095638 :

Hay varias formas de dividir los servicios, cada una con sus propias ventajas e inconvenientes. Una cosa generalmente importante para Feathers es que no hay sesiones, solo tokens web JSON. Los JWT no tienen estado y pueden ser leídos por cualquier servidor que comparta el mismo secreto, por lo que no es necesario que haya un almacén de sesiones central. Las dos opciones principales que se me ocurren son:

  1. Tienen una aplicación principal que maneja la autorización y la administración de todos los clientes conectados, pero en lugar de tener servicios que se comunican con la base de datos, se conectan a servidores API individuales individuales separados en la red interna. Esta es la configuración más fácil y la ventaja es que los servidores API internos pueden ser súper simples y no necesitan autenticación en absoluto (ya que la aplicación principal puede hacer todo y hará consultas de acuerdo con las restricciones de los usuarios autenticados). La desventaja es que la aplicación principal sigue siendo el cuello de botella (pero con una carga reducida, ya que básicamente actúa como un proxy de las API internas).

my50m

  1. Todos los clientes se conectan a todos los servidores API que necesitan mediante un JWT. El JWT se crea mediante una API de autenticación (o usuario) separada. Esta es la solución más escalable, ya que el único cuello de botella es recuperar la información de usuario más actualizada de un servicio de usuarios común (que puede que no siempre sea necesario). La desventaja es que es más complejo de administrar en el lado del cliente y la autenticación (al menos para JWT) tendrá que configurarse en cada servidor. Sin embargo, debido a la apatridia de JWT, no es necesario que haya sesiones compartidas.

lw1bg

¿Fue útil esta página
0 / 5 - 0 calificaciones