fbpx
gRPC no ASP.NET Core – Guia Introdutório
Publicado em: quarta-feira, 12 de jun de 2019
Tags: gRPC

Há inúmeros bons argumentos para deixarmos de usar HTTP + JSON para boa parte de nossos serviços, gRPC é uma boa alternativa a esse modelo. Cross platform, Open Source e Universal, gRPC foi originalmente desenvolvido pelo google agora é parte da CNCF, Cloud Native Computer Foundation.

Afinal pra que pensar em algo diferente de http?

O primeiro ponto a se ressaltar é que não estamos de fato abandonando o HTTP, estamos trocando de HTTP 1.1 para HTTP 2, que por sua vez tem alguns benefícios incríveis como os conexões multiplexadas.

Isso quer dizer que a conexão http que antigamente atendida a um request e um response por vez, agora trabalha de forma bidirecional, recebendo várias requisições, respondendo várias requisições, permitindo comunicação bidirecional. Resumindo de forma bem simplista: Ambos os lados esperam requisições um do outro, o tempo todo, em uma só conexão.

Vamos ilustrar isso? Trouxe algumas imagens do google para falar de http 1.1 e http 2:

O HTTP2 está aí faz algum tempo, mas todas nossas API’s continuavam sob a perspectiva HTTP 1.1.

Mas gRPC não é somente usar nossas API’s sob HTTP2, gRPC é um framework completo, como veremos no texto gRPC Motivation and Design Principles.

gRPC Motivation and Design Principles

No texto gRPC Motivation and Design Principles temos as motivações e requisitos para a criação do gRPC. Abaixo traduzi a motivação e apenas listei os princípios, o texto original merece atenção.

Motivação

O Google tem usado uma única infra-estrutura RPC de propósito geral chamada Stubby para conectar o grande número de microsserviços em execução em nossos datacenters por mais de uma década. Nossos sistemas internos há muito tempo adotaram a arquitetura de microsserviço que está ganhando popularidade hoje. Ter uma infra-estrutura RPC uniforme e compatível com várias plataformas permitiu a implementação de melhorias em toda a cadeia em eficiência, segurança, confiabilidade e análise comportamental essenciais para suportar o incrível crescimento observado naquele período. O Stubby tem muitos recursos excelentes – no entanto, ele não é baseado em nenhum padrão e está muito associado à nossa infraestrutura interna para ser considerado adequado para divulgação pública. Com o advento do SPDY, HTTP / 2 e QUIC, muitos desses mesmos recursos apareceram em padrões públicos, junto com outros recursos que o Stubby não fornece. Ficou claro que era hora de refazer o Stubby para aproveitar essa padronização e estender sua aplicabilidade aos casos de uso móveis, IoT e Cloud.

Princípios e Requisitos

  • Services not Objects, Messages not References
  • Coverage & Simplicity
  • Free & Open
  • Interoperability & Reach
  • General Purpose & Performant
  • Layered
  • Payload Agnostic
  • Streaming
  • Blocking & Non-Blocking
  • Cancellation & Timeout
  • Lameducking
  • Flow-Control
  • Pluggable
  • Extensions as APIs
  • Metadata Exchange
  • Standardized Status Codes

Todos esses elementos são bem detalhados no texto original. Bruno Brito traduziu esse texto no post gRPC em seu blog.

Mas afinal, o que vem a ser RPC?

Eu até poderia trazer uma parte do texto da wikipedia, mas preferi referenciá-lo pois tem muita informação e acho que é relevante para quem está sendo introduzido a esse assunto pela primeira vez. Leia esse texto na Wikipedia. Vou me basear nos termos e exemplos dele.

E gRPC?

gRPC é um RPC framework, uma implementação de RPC desenvolvido pela Google, usado em larga escala no próprio google (internamente) e em alguns serviços externos, inclusive DialogFlow, seu serviço de NLP.

Features

Com um design simples e fácil de usar, gRPC entrega muito background a custo baixíssimo no desenvolvimento:

  • Serialização Eficiente, Binária e Multiplataforma: Protobuf, outro projeto google, é alicerce do gRPC. Ele oferece um modelo de contrato e serialização multiplataforma, fácil para desenvolver, fácil para manter.
  • Poliglota: São mais de 10 linguagens suportadas, e esse número continua crescendo. Isso quer dizer que diferente de tecnologias proprietárias, como WCF, você tem todas as features disponíveis para todas as linguagens por default.
  • Otimizada para performance e escala: Serialização binária, protocolo mutiplexado.
  • Tooling garante compliance com as principais tecnologias.
  • Streaming bidirecional: Essa é uma feature das mais loucas (assista esse vídeo)

