Organização de interação eficaz de microsserviços

Recentemente, as arquiteturas de microsserviço desfrutaram de alguma popularidade. O desempenho e a escalabilidade das soluções baseadas nelas podem depender de como os microsserviços interagem. Essa interação pode ser síncrona ou assíncrona. O material, cuja tradução apresentamos hoje à sua atenção, discute métodos síncronos para a interação de microsserviços. Nomeadamente, nos concentraremos no estudo de duas tecnologias: HTTP / 1.1 e gRPC. A primeira tecnologia é representada por chamadas HTTP padrão. O segundo é baseado no uso da estrutura RPC de alto desempenho do Google. O autor do artigo sugere analisar o código necessário para implementar a interação de microsserviços usando HTTP / 1.1 e gRPC, fazer medições de desempenho e escolher uma tecnologia que permita organizar da melhor maneira a troca de dados entre microsserviços.



Aplicação normal


Vamos começar pequenos e criar um sistema de dois microsserviços que podem interagir entre si. Observe que o modo de cluster não é usado aqui. Aqui está um diagrama de nossa aplicação.


Arquitetura típica de aplicativos

O aplicativo consiste nos seguintes componentes:

  • Ferramenta de Teste do Sistema: jMeter .
  • Serviço A: Um microsserviço que executa solicitações para o serviço B e retorna as respostas recebidas dele.
  • Serviço B (Serviço B): um microsserviço que envia dados JSON estáticos em resposta a solicitações após um atraso de 10 milissegundos usado para todas as suas APIs.
  • Máquinas virtuais (VM 1 e VM 2): instâncias do Amazon EC2 t2.xlarge.

▍HTTP / 1.1


O HTTP / 1.1 é uma tecnologia padrão para organizar a interação de microsserviços, usada ao usar bibliotecas HTTP como axios ou superagent .

Aqui está o código de serviço B que implementa a API do nosso sistema:

server.route({  method: 'GET',  path: '/',  handler: async (request, h) => {    const response = await new Promise((resolve) => {      setTimeout(() => {        resolve({          id: 1,          name: 'Abhinav Dhasmana',          enjoys_coding: true,        });      }, 10);    });    return h.response(response);  }, }); 

Aqui está o código do serviço A que acessa o serviço B usando HTTP / 1.1:

 server.route({ method: 'GET', path: '/', handler: async (request, h) => { try { const response = await Axios({ url: 'http://localhost:8001/', method: 'GET', }); return h.response(response.data); } catch (err) { throw Boom.clientTimeout(err); } }, }); 

Ao executar esses microsserviços, podemos tirar proveito do jMeter para executar testes de desempenho. Vamos descobrir como o sistema se comporta ao trabalhar com 50 usuários, cada um dos quais realiza 2000 solicitações. Como pode ser visto na figura a seguir, a mediana dos resultados da medição é de 37 ms.


Resultados de pesquisa de um sistema de modo normal usando HTTP / 1.1 usando jMeter

▍gRPC


O gRPC usa a tecnologia Buffers de Protocolo por padrão. Portanto, usando o gRPC, além do código de dois serviços, precisaremos escrever o código do arquivo proto, que descreve a interface entre os módulos do sistema.

 syntax = "proto3"; service SampleDataService { rpc GetSampleData (Empty) returns (SampleData) {} } message SampleData { int32 id = 1; string name = 2; bool enjoys_coding = 3; } message Empty {} 

Agora, como agora planejamos usar o gRPC, precisamos reescrever o código de serviço B:

 const grpc = require('grpc'); const proto = grpc.load('serviceB.proto'); const server = new grpc.Server(); const GetSampleData = (call, callback) => { setTimeout(() => {   callback(null, {     id: 1,     name: 'Abhinav Dhasmana',     enjoys_coding: true,   }); }, 10); }; server.addService(proto.SampleDataService.service, { GetSampleData, }); const port = process.env.PORT; console.log('port', port); server.bind(`0.0.0.0:${port}`, grpc.ServerCredentials.createInsecure()); server.start(); console.log('grpc server is running'); 

