Voltar
Engineering
Tabela de conteúdo

 

Há uma proliferação de linguagens de programação modernas agora mais do que nunca. No entanto, as organizações de desenvolvimento tendem a se ater a uma ou duas linguagens, o que lhes permite gerenciar sua pilha adequadamente e mantê-la limpa.

As linguagens de programação são ferramentas essenciais que, se não forem escolhidas adequadamente, podem ter um efeito paralisante nos negócios. Por exemplo, os desenvolvedores preferem Python em vez de Java para configurar algoritmos de aprendizado de máquina, porque o Python tem bibliotecas melhores necessárias para aplicativos de aprendizado de máquina e inteligência artificial.

Cada idioma tem um conjunto específico de recursos e propriedades. Por exemplo, alguns idiomas são mais rápidos do que outros, mas podem levar algum tempo para serem escritos. Algumas linguagens consomem mais recursos e, ainda assim, aceleram o desenvolvimento. E há outras linguagens que estão no meio.

Microservice multilingual

Construindo uma arquitetura de microsserviço independente de linguagem

Embora não seja muito comum, uma arquitetura de microsserviço pode ser criada para se adequar a vários idiomas. Ele oferece aos desenvolvedores a liberdade de escolher a ferramenta certa para suas tarefas. Na fase final do ciclo de vida de desenvolvimento de software, se o Docker puder implantar contêineres independentemente de sua linguagem, sua arquitetura também poderá ser replicada nos estágios iniciais da criação de microsserviços.

No entanto, gerenciar vários idiomas pode ser uma tarefa enorme e um desenvolvedor definitivamente deve considerar os seguintes aspectos ao planejar adicionar mais linguagens à sua pilha de tecnologia:

  • Novo código da placa de caldeira,
  • Definindo modelos/estruturas de dados novamente,
  • Documentação,
  • O ambiente em que trabalha,
  • Nova estrutura, etc.

 

Por que a API RESTful não é a escolha certa

A API REST exige uma nova estrutura para cada nova linguagem, como Express for Node.js, Flask for Python ou Gin for Go. Além disso, o desenvolvedor pode ter que codificar seus modelos/estruturas de dados repetidamente para cada serviço. Isso torna todo o processo redundante e pode resultar em vários erros.

Por exemplo, é muito comum ter um modelo de banco de dados para vários serviços. Mas, quando o banco de dados é atualizado, ele precisa passar por alterações para cada serviço. Para criar um microsserviço multilíngue, precisamos de uma estrutura comum que ofereça suporte a vários idiomas e plataformas e que seja escalável.

 

Abra caminho para gRPC e buffers de protocolo

gRPC 

O gRPC é a estrutura de chamadas de procedimentos remotos de código aberto e de alto desempenho do Google. É compatível com várias linguagens, como Go, Node.js, Python, Java, C-Sharp e muitas outras. Ele usa RPC para fornecer recursos de comunicação para microsserviços. Além disso, é uma alternativa melhor ao REST. O gRPC é muito mais rápido que o REST. E essa estrutura usa buffers de protocolo como linguagem de definição de interface para serialização e comunicação em vez de JSON/XML. Ele funciona com base na comunicação servidor-cliente.

Uma análise aprofundada do gRPC é fornecida aqui.

 

Buffers de protocolo 

Buffers de protocolo são um método de serializar dados que podem ser transmitidos por fio ou armazenados em arquivos. Resumindo, buffer de protocolo ou Protobuf é o mesmo que o JSON é em relação ao REST. É uma alternativa ao JSON/XML, embora menor e mais rápida. O Protobuf define serviços e outros dados e, em seguida, é compilado em vários idiomas. A estrutura gRPC é então usada para criar um serviço.

O gRPC usa o protocolo de transferência mais recente — HTTP/2, que oferece suporte à comunicação bidirecional junto com a solicitação/resposta tradicional. No gRPC, o servidor está vagamente acoplado ao cliente. Na prática, o cliente abre uma conexão de longa duração com o servidor gRPC e um novo fluxo HTTP/2 será aberto para cada chamada RPC.

 

Como usamos o Protobuf?