Transporte

Pra transporte usa-se HTTP2, que difere muito de HTTP1.1 ou HTTP 1.2. O HTTP 2 possui um canal multiplexado que permite comunicação bidirecional. Isso dá outros poderes à implementação de RPC, como as streams. Vale lembrar que HTTP2 é uma evolução do SPDY, da Google (aqui temos um belo overview sobre a história do SPDY e HTTP2).

Serialização

Pra serialização a Google optou por um projeto que ela mesma mantém: o Protobuf – Protocol Buffers. Uma alternativa muito mais eficiente para serialização, concorrendo com BSON, JSON e XML.

Contratos

Os contratos no gRPC são baseados em arquivos .proto, eles expressam a assinatura de todos os métodos das api’s, seguindo o standard do Protobuf que definem o contrato dos serviços, você pode ler a documentação completa do formato aqui.

  • Nesse arquivo, começamos definindo a versão do protobuf
  • Importamos outros tipos padrão (tem uma listagem) e outros arquivos .proto
  • O próximo passo é definir o nome do pacote
  • Definimos nossos serviços e mensagens
    • Os services são os serviços
    • As mensagens são os requests e responses que usaremos
    • Mensagens podem ser compostas por outras mensagens, como é o caso do Selector (definido no arquivo).

Tooling

gRPC está disponível para mais de 10 linguagens e uma delas é C#. Além disso o template que está sendo embarcado no Visual Studio 2019 já traz consigo tudo que é necessário para hospedar e consumir serviços gRPC.

Nesse caso, na hora em que salvamos nossos .proto, toda a geração de código acontece, em um projeto server, ele gera os serviços, no client um proxy para esses serviços.

Os .proto precisam estar presentes tanto no cliente quanto no servidor. O processo de geração de código gera em um projeto Server o serviço, enquanto no Client um client para gRPC. Mas lembre-se, cada projeto tem seu .proto, portanto compartilhar e sincronizar esses arquivos é relevante, principalmente entre times.

Mas tem uma estratégia legal, usada pela Spotify, vou abordar esse tema na live do dia 25.

Server/Hosting

Do lado de quem hospeda um serviço gRPC, os serviços são gerados automaticamente como classes abstratas, e nós devemos implementá-las, sobrescrevendo os métodos que já foram criados pelo processo de geração de código. Lembra do arquivo .proto? É nele que você define a assinatura e ao salvar a geração de código produz os artefatos.

O próprio template de projeto do Visual Studio já cuida de criar para você um serviço Dummy, configurado. Você só tem o trabalho de customizar. Isso ajuda muito a entender como os pontos se conectam.

Client

Da mesma forma que você precisa usar um .proto para criar um serviço, você precisa do mesmo .proto para consumir um serviço gRPC diretamente. Os arquivos .proto do server e do client são necessariamente idênticos ou até os mesmos #ficaDica.

Hoje nem é dia de polêmica a respeito, não só da qualidade dessa estratégia, nem se isso é bom, se isso é ruim, se há workarounds… O que eu posso dizer por hora é: Vamos entender gRPC, depois discutir sobre gRPC.

Aliás temos 2 versões de gRPC para .NET Core! Fique atento!

Vale lembrar que estamos falando da 2° implementação de gRPC no .NET Core, essa implementação guiada pela Microsoft trabalha sob o Kestrel, que ganha suporte a HTTP2 agora na versão 3.0 do .NET Core. Isso quer dizer que quer hospedar gRPC Services em um projeto .NET Core de versão inferior a 3.0, você precisa usar o outro modelo, que NÃO estou abordando nesse post.

As documentações do gRPC C# e ASP.NET Core gRPC Services são diferentes.
A implementação original segue um modelo de hosting próprio enquanto a documentação sob o ASP.NET utiliza o Kestrel como Web Server.

Não seria melhor esperar gRPC ficar maduro?

Na verdade eu não estou com o modo hype ligado não! O ponto é que se você acompanha esse blog, deve ter visto mergulhos rasos ao abordar gRPC. É um projeto que estou de olho desde 2016/2017. De fato o projeto me encantou desde os primeiros minutos em que me deparei com ele, mas eu sinceramente não gostava da forma como ele havia sido implementado para .NET Standard. Sinceramente eu achei frágil, não tão integrado quanto eu esperaria de uma solução do gênero.

