gRPC (gRPC Remote Procedure Call) est un framework open source de communication inter-processus développé par Google. Il repose sur HTTP/2 et Protocol Buffers (Protobuf) pour offrir des appels distants fortement typés, performants et multi-langages. Là où REST/HTTP domine les APIs publiques depuis des années, gRPC s’impose de plus en plus pour la communication inter-services, notamment dans les architectures microservices. Cet article explique ce qu’est gRPC, comment il fonctionne, et dans quels cas le préférer (ou non) à HTTP/REST.
Cet article fait partie de la série gRPC : 1 sur 1.
- Part 1 - Cet article
Qu’est-ce que gRPC ?
gRPC est un protocole d’appel de procédure à distance (RPC). Le principe est simple : on appelle une méthode sur un service distant comme si c’était un appel local. Le framework se charge de la sérialisation, du transport réseau, et de la désérialisation de la réponse.
sequenceDiagram
participant Client
participant Serveur
Client->>Serveur: appel GetProduct(id: 42)
Serveur->>Serveur: exécute la méthode
Serveur-->>Client: retourne Product { ... }
Contrairement à REST, où l’on raisonne en ressources et verbes HTTP (GET /products/42), gRPC raisonne en services et méthodes (ProductService.GetProduct).
Les fondations de gRPC
Protocol Buffers (Protobuf)
Protobuf est le format de sérialisation par défaut de gRPC. C’est un format binaire, compact et fortement typé, défini via des fichiers .proto :
syntax = "proto3";
package catalog;
// Définition du service
service ProductService {
rpc GetProduct (GetProductRequest) returns (Product);
rpc ListProducts (ListProductsRequest) returns (ProductList);
}
// Messages (DTOs)
message GetProductRequest {
int32 id = 1;
}
message ListProductsRequest {
int32 page = 1;
int32 page_size = 2;
}
message Product {
int32 id = 1;
string name = 2;
string description = 3;
double price = 4;
bool in_stock = 5;
}
message ProductList {
repeated Product products = 1;
int32 total_count = 2;
}
Les chiffres (= 1, = 2, etc.) sont des identifiants de champ, pas des valeurs. Ils permettent la compatibilité lors de l’évolution du schéma.
À partir de ce fichier, le compilateur protoc (ou les build tools intégrés à .NET, Go, Java, etc.) génère automatiquement le code client et serveur dans le langage ciblé.
Pourquoi du binaire ?
| Aspect | JSON (REST) | Protobuf (gRPC) |
|---|---|---|
| Format | Texte, lisible | Binaire, compact |
| Taille | ~100 octets pour un objet simple | ~30-50 octets pour le même objet |
| Parsing | Lent (parsing texte, allocation strings) | Rapide (lecture directe de bytes) |
| Schéma | Optionnel (OpenAPI/Swagger) | Obligatoire (.proto) |
Le binaire est plus petit sur le réseau et plus rapide à sérialiser/désérialiser. En revanche, il n’est pas lisible directement (on ne peut pas l’inspecter avec un simple curl).
HTTP/2
gRPC utilise HTTP/2 comme transport, ce qui apporte :
- Multiplexage : plusieurs requêtes/réponses en parallèle sur une seule connexion TCP (pas de head-of-line blocking comme en HTTP/1.1).
- Header compression (HPACK) : les headers sont compressés, ce qui réduit la bande passante.
- Binary framing : les données sont envoyées en frames binaires, au lieu de texte.
- Server push : le serveur peut envoyer des données sans que le client ne les ait demandées (utilisé en interne par gRPC pour le streaming).
REST/HTTP peut aussi utiliser HTTP/2, mais en pratique la plupart des APIs REST fonctionnent en HTTP/1.1 avec JSON.
Les 4 types de communication gRPC
C’est l’un des grands avantages de gRPC : il supporte nativement 4 modes de communication :
1. Unary (requête-réponse classique)
Un appel, une réponse. Équivalent d’un GET ou POST en REST.
rpc GetProduct (GetProductRequest) returns (Product);
2. Server Streaming
Le client envoie une requête, le serveur renvoie un flux de réponses.
rpc ListProducts (ListProductsRequest) returns (stream Product);
Cas d’usage : exporter un grand nombre de résultats, flux de logs, notifications en temps réel.
3. Client Streaming
Le client envoie un flux de requêtes, le serveur renvoie une seule réponse à la fin.
rpc UploadProducts (stream Product) returns (UploadSummary);
Cas d’usage : upload de fichiers par morceaux, ingestion de données en batch.
4. Bidirectional Streaming
Les deux côtés envoient et reçoivent des flux simultanément.
rpc Chat (stream ChatMessage) returns (stream ChatMessage);
Cas d’usage : chat en temps réel, synchronisation bidirectionnelle, pipelines de traitement.
En REST, pour obtenir du streaming on doit recourir à des solutions annexes (WebSocket, SSE), qui ne sont pas intégrées nativement au protocole.
gRPC en .NET : exemple complet
Créer un service gRPC
dotnet new grpc -n ProductApi
Définir le contrat (Protos/product.proto)
syntax = "proto3";
option csharp_namespace = "ProductApi";
package catalog;
service ProductService {
rpc GetProduct (GetProductRequest) returns (Product);
rpc ListProducts (Empty) returns (stream Product);
}
message GetProductRequest {
int32 id = 1;
}
message Product {
int32 id = 1;
string name = 2;
double price = 3;
}
message Empty {}
Référencer dans le .csproj
<ItemGroup>
<Protobuf Include="Protos\product.proto" GrpcServices="Server" />
</ItemGroup>
Implémenter le service
using Grpc.Core;
using ProductApi;
public class ProductServiceImpl : ProductService.ProductServiceBase
{
private static readonly List<Product> Products =
[
new() { Id = 1, Name = "Clavier mécanique", Price = 89.99 },
new() { Id = 2, Name = "Souris gaming", Price = 59.99 },
new() { Id = 3, Name = "Écran 4K", Price = 449.99 }
];
// Unary : une requête, une réponse
public override Task<Product> GetProduct(GetProductRequest request, ServerCallContext context)
{
var product = Products.FirstOrDefault(p => p.Id == request.Id)
?? throw new RpcException(new Status(StatusCode.NotFound,
$"Produit {request.Id} introuvable"));
return Task.FromResult(product);
}
// Server streaming : une requête, N réponses
public override async Task ListProducts(
Empty request,
IServerStreamWriter<Product> responseStream,
ServerCallContext context)
{
foreach (var product in Products)
{
await responseStream.WriteAsync(product);
await Task.Delay(500); // Simule un traitement
}
}
}
Configurer Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.MapGrpcService<ProductServiceImpl>();
app.Run();
Créer le client
dotnet new console -n ProductClient
cd ProductClient
dotnet add package Grpc.Net.Client
dotnet add package Google.Protobuf
dotnet add package Grpc.Tools
Référencer le même .proto en mode client :
<ItemGroup>
<Protobuf Include="..\ProductApi\Protos\product.proto" GrpcServices="Client"
Link="Protos\product.proto" />
</ItemGroup>
Appel unary
using Grpc.Net.Client;
using ProductApi;
var channel = GrpcChannel.ForAddress("http://localhost:5001");
var client = new ProductService.ProductServiceClient(channel);
// Appel unary
var product = await client.GetProductAsync(new GetProductRequest { Id = 1 });
Console.WriteLine($"{product.Name} - {product.Price} €");
Appel server streaming
// Server streaming : lire un flux de produits
using var stream = client.ListProducts(new Empty());
await foreach (var product in stream.ResponseStream.ReadAllAsync())
{
Console.WriteLine($"Reçu : {product.Name} - {product.Price} €");
}
Avantages de gRPC par rapport à HTTP/REST
Performance
- Sérialisation binaire (Protobuf) : 5 à 10x plus compact que JSON, 10x plus rapide à sérialiser/désérialiser.
- HTTP/2 : multiplexage, compression des headers, réduction de la latence.
- Connexions persistantes : pas de surcoût de connexion TCP à chaque requête.
En pratique, pour des charges élevées (milliers d’appels par seconde entre services), gRPC peut diviser la latence par 2 à 5 par rapport à REST/JSON.
Contrat fort et génération de code
- Le fichier
.protoest le contrat unique entre client et serveur. - Le code est généré automatiquement dans tous les langages supportés (C#, Java, Go, Python, Rust, etc.).
- Toute incompatibilité est détectée à la compilation, pas au runtime.
En REST, le contrat (OpenAPI/Swagger) est souvent optionnel, maintenu manuellement, et les erreurs de schéma ne se révèlent qu’à l’exécution.
Streaming natif
gRPC supporte 4 modes de communication nativement, là où REST est limité au modèle requête-réponse. Pour du streaming, REST nécessite des solutions ad hoc (WebSocket, Server-Sent Events).
Multi-langage
Le même fichier .proto génère des clients et serveurs dans tous les langages supportés. Un service C# peut être appelé par un client Go ou Python sans écrire de code d’intégration.
Évolution du schéma
Protobuf permet d’ajouter des champs sans casser les clients existants (les champs inconnus sont ignorés), grâce aux identifiants numériques de champ. C’est plus robuste que l’évolution d’un schéma JSON.
Inconvénients de gRPC par rapport à HTTP/REST
Pas lisible par un humain
Le format binaire de Protobuf n’est pas lisible directement. On ne peut pas inspecter les requêtes/réponses avec un simple curl ou un navigateur. Il faut des outils spécifiques :
- grpcurl : équivalent de curl pour gRPC
- gRPC UI : interface graphique (comme Postman pour gRPC)
- Postman : supporte gRPC depuis la v10
- Reflection : le service peut exposer ses
.protopour que les outils les découvrent dynamiquement
# grpcurl : lister les services
grpcurl -plaintext localhost:5001 list
# grpcurl : appeler une méthode
grpcurl -plaintext -d '{"id": 1}' localhost:5001 catalog.ProductService/GetProduct
Pas adapté aux navigateurs web (sans proxy)
Les navigateurs ne supportent pas nativement gRPC (pas d’API JavaScript pour HTTP/2 frames). Il faut passer par :
- gRPC-Web : un protocole adapté pour les navigateurs, avec un proxy (Envoy) ou un middleware côté serveur.
- Un gateway REST : qui traduit les appels REST en appels gRPC (ex. : grpc-gateway).
En .NET, le middleware gRPC-Web se configure simplement :
var app = builder.Build();
app.UseGrpcWeb(); // Active gRPC-Web
app.MapGrpcService<ProductServiceImpl>().EnableGrpcWeb();
Mais cela reste une couche supplémentaire par rapport à une API REST directement consommable par un navigateur.
Complexité de mise en place
- Il faut gérer les fichiers
.proto, le compilateur Protobuf, la génération de code. - Le debugging est plus complexe (binaire, outils spécifiques).
- L’infrastructure doit supporter HTTP/2 (certains load balancers, proxys ou CDN ne le supportent pas bien).
Moins d’écosystème pour les APIs publiques
REST/HTTP est le standard universel pour les APIs publiques. La quasi-totalité des outils, documentations et intégrations tierces supposent du REST/JSON. gRPC est plus adapté à la communication interne entre microservices.
Load balancing côté client
En HTTP/1.1, chaque requête ouvre une connexion, donc un load balancer L4 répartit naturellement les requêtes. En gRPC (HTTP/2), une seule connexion persistante peut envoyer toutes les requêtes, ce qui contourne le load balancing L4. Solutions :
- Load balancing L7 (Envoy, Nginx avec gRPC support)
- Client-side load balancing (le client connaît les instances et répartit lui-même)
- Service mesh (Istio, Linkerd) ou Dapr
Comparatif synthétique
| Critère | HTTP/REST + JSON | gRPC + Protobuf |
|---|---|---|
| Format | Texte (JSON) | Binaire (Protobuf) |
| Transport | HTTP/1.1 ou HTTP/2 | HTTP/2 obligatoire |
| Contrat | Optionnel (OpenAPI) | Obligatoire (.proto) |
| Génération de code | Optionnelle | Automatique |
| Performance | Bon | Excellent (2-10x plus rapide) |
| Taille des messages | ~2-5x plus gros | Compact (binaire) |
| Streaming | SSE, WebSocket (ad hoc) | Natif (4 modes) |
| Lisibilité | Oui (curl, navigateur) | Non (outils spécifiques) |
| Navigateur | Natif | gRPC-Web + proxy |
| APIs publiques | Standard | Rare |
| Communication inter-services | Bon | Excellent |
| Écosystème | Universel | En croissance |
| Load balancing | Simple (L4) | Nécessite L7 ou client-side |
| Évolution du schéma | Fragile (JSON) | Robuste (identifiants numériques) |
Quand utiliser quoi ?
Choisir HTTP/REST quand :
- L’API est consommée par des navigateurs ou des clients externes.
- La simplicité et la lisibilité sont prioritaires.
- L’écosystème tiers (documentation, portails développeurs, intégrations) est important.
- Les performances ne sont pas critiques (charges modérées).
Choisir gRPC quand :
- La communication est interne entre microservices.
- Les performances sont critiques (haute fréquence, faible latence).
- Vous avez besoin de streaming (temps réel, flux de données).
- Vous travaillez dans un environnement multi-langage et voulez un contrat unique.
- Vous voulez des garanties de compatibilité à la compilation.
Combiner les deux
L’approche la plus courante est de combiner les deux :
REST/JSON gRPC/Protobuf
Navigateur/Mobile ──────────▶ API Gateway ──────────────────────▶ Microservices internes
(REST → gRPC) ◀────────▶ (gRPC entre eux)
- REST en façade pour les clients externes.
- gRPC en interne entre les services pour la performance et les contrats typés.
- Un API Gateway ou un BFF (Backend For Frontend) fait la traduction.
Résumé
gRPC est un protocole RPC moderne, performant et fortement typé, idéal pour la communication inter-services. Ses avantages principaux — sérialisation binaire, streaming natif, contrats générés, multi-langage — en font un choix solide pour les architectures microservices. En revanche, son format binaire, sa dépendance à HTTP/2 et sa moindre accessibilité pour les navigateurs le rendent moins adapté aux APIs publiques, où REST/JSON reste le standard. En pratique, les deux protocoles coexistent souvent dans la même architecture, chacun utilisé là où il excelle.