Primeiro definimos nosso serviço no Protobuf e o compilamos em qualquer idioma. Em seguida, usamos os arquivos compilados para criar nossa estrutura gRPC para criar nosso servidor e cliente, conforme mostrado no diagrama abaixo.

Protobuffers for microservices

Para explicar o processo:

  1. Definir um serviço usando buffers de protocolo
  2. Compile esse serviço em outros idiomas conforme sua escolha
  3. Gere código clichê em cada idioma
  4. Use isso para criar servidores e clientes gRPC

 

Vantagens de usar essa arquitetura:

  • Você pode usar vários idiomas com uma única estrutura.
  • Definição única em todos os serviços, o que é muito útil em uma organização.
  • Qualquer cliente pode se comunicar com qualquer servidor, independentemente do idioma.
  • O gRPC permite comunicação bidirecional e usa HTTP/2, que é muito rápido.

 

Criando um microsserviço com gRPC

Vamos criar um microsserviço simples — Serviço Hello World. Este é um serviço muito básico que invoca apenas um método — HelloWorld — que retornaria a string”Olá mundo”.

Estas são as 4 etapas a serem seguidas ao criar um microsserviço:

  1. Defina o serviço (arquivo de buffer de protocolo)
  2. Selecione seus idiomas
  3. Compilar o serviço definido em idiomas selecionados
  4. Crie um servidor e um cliente gRPC usando os arquivos compilados

Para esse serviço simples, estamos optando por 2 idiomas: Go e Node.js. Como o gRPC funciona em uma arquitetura cliente-servidor, usaremos Go no servidor (já que é rápido e eficiente em termos de recursos) e Node.js para clientes (já que a maioria dos aplicativos atualmente são React/Angular).

**Também é possível decidir executar servidores gRPC com a API REST, se não quiser criar clientes. Eles podem fazer isso criando um servidor proxy REST. Embora pareça trabalhoso, na verdade é muito simples e será tratado na seção 'Compilação' que se seguirá.

 

Etapa 1: Definindo um serviço

Mensagens e serviços são definidos usando Protobuf em um arquivo proto (.proto arquivo).

A sintaxe é bem simples; as mensagens são definidas e usadas como Solicitação e Resposta para as chamadas RPC, para cada serviço. Aqui está um guia de idiomas para buffers de protocolo.

Podemos criar uma nova pasta para cada serviço com o nome desse serviço específico. E, para facilitar a acessibilidade, podemos armazenar todos esses serviços na pasta “serviços”.

O serviço que estamos definindo aqui é “helloworld”. E cada pasta deve conter 2 arquivos, a saber:

  • service.proto — contém definição
  • .protolangs — contém os idiomas nos quais esse serviço deve ser gerado.

 

Services folder
Estrutura de pastas

Agora, vamos definir nosso serviço:

gRPC hello world

 

Conforme mostrado acima, definimos uma Solicitação vazia, uma string Response e um HelloWorldService com uma única chamada RPC HelloWorld. Essa chamada aceita solicitações e retorna respostas. Você pode ver o repositório completo aqui.

 

Etapa 2: Selecionar idiomas

Depois que o serviço for definido, teremos que escolher os idiomas nos quais compilar os serviços. Essa escolha é feita com base nos requisitos e no uso do serviço, além do conforto do desenvolvedor. Os diferentes idiomas que se pode escolher são Go, Node.js, Python, Java, C, C#, Ruby, Scala, PHP, etc. Conforme mencionado anteriormente, neste exemplo, usaremos Go e Node.js. Em seguida, adicionaremos esses idiomas ao arquivo.protolangs, mencionando cada idioma em uma nova linha.

adding languages for microservices

 

Etapa 3: Compilação

Compilar é a parte mais interessante de todo esse processo. Na etapa 3, compilaremos o arquivo.proto nos idiomas selecionados, Go e Node.js.

O buffer de protocolo vem com uma ferramenta de linha de comando chamada “protoc”, que compila a definição do serviço para uso. Mas para cada idioma, teremos que baixar e instalar plugins. Isso pode ser feito usando um dockerfile.