Eu estava aguardando gRPC faz pelo menos 2 anos, mas somente agora, me senti confiante para usá-lo. E estou tendo ótimos resultados.

gRPC é super maduro, no entanto acabamos de ganhar uma segunda implementação para .NET Standard e como qualquer nova implementação, possui seus riscos até alcance a maturidade de GA.

Exemplos:

Por fim, me encaminhando para o encerramento do post, vou mostrar algumas coisas legais, para dar clareza sobre como as coisas funcionam.

O primeiro ponto é que para hospedar um serviço gRPC basta seguir o processo de criação de um projeto ASP.NET Core, e na opção de tipo de projeto tem um tipo que é o ASP.NET gRPC Services.

Como sempre eu estou usando uma versão preview do Visual Studio, mais especificamente Visual Studo 2019 16.2.0 preview 1. Como qualquer versão preview, tudo pode mudar.

Já do ponto de vista de quem consome, você precisa adicionar algumas referências e fazer algumas configurações. Vou mostrar em linhas gerais os principais arquivos.

Contrato

Esse é um arquivo .proto de um serviço que estou construindo. Eu tenho esse arquivo no client e no server.

syntax = "proto3";

import "google/protobuf/empty.proto";
import "google/protobuf/duration.proto";

package HandShake;

service WebDriverWorker {

  rpc Init (InitRequest) returns (google.protobuf.Empty) {}
  
  rpc GetScreenshot (google.protobuf.Empty) returns (Feedback) {}
  
  rpc NavigateToUrl (NavigateToUrlRequest) returns (google.protobuf.Empty) {}
  rpc NavigateBack (google.protobuf.Empty) returns (google.protobuf.Empty) {}
  rpc NavigateForward (google.protobuf.Empty) returns (google.protobuf.Empty) {}
  rpc NavigateRefresh (google.protobuf.Empty) returns (google.protobuf.Empty) {}

  rpc Click (Selector) returns (google.protobuf.Empty) {}
  rpc SendKeys (SendKeysRequest) returns (google.protobuf.Empty) {}

  rpc Shutdown (google.protobuf.Empty) returns (google.protobuf.Empty) {}
}

////////////////////////////////
// SHARED
////////////////////////////////
enum Browser {
	Chrome = 0;
	Firefox = 1;	
}

message Selector {
	oneof selectorExpressio{
		string id = 1;
		string linkText = 2;
		string name = 3;
		string xPath = 4;
		string className = 5;
		string partialLinkText = 6;
		string tagName = 7;
		string cssSelector = 8;
	}
	google.protobuf.Duration waitCycle = 9;
	int32 maxAttemps = 10;
}

message SendKeysRequest{
	Selector selector = 1;
	string text = 2;
}

////////////////////////////////
// Request / Response
////////////////////////////////

// The request message containing the user's name.
message InitRequest {
  Browser driverType = 1;
}

// The response message containing the greetings.
message Feedback {  
  bytes screenshot = 1;
  map<string, string> data = 2;
}

message NavigateToUrlRequest{
	string url = 1;
}

 

Hosting

CSPROJ

Este é um típico CSPROJ para hospedar serviços gRPC. Você não precisa editar teu CSPROJ, eu editei para usar wildcard “*.proto” no diretório para evitar que o visual studio criasse uma entrada para cada arquivo.

Novo Startup.cs

Do ponto de vista hospedagem do serviço, temos de levar em conta as mudanças do Startup.cs, e o que o gRPC precisa. O Startup.cs foi alterado no .NET Core 3, o gRPC só entra nesse novo formato. Por isso é muito importante

 

public class Startup
{

    public void ConfigureServices(IServiceCollection services)
    {
        ...

        services.AddGrpc(options => {
            options.EnableDetailedErrors = true;
            options.ReceiveMaxMessageSize = 1 * 1024 * 1024; // 1 megabytes; 
            options.SendMaxMessageSize    = 5 * 1024 * 1024; // 5 megabytes;
            options.ResponseCompressionLevel = System.IO.Compression.CompressionLevel.Optimal;
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGrpcService<WebDriverWorkerService>();
        });
    }

}

 

Não se assuste, essas mudanças já vem no projeto default.

Client

Já no client, não há nada entregue pelo visual studio, portanto temos de abrir o nosso csproj e fazer algumas mudanças, como vemos no exemplo do CSPROJ do client, abaixo:

