Repite después de mi:
Los eventos REST y asíncronos no son alternativas. Son completamente ortogonales.
Puede tener uno, o el otro, o ambos, o ninguno. Son herramientas completamente diferentes para dominios de problemas completamente diferentes. De hecho, la comunicación de solicitud-respuesta de propósito general es absolutamente capaz de ser asíncrona, controlada por eventos y tolerante a fallas .
Como ejemplo trivial, el protocolo AMQP envía mensajes a través de una conexión TCP. En TCP, cada paquete debe ser reconocido por el receptor . Si un remitente de un paquete no recibe un ACK para ese paquete, sigue reenviando ese paquete hasta que sea ACK o hasta que la capa de aplicación "se rinda" y abandone la conexión. Este es claramente un modelo de solicitud-respuesta no tolerante a fallas porque cada "solicitud de envío de paquetes" debe tener una "respuesta de reconocimiento de paquetes" que lo acompaña, y la falta de respuesta da como resultado que falle la conexión completa. ¡Sin embargo, AMQP, un protocolo estandarizado y ampliamente adoptado para la mensajería asincrónica tolerante a fallas, se comunica a través de TCP! ¿Lo que da?
El concepto central en juego aquí es que la mensajería escalable y poco tolerante a fallas se define por los mensajes que envía , no por cómo los envía . En otras palabras, el acoplamiento suelto se define en la capa de aplicación .
Veamos a dos partes que se comunican directamente con HTTP RESTful o indirectamente con un agente de mensajes AMQP. Supongamos que la Parte A desea cargar una imagen JPEG a la Parte B, que afinará, comprimirá o mejorará la imagen. La Parte A no necesita la imagen procesada de inmediato, pero requiere una referencia para su uso y recuperación en el futuro. Aquí hay una manera que podría ir en REST:
- La Parte A envía un
POST
mensaje de solicitud HTTP a la Parte B conContent-Type: image/jpeg
- La Parte B procesa la imagen (durante mucho tiempo si es grande) mientras la Parte A espera, posiblemente haciendo otras cosas
- La Parte B envía un
201 Created
mensaje de respuesta HTTP a la Parte A con un Content-Location: <url>
encabezado que enlaza con la imagen procesada
- La Parte A considera su trabajo realizado ya que ahora tiene una referencia a la imagen procesada
- En algún momento en el futuro, cuando la Parte A necesite la imagen procesada, la OBTENDRÁ usando el enlace del
Content-Location
encabezado anterior
El 201 Created
código de respuesta le dice a un cliente que no solo su solicitud fue exitosa, sino que también creó un nuevo recurso. En una respuesta 201, el Content-Location
encabezado es un enlace al recurso creado. Esto se especifica en RFC 7231 Secciones 6.3.2 y 3.1.4.2.
Ahora, veamos cómo funciona esta interacción sobre un hipotético protocolo RPC además de AMQP:
- La Parte A envía a un agente de mensajes AMQP (llámelo Messenger) un mensaje que contiene la imagen e instrucciones para enrutarla a la Parte B para su procesamiento, luego responde a la Parte A con una dirección de algún tipo para la imagen
- La fiesta A espera, posiblemente haciendo otras cosas
- Messenger envía el mensaje original de la Parte A a la Parte B
- La parte B procesa el mensaje
- La Parte B envía a Messenger un mensaje que contiene una dirección para la imagen procesada e instrucciones para enrutar ese mensaje a la Parte A
- Messenger envía a la Parte A el mensaje de la Parte B que contiene la dirección de la imagen procesada
- La Parte A considera su trabajo realizado ya que ahora tiene una referencia a la imagen procesada
- En algún momento en el futuro, cuando la Parte A necesite la imagen, recupera la imagen utilizando la dirección (posiblemente enviando mensajes a otra parte)
¿Ves el problema aquí? En ambos casos, la Parte A no puede obtener una dirección imagen hasta después de la Parte B procesa la imagen . Sin embargo, la Parte A no necesita la imagen de inmediato y, por todos los derechos, ¡no podría importarle menos si el procesamiento aún está terminado!
Podemos arreglar esto con bastante facilidad en el caso de AMQP haciendo que la Parte B le diga a A que B aceptó la imagen para procesarla, dándole a A una dirección de dónde estará la imagen después de que se complete el procesamiento. Luego, la Parte B puede enviar un mensaje a A en algún momento en el futuro indicando que el procesamiento de la imagen ha finalizado. Mensajería AMQP al rescate!
Excepto adivina qué: puedes lograr lo mismo con REST . En el ejemplo de AMQP, cambiamos el mensaje "aquí está la imagen procesada" a un mensaje "la imagen se está procesando, puede obtenerla más tarde". Para hacerlo en RESTful HTTP, usaremos el 202 Accepted
código y Content-Location
nuevamente:
- La Parte A envía un
POST
mensaje HTTP a la Parte B conContent-Type: image/jpeg
- La Parte B inmediatamente envía una
202 Accepted
respuesta que contiene algún tipo de contenido de "operación asincrónica" que describe si el procesamiento ha finalizado y dónde estará disponible la imagen cuando termine el procesamiento. También se incluye un Content-Location: <link>
encabezado que, en una 202 Accepted
respuesta, es un enlace al recurso representado por el cuerpo de la respuesta. ¡En este caso, eso significa que es un enlace a nuestra operación asincrónica!
- La Parte A considera su trabajo realizado ya que ahora tiene una referencia a la imagen procesada
- En algún momento en el futuro, cuando la Parte A necesite la imagen procesada, primero OBTENDRÁ el recurso de operación asíncrona vinculado al
Content-Location
encabezado para determinar si el procesamiento ha finalizado. Si es así, la Parte A luego usa el enlace en la operación asíncrona para OBTENER la imagen procesada.
La única diferencia aquí es que en el modelo AMQP, la Parte B le dice a la Parte A cuándo se realiza el procesamiento de la imagen. Pero en el modelo REST, la Parte A verifica si el procesamiento se realiza justo antes de que realmente necesite la imagen. Estos enfoques son igualmente escalables . A medida que el sistema se hace más grande, el número de mensajes enviados tanto en el AMQP asíncrono como en las estrategias REST asíncronas aumenta con una complejidad asintótica equivalente. La única diferencia es que el cliente está enviando un mensaje adicional en lugar del servidor.
Pero el enfoque REST tiene algunos trucos más bajo la manga: descubrimiento dinámico y negociación de protocolo . Considere cómo comenzaron las interacciones REST de sincronización y asíncrona. La Parte A envió exactamente la misma solicitud a la Parte B, y la única diferencia fue el tipo particular de mensaje de éxito con el que respondió la Parte B. ¿Qué pasaría si la Parte A quisiera elegir si el procesamiento de imágenes es sincrónico o asincrónico? ¿Qué sucede si la Parte A no sabe si la Parte B es incluso capaz de procesar de forma asíncrona?
Bueno, ¡HTTP ya tiene un protocolo estandarizado para esto! Se llama Preferencias HTTP, específicamente la respond-async
preferencia de RFC 7240 Sección 4.1. Si la Parte A desea una respuesta asincrónica, incluye un Prefer: respond-async
encabezado con su solicitud POST inicial. Si la Parte B decide honrar esta solicitud, envía una 202 Accepted
respuesta que incluye a Preference-Applied: respond-async
. De lo contrario, la Parte B simplemente ignora el Prefer
encabezado y lo devuelve 201 Created
como lo haría normalmente.
Esto permite a la Parte A negociar con el servidor, adaptándose dinámicamente a cualquier implementación de procesamiento de imagen con la que esté hablando. Además, el uso de enlaces explícitos significa que la Parte A no tiene que conocer a ninguna otra parte que no sea B: ningún agente de mensajes AMQP, ningún Parte M misterioso que sepa cómo convertir la dirección de la imagen en datos de imagen, ni un segundo B-Async parte si se deben realizar solicitudes síncronas y asíncronas, etc. Simplemente describe lo que necesita, lo que opcionalmente le gustaría, y luego reacciona a los códigos de estado, contenido de respuesta y enlaces. AñadirCache-Control
encabezados para obtener instrucciones explícitas sobre cuándo conservar copias locales de datos, y ahora los servidores pueden negociar con los clientes qué recursos pueden mantener las copias locales (¡o incluso fuera de línea!). Así es como se construyen microservicios tolerantes a fallas acoplados libremente en REST.
UserCreated
evento (por ejemplo, nombre de usuario duplicado o correo electrónico o interrupción de la base de datos)./users/
punto final, y permitir que el sistema publique su evento si tuvo éxito, y responder a la solicitud con la nueva entidadCon un sistema de origen de eventos, los aspectos asincrónicos normalmente entran en juego cuando se cambia algo que representa el estado, tal vez una base de datos o una vista agregada de algunos datos. Usando su ejemplo, una llamada a GET / api / users podría simplemente devolver la respuesta de un servicio que tiene una representación actualizada de una lista de usuarios en el sistema. En otro escenario, la solicitud a GET / api / users podría hacer que un servicio use la secuencia de eventos desde la última instantánea de los usuarios para crear otra instantánea y simplemente devolver los resultados. Un sistema controlado por eventos no es necesariamente puramente asíncrono desde la solicitud hasta la respuesta, sino que tiende a estar en el nivel en que los servicios deben interactuar con otros servicios. A menudo no tiene sentido devolver asincrónicamente una solicitud GET y, por lo tanto, simplemente puede devolver la respuesta de un servicio,
fuente