Ou seja, é um arquivo docker que inclui tudo isso e está disponível para todos. Ele tem o “proto compilador” com suporte para todas as linguagens e recursos adicionais, como documentação, validador e até mesmo um servidor proxy REST, sobre o qual falamos na etapa 1.

Por exemplo,

$ docker run -v `pwd`: /defs ou seja, protoc-all -f myproto.proto -l ruby

Ele aceita um arquivo.proto e linguagem, ambos os quais já temos. A seguir está um script bash simples que percorrerá nossa pasta de serviços e selecionará o arquivo service.proto para compilar nos idiomas do arquivo.protolangs.

#! /bin/bash echo “Começando... “ conjunto x repo="`PWD`/repo” função enterDir { echo “Inserindo $1" empurrou $1 > /dev/null } função leaveDir { echo “Saindo” popd > /dev/null } função ComplieProto { para dir em */; do se; então enquanto lê lang; do target=$ {dir%/*} mkdir -p $repo/$lang rm -rf $repo/$lang/$target mkdir -p $repo/$lang/$target mkdir -p $repo/$lang/$target/doc echo "Compilando para $lang” docker run -v `pwd`: /defs ou seja, protoc-all -f $target/service.proto -l $lang --with-docs --lint $ (&& echo “--with-typescript” || echo “--with-validator”) cp -R gen/pb-$lang/$target/* $repo/$lang/$target cp -R gen/pb-$lang/doc/* $repo/$lang/$target/doc geração sudo rm -rf feito < $dir/.protolangs se concluído } função compile { echo “Iniciando a construção” mkdir -p $ REPO para dir em services/; do Digite Dir $dir Compilar Proto para $dir Deixar IR concluído } compilar

 

  • Os scripts executam um loop para cada pasta no /serviços.
  • Em seguida, ele pega o .protolangs arquivo e os repete novamente com cada um dos idiomas escritos na pasta.
  • Em seguida, compila service.proto com o idioma.
  • O docker gera os arquivos na pasta gen/pb- {language}.
  • Simplesmente copiamos o conteúdo para a pasta repos/ {language}/{servicename}.

Em seguida, executamos o script:

$ chmod +x generate.sh

$. /genetare.sh

O arquivo gerado aparece na /repositórios pasta.

Dica: você pode hospedar essas definições em um repositório e usar o script gerado em um pipeline de CI/CD para automatizar esse processo.

Microservice node file

O service_pb gerado com sucesso para Node.js e Go, junto com alguns documentos e validadores, constitui o código padrão para nosso servidor e clientes que estamos prestes a criar.

**Conforme discutido anteriormente, se você não quiser usar o cliente e quiser APIs REST-JSON em vez disso, você pode criar um proxy REST adicionando uma única tag no a saber, /protoc-all dockerfile, ou seja, — com gateway. Para isso, teremos que adicionar caminhos de API em nossos protofiles. Dê uma olhada em isso para obter mais informações. Agora, execute esse gateway e o servidor proxy REST estará pronto para servir o servidor gRPC.

 

Dica: você também pode hospedar esse protorepo no github como um repositório. Você pode ter um único repositório para todas as definições em sua organização, da mesma forma que o Google.

 

Etapa 4: servidor e cliente gRPC

Agora que temos o código service_pb para Go e Node.js, podemos usá-lo para criar um servidor e um cliente. Para cada idioma, o código será um pouco diferente, devido às diferenças nos idiomas. Mas o conceito continuará o mesmo.

Para servidores: teremos que implementar funções de RPC.

Para clientes: teremos que chamar as funções RPC.

 

Você pode ver o código gRPC para todos os idiomas aqui. Com apenas algumas linhas de código, podemos criar um servidor e, com menos linhas de código, podemos criar um cliente.

 

Servidor (Go):
pacote principal importar ( “contexto” “fmt” “registro” “rede” helloworld “github.com/rohan-luthra/service-helloworld-go/helloworld” “google.golang.org/grpc” ) tipo de estrutura de servidor { } func (*servidor) helloWorld (ctx context.context, solicitação *helloworld.request) (*helloworld.response, erro) { resposta: = &helloworld.response { Mensagem: “hello world from go grpc”, } resposta de retorno, nula } func main () { endereço: = “0.0.0. 0:50051” lis, err: = net.listen (“tcp”, endereço) se errar! = zero { log.fatalf (“Erro %v”, erro) } fmt.Printf (“O servidor está escutando em %v... “, endereço) s: = gRPC.newServer () helloworld.registerHelloWorldServidor (es) de serviço e servidor {}) S.serve (lista) }

 

 

 