Eu tive de adicionar essas mudanças na mão. Isso ainda não está claro, sobre como ficará essa integração quando a versão final (do ASP.NET Core 3.0) estiver pronta.

Esse projeto é um console de teste. Onde uso como playground, onde valido algumas coisas, faço testes de outras, entendo como funciona. É assim, em caráter exploratório que começo minha imersão. Com calma vou estruturando cada parte, de conhecimento e do código, na medido que a compreendo melhor.

public class Program
{
    public static async Task Main(string[] args)
    {
        var empty = new Google.Protobuf.WellKnownTypes.Empty();

        Thread.Sleep(TimeSpan.FromSeconds(10));

        var channel = new Channel("poltys.worker:80", ChannelCredentials.Insecure, new[] {
            new ChannelOption(ChannelOptions.MaxReceiveMessageLength , 5*1024*1024),
            new ChannelOption(ChannelOptions.MaxSendMessageLength , 1*1024*1024)
        });

        var client = new WebDriverWorker.WebDriverWorkerClient(channel);

        client.Init(new InitRequest { DriverType = Browser.Chrome });

        client.Shutdown(empty);

        await channel.ShutdownAsync();

    }
}

 

Pontos de atenção

Documentação

A documentação ainda está sendo criada, ajudei em algumas modificações, mas ainda falta deixar claro como as coisas funcionam. Uma das demandas que tive era por alterar os limites de envio e recebimento e enviei um pull request gRPC channel config set limits #12539 para a documentação, adicionando alguns elementos de configuração que havia descoberto olhando o código do projeto.

O ponto a ser lembrado é que client envia, server recebe e quando você trabalha com limites de dados diferente entre client e server, você terá problemas. Assim esse PR ajuda a melhorar a página gRPC para configuração do ASP.NET Core, mas está longe de ter o disclaimer que considero necessário:

É preciso casar, capacidade de envio do client, com capacidade de recebimento do server.

Da mesma forma que é necessário casar capacidade de envio do server com capacidade do recebimento do client.

Abaixo temos um código de exemplo:

//Cliente
var channel = new Channel("poltys.worker:80", ChannelCredentials.Insecure, new[] {
    new ChannelOption(ChannelOptions.MaxReceiveMessageLength , 5 * 1024 * 1024), // 5 megabytes
    new ChannelOption(ChannelOptions.MaxSendMessageLength ,    1 * 1024 * 1024), // 1 megabyte
});

//Servidor
services.AddGrpc(options => {
   ...
    options.ReceiveMaxMessageSize   = 1 * 1024 * 1024; // 1 megabyte
    options.SendMaxMessageSize      = 5 * 1024 * 1024; // 5 megabytes
   ...
});

Note que os nomes são similares mas não idênticos:

ChannelOptions.MaxReceiveMessageLength vs options.ReceiveMaxMessageSize

ChannelOptions.MaxSendMessageLength vs options.SendMaxMessageSize

No meu caso eu só precisei aumentar o dado que vem do servidor para o cliente, pois um dos métodos do serviço é a obtenção de um screenshot de página inteira.

Nesse exemplo o client envia até 1MB e recebe até 5MB. Já o server recebe até 1MB e envia até 5MB.

Web Servers, Load Balancers, Proxyes Reversos, API Gateways e API managers

Embora HTTP2 esteja aí faz um tempinho, nem todo mundo ou nem todas as versões de todos os webservers, proxy reversos, ou load balancers suportam HTTP2. Há bons desafios envolvendo isso.

Eu aconselho, não só por conta do gRPC ou suporte a HTTP2, você a dar uma olhada no Envoy.

Vou mudar todos os meus serviços para gRPC amanhã! Isso é uma boa ideia?

Definitivamente não! gRPC vem como uma oportunidade muito interessante para comunicação entre processos e comunicação entre serviços dentro de uma mesma infraestrutura. Ainda temos equipamentos muito antigos em todo canto da internet atrapalhando o uso de todo o potencial do gRPC. O browser embora se beneficie de http2, ainda não implementa algumas coisas nos motores de javascript e principalmente nas libraries de acesso http. Se você pegar um projeto com jQuery ou Angular ou React não vai conseguir usar tão bem. 

Outro ponto relevante é que não faz sentido sair migrando tudo par gRPC! Serviços internos fazem todo o sentido, pois você consegue gerir melhor. Para serviços externos, você precisa garantir seus clientes também suportem gRPC.

gRPC é maduro?

