gRPC: el protocolo RPC de Google que corre sobre HTTP/2
@programacionLo esencial
- gRPC nació en Google en 2015 como evolución pública de Stubby, su sistema RPC interno usado desde 2001.
- Corre sobre HTTP/2, lo que permite multiplexar varias llamadas simultáneas en una sola conexión TCP.
- Serializa los mensajes con Protocol Buffers (protobuf), un formato binario más compacto que JSON.
- Define 4 tipos de llamada: unaria, server streaming, client streaming y bidireccional.
- El contrato se escribe en un archivo .proto y el compilador protoc genera el código cliente y servidor.
- gRPC se convirtió en proyecto graduado de la CNCF en 2019, junto a Kubernetes y Prometheus.
- Proyectos como etcd y CockroachDB lo usan para la comunicación interna entre sus nodos.
Qué es gRPC
Google usa gRPC internamente para conectar miles de microservicios, heredando el diseño de Stubby, su sistema RPC privado desde 2001, que la empresa reescribió y liberó como proyecto abierto en 2015.
A diferencia de REST, donde el cliente pide recursos por URL (GET /usuarios/42), gRPC expone funciones remotas directamente: el cliente llama a un método como si fuera local y la biblioteca se encarga de serializar la petición y enviarla por red. Podés revisar el detalle en la documentación oficial de gRPC.
De Stubby a gRPC: el origen en Google
Stubby resolvía un problema concreto dentro de Google: miles de servicios internos necesitaban llamarse entre sí sin acordar manualmente un formato HTTP para cada endpoint. Al abrir el proyecto, Google reemplazó el transporte propietario por HTTP/2 y el formato de mensajes por protobuf, ambos ya estandarizados.
El proyecto pasó a manos de la Cloud Native Computing Foundation (CNCF) y se graduó en 2019, el mismo estatus que tienen Kubernetes y Prometheus. Esto significa gobernanza abierta y no dependencia exclusiva de un solo mantenedor corporativo.
HTTP/2 bajo el capot: multiplexación real
HTTP/1.1 abre una conexión TCP por petición (o hace pool de varias), y cada una espera su turno. HTTP/2 introduce streams: múltiples llamadas viajan intercaladas dentro de la misma conexión TCP, sin que una tenga que esperar a que termine la anterior.
Esto elimina el head-of-line blocking a nivel de aplicación: una llamada lenta no bloquea a las demás que comparten la conexión. HTTP/2 también comprime los encabezados con HPACK, reduciendo el overhead de metadatos en cada llamada.
Protocol Buffers: el formato binario que reemplaza a JSON
Protobuf es un formato de serialización binario definido por esquema. En vez de mandar texto con nombres de campo repetidos ({"sku": "SKU-4471"}), protobuf codifica cada campo como un número de índice más el valor, lo que produce mensajes más chicos que su equivalente en JSON. Podés ver la especificación completa en protobuf.dev.
syntax = "proto3";
package inventario;
service InventoryService {
rpc GetStock (StockRequest) returns (StockResponse);
rpc WatchStock (StockRequest) returns (stream StockResponse);
}
message StockRequest {
string sku = 1;
}
message StockResponse {
string sku = 1;
int32 unidades = 2;
}Este archivo .proto define un servicio con dos métodos: uno que devuelve una sola respuesta (GetStock) y otro que devuelve un flujo continuo de respuestas (WatchStock). El compilador protoc genera, a partir de este archivo, las clases y stubs de cliente y servidor en el lenguaje que elijas.
Los 4 tipos de llamada: unaria y streaming
- Unaria: el cliente envía una petición y recibe una sola respuesta, igual que una llamada HTTP tradicional.
- Server streaming: el cliente envía una petición y el servidor responde con un flujo de mensajes, útil para notificaciones de cambios de estado.
- Client streaming: el cliente envía un flujo de mensajes y el servidor responde una sola vez al terminar, por ejemplo para subir datos en lotes.
- Bidireccional: ambos lados envían y reciben flujos de mensajes de forma independiente sobre la misma conexión.
Ejemplo práctico: cliente en Node.js
Con el archivo inventario.proto ya definido, un cliente en Node.js puede llamar al servicio InventoryService sin escribir a mano ninguna petición HTTP:
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const packageDef = protoLoader.loadSync('inventario.proto');
const proto = grpc.loadPackageDefinition(packageDef).inventario;
const client = new proto.InventoryService(
'localhost:50051',
grpc.credentials.createInsecure()
);
client.getStock({ sku: 'SKU-4471' }, (err, response) => {
if (err) throw err;
console.log(response.unidades);
});El objeto client expone getStock como si fuera una función local. Por debajo, la biblioteca serializa { sku: 'SKU-4471' } a protobuf, lo envía por HTTP/2 y deserializa la respuesta a un objeto StockResponse.
gRPC vs REST: cuándo conviene cada uno
gRPC rinde mejor en comunicación interna entre microservicios: contratos tipados por el .proto, mensajes binarios más chicos y streaming nativo. Kubernetes y CockroachDB lo usan justamente para eso.
El límite real está en el navegador: un cliente web no puede abrir streams HTTP/2 crudos como los espera gRPC, así que se necesita una capa intermedia como gRPC-Web con un proxy. Para una API pública que terceros van a debuguear con curl o Postman, REST con JSON sigue siendo más simple de inspeccionar y documentar.
Conclusión
gRPC no reemplaza a REST en todos los casos: resuelve un problema específico, la comunicación rápida y tipada entre servicios que vos controlás en ambos extremos. Cuando esa condición se cumple, HTTP/2 y protobuf entregan menos overhead que JSON sobre HTTP/1.1.