Como você pode ver, importamos o service.pb.go que foi gerado pelo nosso script de shell. Em seguida, implementamos a função helloWorld — que retorna a resposta “hello world from go grpc”. Criando assim um servidor gRPC.

 

Cliente (Node.js):
var helloword = exigir ('. /helloworld/service_pb '); var services = require ('. /helloworld/service_grpc_pb '); var grpc = exigir ('grpc'); função main () { var client = novo services.HelloWorldServiceClient ('localhost: 50051', gRPC.credentials.createInsecure ()); solicitação var = novo HelloWord.request (); var usuário; if (process.argv.length >= 3) { usuário = process.argv [2]; } senão { usuário = 'mundo'; } client.helloWorld (solicitação, função (erro, resposta) { if (err) console.log ('Erro do cliente Node: ', err) else console.log ('Mensagem do cliente Node: ', response.getMessage ()); }); } principal ();

 

Nós importamos o arquivo service_pb.js que foi gerado pelo nosso script shell. Adicione o endereço do servidor gRPC e chame a função HelloWorld e a resposta de saída para o console.

 

Teste o código

Execute o servidor e verifique se o código funciona.

Testing code Microservice

Agora que nosso servidor está em execução, vamos fazer uma chamada do nosso cliente Node.js:

Testing Node.js

*Ignore o aviso.

 

Quando recebemos a saída do console “hello world from go grpc”, podemos concluir que tudo funcionou conforme o esperado.

Assim, criamos com sucesso um servidor e cliente gRPC com uma única definição de proto e um script de shell. Esse foi um exemplo simples de uma chamada RPC retornando um texto “hello world”. Mas você pode fazer quase tudo com isso. Por exemplo, você pode criar um microsserviço CRUD que executa chamadas de adição, obtenção, atualização de RPC ou uma operação de sua escolha. Você só precisa defini-lo uma vez e executar o shell script. Você também pode ligar para um serviço de outro, criando clientes onde quiser ou em qualquer idioma que desejar. Esse é um exemplo de arquitetura de microsserviço perfeita.

 

Resumo

Espero que este blog tenha ajudado você a criar uma arquitetura de microsserviço apenas com buffers de protocolo, gRPC, um arquivo docker e um script de shell. Essa arquitetura é independente de linguagem, o que significa que ela se adapta a várias linguagens de programação. Além disso, é quase 7 vezes mais rápido que o servidor REST tradicional, com benefícios adicionais de documentação e validações.

Além de a arquitetura ser independente da linguagem, ela permite que você gerencie todas as estruturas de dados em sua organização em um único repositório, o que pode ser um divisor de águas. Os buffers de protocolo também suportam importação, herança, tags, etc.

Você só precisa seguir estas etapas ao criar um novo microsserviço:

  1. Defina seu serviço
  2. Selecionar idiomas
  3. Compilar, ou seja, executar o script de shell (automatizado — pode ser feito no pipeline de CI/CD)
  4. Finalmente, codifique seus servidores e clientes.
  5. Implante como quiser (sugestão: use contêineres docker)

Agora você está equipado para criar vários microsserviços, ativar a comunicação entre microsserviços ou simplesmente usá-los como estão e também adicionar uma camada de proxy REST para criar APIs. Lembre-se de que todos os serviços usam uma única estrutura, independentemente da linguagem de programação.

Você pode encontrar todo o repositório de código aqui.

 

Bônus:

Você também pode publicar os arquivos proto gerados de um serviço como pacotes para cada idioma, por exemplo, Node.js — npm, Python — pip, golang — GitHub, Java — Maven e assim por diante. Corra”npm install helloworld-proto para chamar os arquivos.pb. E se alguém atualizar a definição do Proto, basta executar”atualização npm helloworld-proto”.

Nenhum item encontrado.

Blogs relacionados