Sim, para quem não está a par sobre NLP e Chatbots com google API.AI, desde Janeiro de 2018, o padrão de comunicação com o API.AI é via gRPC. Mas note, você não recebe um .proto e se vira para criar seu client! Você usa um client previamente gerado. Acredito que este seja o melhor cenário quando você quer expor sua API gRPC para fora da tua empresa. Mas isso demanda mais trabalho, principalmente na integração contínua.

Conclusão

É uma novidade muito, mas muito relevante. Não é para todo mundo e talvez sequer seja o momento para você. Mas saber que existe, saber das suas possibilidades abrem possibilidades muito interessantes.

Para alguns, há muitos desafios a serem considerados, para outros menos. Tudo depende de onde está para onde está indo.

E você?! Animado(a) com gRPC?

Ainda falta falar de Stream, mas vou deixar para outro post!

 
https://www.youtube.com/watch?v=XQ6vNDKuhEs

Meus vídeos sobre gRPC

Live @ Canal Dotnet – gRPC: o novo modelo de comunicação Cross-Platform

https://www.youtube.com/watch?v=rrugn-DDfRI

Live @ Canal Dotnet – gRPC no ASP.NET Core 3.0: Implementando Streams

https://www.youtube.com/watch?v=aYD4YQW7w9E

Demo Básica de gRPC

Nesse repositório temos demos com gRPC Client em .NET Core, e gRPC Service em Node e ASP.NET Corer | https://github.com/luizcarlosfaria/gRPC-Playground

Vídeos da Comunidade

Community Standup

https://www.youtube.com/watch?v=Pa6qtu1wIs8

Adopting gRPC at Spotify by Matthias Grüter

https://www.youtube.com/watch?v=CbNimCiMqe8

O Cloud Native .NET é meu principal projeto.

Onde empenho energia para ajudar, acompanhar, direcionar Desenvolvedores, Líderes Técnicos e jovens Arquitetos na jornada Cloud Native.

Conduzo entregando a maior e mais completa stack de tecnologias do mercado.

Ao trabalhar com desenvolvedores experientes, eu consigo usar seu aprendizado com .NET, banco de dados, e arquitetura para encurtar a jornada.

Ao restringir à desenvolvedores .NET eu consigo usar do contexto de tecnologias e problemas do seu dia-a-dia, coisas que você conhece hoje, como WCF, WebForms, IIS e MVC, por exemplo, para mostrar a comparação entre o que você conhece e o que está sendo apresentado.

É assim que construímos fundamentos sólidos, digerindo a complexidade com didática, tornando o complexo, simples.

É assim que conseguimos tornar uma jornada densa, em um pacote de ~4 meses.

Eu não acredito que um desenvolvedor possa entender uma tecnologia sem compreender seus fundamentos. Ele no máximo consegue ser produtivo, mas isso não faz desse desenvolvedor um bom tomador de decisões técnicas.

É preciso entender os fundamentos para conseguir tomar boas decisões.

4 Comentários

  1. Thiago juliano da Silva

    Bela compilação do conteúdo.
    Achei muito interessante, mas era o caso de dar um exemplo em vs2017?
    A maior parte dos projetos hoje estão rodando em vs2017. Como você mesmo falou, vs2019 é preview.
    Parabéns Luiz.

    Responder
    • Luiz Carlos Faria

      Opa Thiago, essas novidades a gente só consegue mostrar com as versões preview. Eu uso preview desde o 2015, claro que sofri muito com ele, mas já no 2017 estabilizou e no 2019 está fantástico. Estou testando com base no 2019 preview pq é com ele que temos acesso ao novo template de projetos, é com ele que conseguimos rodar ASP.NET Core 3 com as novidades.

      Já para quem está rodando versões GA, ou .NET Core 2.X está preso à outra implementação que não está sob Kestrel, funciona diferente.

      Responder
  2. Fernando Vellozo

    Quero saber com seria o processo (ou estrategia) de autenticação e segurança com gRPC, se poder mostrar isso na live seria perfeito, Deis já agradeço!

    Responder
    • Luiz Carlos Faria

      Anotado, eu mostro na live. Obrigado Fernando.

      Responder

Deixe uma resposta para Luiz Carlos Faria Cancelar resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.

[docker de a a z]

Lives

Fique de olho nas lives

Fique de olho nas lives no meu canal do Youtube, no Canal .NET e nos Grupos do Facebook e Instagram.

Aceleradores

Existem diversas formas de viabilizar o suporte ao teu projeto. Seja com os treinamentos, consultoria, mentorias em grupo.