Preste atenção a alguns recursos deste código:

  • O comando const server = new grpc.Server(); criamos um servidor grpc.
  • server.addService(proto... comando server.addService(proto... adicionamos o serviço ao servidor.
  • O comando server.bind(`0.0.0.0:${port}... é usado para ligar a porta e as credenciais.

Agora reescreva o serviço A usando gRPC:

 const protoPath = `${__dirname}/../serviceB/serviceB.proto`; const proto = grpc.load(protoPath); const client = new proto.SampleDataService('localhost:8001', grpc.credentials.createInsecure()); const getDataViagRPC = () => new Promise((resolve, reject) => { client.GetSampleData({}, (err, response) => {   if (!response.err) {     resolve(response);   } else {     reject(err);   } }); }); server.route({ method: 'GET', path: '/', handler: async (request, h) => {   const allResults = await getDataViagRPC();   return h.response(allResults); }, }); 

Entre os recursos desse código estão os seguintes:

  • const client = new proto.SampleDataService... comando const client = new proto.SampleDataService... criamos um cliente grpc.
  • Uma chamada remota é feita usando o client.GetSampleData({}... .

Agora vamos testar o que obtivemos com o jMeter.


Resultados de pesquisa de um sistema de modo normal usando gRPC usando jMeter

Após cálculos simples, você pode descobrir que uma solução usando gRPC é 27% mais rápida que uma solução usando HTTP / 1.1.

Aplicativo de cluster


Aqui está um diagrama de um aplicativo semelhante ao que acabamos de pesquisar, mas trabalhando no modo de cluster.


Arquitetura de aplicativos no modo de cluster

Se você comparar essa arquitetura com a considerada anteriormente, as seguintes alterações poderão ser observadas:

  • Há um balanceador de carga (Load Balancer), que usa o NGINX .
  • O serviço B agora está presente em três instâncias que escutam em portas diferentes.

Uma arquitetura semelhante é típica para projetos reais.

Explorando HTTP / 1.1 e gRPC em um novo ambiente.

▍HTTP / 1.1


Ao usar microsserviços que usam HTTP / 1.1 em um ambiente em cluster, seu código não precisará ser alterado. Você só precisa configurar o nginx para organizar o balanceamento do tráfego do serviço B. No nosso caso, para fazer isso, você precisa trazer o arquivo /etc/nginx/sites-available/default para este formulário:

 upstream httpservers {  server ip_address:8001;  server ip_address:8002;  server ip_address:8003; } server {  listen 80;  location / {     proxy_pass http://httpservers;  } } 

Agora vamos executar o que temos e ver os resultados do teste do sistema usando o jMeter.


Resultados da pesquisa para um sistema baseado em cluster usando HTTP / 1.1 usando jMeter

A mediana neste caso é 41 ms.

▍gRPC


O suporte ao GRPC apareceu no nginx 1.13.10 . Portanto, precisamos da versão mais recente do nginx, para a instalação em que o comando sudo apt-get install nginx usual não é adequado.

Também aqui não usamos Node.js no modo de cluster , pois o gRPC não é suportado nesse modo.

Para instalar a versão mais recente do nginx, use a seguinte sequência de comandos:

 sudo apt-get install -y software-properties-common sudo add-apt-repository ppa:nginx/stable sudo apt-get update sudo apt-get install nginx 

Além disso, precisaremos de certificados SSL. Um certificado autoassinado pode ser criado usando o openSSL :

 openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \ -keyout localhost-privatekey.pem -out localhost-certificate.pem 

Para usar o gRPC, você precisa editar o arquivo / etc/nginx/sites-available/default :

 upstream httpservers {  server ip_address:8001;  server ip_address:8002;  server ip_address:8003; } server {  listen 80;  location / {     proxy_pass http://httpservers;  } } 

Agora tudo está pronto para testar a solução de gRPC de cluster usando o jMeter.


Resultados de um sistema em modo de cluster usando gRPC usando jMeter

Nesse caso, a mediana é de 28 ms, 31% mais rápida em comparação com o mesmo indicador obtido ao examinar uma solução HTTP / 1.1 em cluster.

Sumário


Os resultados do estudo mostram que um aplicativo baseado em microsserviço que usa gRPC é cerca de 30% mais produtivo do que um aplicativo semelhante que usa HTTP / 1.1 para trocar dados entre microsserviços. O código fonte dos projetos discutidos neste artigo pode ser encontrado aqui .

Caros leitores! Se você estiver desenvolvendo microsserviços, fale sobre como você organiza a troca de dados entre eles.

Source: https://habr.com/ru/post/pt421579/


All Articles