Repita depois de mim:
REST e eventos assíncronos não são alternativas. Eles são completamente ortogonais.
Você pode ter um, ou o outro, ou ambos, ou nenhum. São ferramentas totalmente diferentes para domínios de problemas completamente diferentes. De fato, a comunicação de solicitação-resposta de propósito geral é absolutamente capaz de ser assíncrona, orientada a eventos e tolerante a falhas .
Como um exemplo trivial, o protocolo AMQP envia mensagens através de uma conexão TCP. No TCP, todos os pacotes devem ser reconhecidos pelo destinatário . Se um remetente de um pacote não receber um ACK para esse pacote, ele continuará reenviando esse pacote até que seja ACK ou até que a camada de aplicativo "desista" e abandone a conexão. Este é claramente um modelo de solicitação-resposta não tolerante a falhas, porque cada "solicitação de envio de pacote" deve ter uma "resposta de confirmação de pacote" associada, e a falha em responder resulta na falha de toda a conexão. No entanto, o AMQP, um protocolo padronizado e amplamente adotado para mensagens tolerantes a falhas assíncronas, é comunicado através do TCP! O que da?
O conceito principal em jogo aqui é que o sistema de mensagens tolerante a falhas e escalável e com acoplamento fraco é definido por quais mensagens você envia , não por como as envia . Em outras palavras, o acoplamento flexível é definido na camada de aplicação .
Vejamos duas partes se comunicando diretamente com o RESTful HTTP ou indiretamente com um intermediário de mensagens AMQP. Suponha que a Parte A deseje fazer upload de uma imagem JPEG na Parte B, que irá afiar, compactar ou aprimorar a imagem. A Parte A não precisa da imagem processada imediatamente, mas exige uma referência a ela para uso e recuperação futuros. Aqui está uma maneira que pode ser usada no REST:
- A Parte A envia uma
POST
mensagem de solicitação HTTP para a Parte B comContent-Type: image/jpeg
- O Partido B processa a imagem (por muito tempo, se for grande) enquanto o Partido A espera, possivelmente fazendo outras coisas
- A parte B envia uma
201 Created
mensagem de resposta HTTP para a parte A com um Content-Location: <url>
cabeçalho vinculado à imagem processada
- A Parte A considera seu trabalho concluído, pois agora tem uma referência à imagem processada
- Em algum momento no futuro, quando a Parte A precisar da imagem processada, ela a obterá usando o link do
Content-Location
cabeçalho anterior
O 201 Created
código de resposta informa ao cliente que sua solicitação não apenas foi bem-sucedida, como também criou um novo recurso. Em uma resposta 201, o Content-Location
cabeçalho é um link para o recurso criado. Isso é especificado nas seções 6.3.2 e 3.1.4.2 da RFC 7231.
Agora, vamos ver como essa interação funciona em um protocolo RPC hipotético sobre o AMQP:
- A Parte A envia a um intermediário de mensagens AMQP (chame-a de Messenger) uma mensagem contendo a imagem e instruções para rotear para a Parte B para processamento e, em seguida, responda à Parte A com um endereço de algum tipo para a imagem
- O partido A espera, possivelmente fazendo outras coisas
- O Messenger envia a mensagem original do Partido A para o Partido B
- A parte B processa a mensagem
- A Parte B envia ao Messenger uma mensagem contendo um endereço para a imagem processada e instruções para rotear essa mensagem para a Parte A
- O Messenger envia à Parte A a mensagem da Parte B contendo o endereço da imagem processada
- A Parte A considera seu trabalho concluído, pois agora tem uma referência à imagem processada
- Em algum momento no futuro, quando a Parte A precisar da imagem, ela será recuperada usando o endereço (possivelmente enviando mensagens para outra parte)
Você vê o problema aqui? Em ambos os casos, Partido A não pode obter um endereço imagem até depois do partido B processa a imagem . No entanto, a Parte A não precisa da imagem imediatamente e, com todos os direitos, não se importava se o processamento ainda estivesse concluído!
Podemos corrigir isso com muita facilidade no caso AMQP, solicitando que a Parte B diga a A que B aceitou a imagem para processamento, fornecendo a A um endereço para onde a imagem estará após a conclusão do processamento. A Parte B pode enviar uma mensagem para A em algum momento no futuro, indicando que o processamento da imagem está concluído. Mensagens AMQP para o resgate!
Exceto adivinhe: você pode conseguir a mesma coisa com o REST . No exemplo do AMQP, alteramos uma mensagem "aqui está a imagem processada" para uma mensagem "a imagem está sendo processada, você pode obtê-la mais tarde". Para fazer isso no RESTful HTTP, usaremos o 202 Accepted
código Content-Location
novamente:
- A Parte A envia uma
POST
mensagem HTTP para a Parte B comContent-Type: image/jpeg
- A Parte B envia imediatamente uma
202 Accepted
resposta que contém algum tipo de conteúdo de "operação assíncrona" que descreve se o processamento está concluído e onde a imagem estará disponível quando terminar o processamento. Também está incluído um Content-Location: <link>
cabeçalho que, em uma 202 Accepted
resposta, é um link para o recurso representado por qualquer que seja o corpo da resposta. Nesse caso, isso significa que é um link para nossa operação assíncrona!
- A Parte A considera seu trabalho concluído, pois agora tem uma referência à imagem processada
- Em algum momento no futuro, quando a Parte A precisar da imagem processada, primeiro obtém o recurso de operação assíncrona vinculado ao
Content-Location
cabeçalho para determinar se o processamento foi concluído. Nesse caso, a Parte A usa o link na própria operação assíncrona para OBTER a imagem processada.
A única diferença aqui é que, no modelo AMQP, o Partido B informa ao Partido A quando o processamento da imagem é concluído. Porém, no modelo REST, a Parte A verifica se o processamento é realizado logo antes de realmente precisar da imagem. Essas abordagens são equivalentemente escaláveis . À medida que o sistema aumenta, o número de mensagens enviadas nas estratégias assíncrona AMQP e REST assíncrona aumenta com uma complexidade assintótica equivalente. A única diferença é que o cliente está enviando uma mensagem extra em vez do servidor.
Mas a abordagem REST tem mais alguns truques na manga: descoberta dinâmica e negociação de protocolo . Considere como as interações REST de sincronização e assíncrona começaram. A Parte A enviou exatamente o mesmo pedido à Parte B, com a única diferença sendo o tipo específico de mensagem de sucesso com a qual a Parte B respondeu. E se a Parte A quisesse escolher se o processamento da imagem era síncrono ou assíncrono? E se o Partido A não souber se o Partido B é capaz de processar assíncrono?
Bem, o HTTP já tem um protocolo padronizado para isso! Chama-se Preferências HTTP, especificamente a respond-async
preferência da Seção 4.1 da RFC 7240. Se a Parte A desejar uma resposta assíncrona, ela incluirá um Prefer: respond-async
cabeçalho com sua solicitação POST inicial. Se a Parte B decidir atender a essa solicitação, ela envia de volta uma 202 Accepted
resposta que inclui a Preference-Applied: respond-async
. Caso contrário, o Partido B simplesmente ignora o Prefer
cabeçalho e envia de volta 201 Created
como faria normalmente.
Isso permite que a Parte A negocie com o servidor, adaptando-se dinamicamente a qualquer implementação de processamento de imagem com a qual estiver falando. Além disso, o uso de links explícitos significa que a Parte A não precisa saber sobre nenhuma outra parte além de B: nenhum intermediário de mensagens AMQP, nenhum misterioso Parte C que sabe como transformar o endereço da imagem em dados de imagem, nenhum segundo B-Async participe se for necessário fazer solicitações síncronas e assíncronas etc. Ele simplesmente descreve o que precisa, do que seria opcional e, em seguida, reage aos códigos de status, ao conteúdo da resposta e aos links. Adicionar emCache-Control
cabeçalhos para obter instruções explícitas sobre quando manter cópias locais de dados e agora os servidores podem negociar com os clientes quais recursos os clientes podem manter cópias locais (ou até offline!). É assim que você cria microsserviços tolerantes a falhas com pouco acoplamento no REST.
UserCreated
evento (por exemplo, nome de usuário duplicado ou falha de email ou banco de dados)./users/
endpoint, e permitir que o sistema para publicar o seu evento se ele conseguiu, e responder ao pedido com a nova entidadeCom um sistema de origem de eventos, os aspectos assíncronos normalmente entram em jogo quando algo que representa estado, talvez um banco de dados ou uma visão agregada de alguns dados, é alterado. Usando seu exemplo, uma chamada para GET / api / users pode simplesmente retornar a resposta de um serviço que possui uma representação atualizada de uma lista de usuários no sistema. Em outro cenário, a solicitação para GET / api / users pode fazer com que um serviço use o fluxo de eventos desde a última captura instantânea de usuários para criar outra captura instantânea e simplesmente retornar os resultados. Um sistema orientado a eventos não é necessariamente puramente assíncrono de Solicitação para Resposta, mas tende a estar no nível em que os serviços precisam interagir com outros serviços. Muitas vezes, não faz sentido retornar de forma assíncrona uma solicitação GET e, portanto, você pode simplesmente retornar a resposta de um serviço,
fonte