Un cop hem descompost l'aplicació en serveis autònoms, sorgeix una pregunta inevitable: com es comuniquen entre si i com els troba el món exterior? La comunicació és el sistema nerviós d'una arquitectura distribuïda, i triar malament l'estil (síncron enfront d'asíncron) o la infraestructura (gateway, descobriment de serveis) pot convertir un conjunt de serveis elegants en un fràgil monòlit distribuït.
En aquesta lliçó compararem la comunicació síncrona (REST, gRPC) amb l'asíncrona (missatgeria, esdeveniments), entendrem el paper de l'API Gateway com a porta d'entrada i veurem com el service discovery permet que els serveis es localitzin en un entorn dinàmic.
Contingut
- Síncron enfront d'asíncron
- Comunicació síncrona: REST i gRPC
- Comunicació asíncrona: missatgeria i esdeveniments
- API Gateway
- Service Discovery
- Triar l'estil adequat
- Errors comuns i consells
- Exercicis
- Conclusió
- Síncron enfront d'asíncron
La primera gran decisió és si qui crida espera la resposta (síncron) o continua sense esperar (asíncron).
| Aspecte | Síncron (REST/gRPC) | Asíncron (missatges/esdeveniments) |
|---|---|---|
| Model | Petició/resposta | Publicar/subscriure o cua |
| Acoblament temporal | Alt: tots dos han d'estar vius | Baix: desacoblats en el temps |
| Simplicitat | Major (flux directe) | Menor (més peces) |
| Disponibilitat | Si B cau, A se'n veu afectat | A continua encara que B estigui caigut |
| Consistència | Immediata | Eventual |
| Casos típics | Consultes, validacions immediates | Notificacions, integració, esdeveniments |
La idea clau de l'acoblament temporal: en una crida síncrona, el servei destí ha d'estar disponible en aquell instant. En l'asíncrona, el missatge espera en una cua fins que el destí pugui processar-lo.
- Comunicació síncrona: REST i gRPC
REST sobre HTTP és l'estàndard de facto: senzill, universal, basat en recursos i verbs HTTP.
// Client REST amb timeout explícit (mai confiïs en la xarxa)
public Cliente obtenerCliente(String id) {
return webClient.get()
.uri("/clientes/{id}", id)
.retrieve()
.bodyToMono(Cliente.class)
.timeout(Duration.ofSeconds(2)) // talla si triga massa
.block();
}El timeout és imprescindible: sense ell, un servei lent bloquejaria indefinidament qui crida (recorda la fal·làcia "la latència és zero").
gRPC usa HTTP/2 i serialització binària (Protocol Buffers), cosa que el fa més ràpid i compacte, ideal per a comunicació interna d'alt rendiment.
// Definició del contracte en Protocol Buffers (clientes.proto)
syntax = "proto3";
service ClienteService {
rpc ObtenerCliente (ClienteRequest) returns (ClienteResponse);
}
message ClienteRequest { string id = 1; }
message ClienteResponse { string id = 1; string nombre = 2; }A partir d'aquest contracte, gRPC genera automàticament el codi de client i servidor. La comparació ràpida:
| Criteri | REST/JSON | gRPC/Protobuf |
|---|---|---|
| Format | Text (JSON) | Binari |
| Rendiment | Bo | Excel·lent |
| Llegibilitat | Alta | Baixa (binari) |
| Navegadors | Suport natiu | Limitat |
| Streaming | Limitat | Natiu (bidireccional) |
| Ús típic | APIs públiques | Comunicació interna |
- Comunicació asíncrona: missatgeria i esdeveniments
En la comunicació asíncrona, un servei publica un missatge en un broker (RabbitMQ, Apache Kafka, etc.) i altres el consumeixen quan poden. Distingim:
- Comandes: petició perquè alguna cosa passi ("EnviarRecibo"). Solen tenir un únic destinatari.
- Esdeveniments: notificació d'alguna cosa que ja ha passat ("PolizaCreada"). Poden tenir molts subscriptors.
{
"tipo": "PolizaCreada",
"version": 1,
"ocurridoEn": "2026-06-30T10:15:00Z",
"datos": {
"polizaId": "POL-00123",
"ramo": "hogar"
}
}Aquest esdeveniment descriu un fet consumat. El servei de facturació pot subscriure-s'hi per generar el primer rebut, i el de notificacions per enviar un correu de benvinguda, sense que el servei de pòlisses en sàpiga res. Això redueix dràsticament l'acoblament.
// Consumidor d'esdeveniments: reacciona a PolizaCreada
@KafkaListener(topics = "polizas")
public void onPolizaCreada(PolizaCreadaEvent evento) {
// Processament idempotent: si ja l'hem processat, sortim
if (yaProcesado(evento.getId())) return;
facturacion.generarPrimerRecibo(evento.getPolizaId());
marcarProcesado(evento.getId());
}La idempotència és crítica perquè els brokers solen garantir lliurament "almenys una vegada", cosa que significa que un missatge pot arribar duplicat.
- API Gateway
L'API Gateway és l'única porta d'entrada per als clients externs. En lloc que el frontend conegui l'adreça de cada microservei, parla només amb el gateway, que encamina i agrega.
graph LR
APP[App Mòbil] --> GW[API Gateway]
WEB[Web] --> GW
GW --> S1[Servei Pòlisses]
GW --> S2[Servei Clients]
GW --> S3[Servei Sinistres]Responsabilitats habituals del gateway:
| Funció | Descripció |
|---|---|
| Encaminament | Dirigeix cada petició al servei correcte. |
| Autenticació | Valida tokens abans de passar al backend. |
| Limitació de taxa | Protegeix davant abusos (rate limiting). |
| Agregació | Combina respostes de diversos serveis en una. |
| TLS | Acaba el xifratge en un únic punt. |
# Configuració de rutes en un API Gateway (estil Spring Cloud Gateway)
spring:
cloud:
gateway:
routes:
- id: polizas
uri: lb://servicio-polizas # lb = balanceig via service discovery
predicates:
- Path=/api/polizas/**
- id: clientes
uri: lb://servicio-clientes
predicates:
- Path=/api/clientes/**Cada ruta associa un patró d'URL (predicates) amb un servei destí (uri). El prefix lb:// indica que l'adreça concreta es resol mitjançant el service discovery, no es codifica a mà.
Compte: el gateway no ha de contenir lògica de negoci. Si el converteixes en un cervell central, tornes al monòlit.
- Service Discovery
Al núvol, les instàncies d'un servei apareixen i desapareixen contínuament (autoescalat, desplegaments, errors). Les seves adreces IP no són fixes. El service discovery resol el problema: un registre central on els serveis s'inscriuen i es busquen per nom.
sequenceDiagram
participant S as Servei Pòlisses
participant R as Registre (Discovery)
participant C as Servei Client
S->>R: Em registro: polizas -> 10.0.0.5:8080
C->>R: On és "polizas"?
R->>C: 10.0.0.5:8080
C->>S: Petició HTTPHi ha dos models:
| Model | Descripció | Exemple |
|---|---|---|
| Del costat del client | El client consulta el registre i tria instància. | Eureka + Ribbon |
| Del costat del servidor | Un balancejador resol per tu. | Kubernetes Services |
A Kubernetes, el descobriment està integrat: cada servei té un nom DNS estable i el clúster balanceja automàticament.
# A Kubernetes, "servicio-polizas" és un nom DNS resoluble des d'altres pods
apiVersion: v1
kind: Service
metadata:
name: servicio-polizas
spec:
selector:
app: polizas
ports:
- port: 8080Amb aquesta definició, qualsevol pod pot cridar http://servicio-polizas:8080 i Kubernetes encamina a una instància sana, sense que ningú gestioni IPs.
- Triar l'estil adequat
Una guia pràctica per decidir:
- Necessites la resposta ara per continuar (validar una dada, mostrar una pantalla)? → Síncron.
- Estàs notificant una cosa que ja ha passat i a diversos interessats? → Asíncron (esdeveniments).
- Vols que el servei destí pugui estar caigut sense afectar-te? → Asíncron.
- L'operació és una consulta simple i de baixa latència? → Síncron (gRPC intern o REST).
El principi general: prefereix l'asíncron per reduir acoblament, i reserva el síncron per a consultes que realment necessiten resposta immediata.
Errors Comuns i Consells
- Crides síncrones en cadena: A crida B, que crida C, que crida D. La latència i la probabilitat d'error s'acumulen. Considera esdeveniments.
- Oblidar els timeouts: tota crida síncrona ha de tenir timeout. Sense ell, un servei lent t'arrossega.
- Ficar lògica de negoci al gateway: el gateway encamina i protegeix, no decideix. La lògica viu als serveis.
- Assumir lliurament exactament una vegada: els brokers lliuren "almenys una vegada". Fes els consumidors idempotents.
- Codificar IPs a mà: usa service discovery; les adreces canvien constantment.
Exercicis
- Compara en una taula la comunicació síncrona i l'asíncrona en termes d'acoblament temporal, disponibilitat i consistència.
- Explica per què un consumidor d'esdeveniments ha de ser idempotent i mostra en pseudocodi Java com aconseguir-ho.
- Tens una pantalla que necessita mostrar, en una sola crida, les dades del client i les seves pòlisses, que viuen en serveis diferents. Quina peça de l'arquitectura usaries i com?
Solucions
-
Síncron: acoblament temporal alt (tots dos han d'estar vius), disponibilitat dependent del destí, consistència immediata. Asíncron: acoblament temporal baix (el missatge espera en cua), disponibilitat independent, consistència eventual.
-
Ha de ser idempotent perquè els brokers lliuren "almenys una vegada", així que un missatge pot arribar duplicat. Solució:
public void onEvento(Evento e) {
if (yaProcesado(e.getId())) return; // descarta duplicats
procesar(e);
marcarProcesado(e.getId());
}- L'API Gateway amb un patró d'agregació (o un BFF, Backend For Frontend): el gateway rep la petició, crida en paral·lel el servei de clients i el de pòlisses, i combina totes dues respostes en un únic JSON que retorna a la pantalla. Així el frontend fa una sola crida.
Conclusió
Hem après que la comunicació entre serveis es mou entre dos pols: la síncrona (REST, gRPC), simple però acoblada en el temps, i l'asíncrona (esdeveniments, missatges), desacoblada però eventualment consistent. L'API Gateway ofereix una porta d'entrada única que encamina, protegeix i agrega, mentre que el service discovery permet que els serveis es trobin en un entorn dinàmic.
Tota aquesta comunicació per xarxa comparteix un risc: les dependències fallen. La lliçó següent, Patrons de Resiliència: Circuit Breaker, Retry i Bulkhead, ens ensenyarà a dissenyar serveis que sobreviuen als errors parcials en lloc de propagar-los.
Curs d'Arquitectura d'Aplicacions
Mòdul 1: Fonaments de l'Arquitectura d'Aplicacions
- Què és l'Arquitectura d'Aplicacions?
- El Rol de l'Arquitecte de Programari
- Atributs de Qualitat i Requisits No Funcionals
- Decisions Arquitectòniques i Compromisos (Trade-offs)
- Documentació d'Arquitectura: Vistes i el Model C4
Mòdul 2: Principis i Tàctiques de Disseny
- Acoblament, Cohesió i Separació de Responsabilitats
- Principis SOLID Aplicats a l'Arquitectura
- DRY, KISS, YAGNI i Altres Principis de Disseny
- Tàctiques Arquitectòniques per als Atributs de Qualitat
- Gestió del Deute Tècnic
Mòdul 3: Estils i Patrons Arquitectònics
- Arquitectura Monolítica
- Arquitectura en Capes (N-Tier)
- Arquitectura Client-Servidor
- Arquitectura Hexagonal (Ports i Adaptadors)
- Arquitectura Neta i Ceba (Clean & Onion)
Mòdul 4: Arquitectures Distribuïdes i Microserveis
- Introducció als Sistemes Distribuïts
- Arquitectura de Microserveis
- Descomposició de Serveis i Bounded Contexts
- API Gateway, Service Discovery i Comunicació entre Serveis
- Patrons de Resiliència: Circuit Breaker, Retry i Bulkhead
- El Teorema CAP i la Consistència de Dades
Mòdul 5: Arquitectures Dirigides per Esdeveniments i Missatgeria
- Fonaments de l'Arquitectura Orientada a Esdeveniments
- Missatgeria Asíncrona: Cues i Brokers
- Patrons d'Esdeveniments: Event Sourcing i CQRS
- Gestió de Transaccions Distribuïdes: Patró Saga
- Streaming de Dades en Temps Real
Mòdul 6: Disseny Dirigit pel Domini (DDD)
- Conceptes Fonamentals del DDD
- Disseny Estratègic: Bounded Contexts i Llenguatge Ubic
- Disseny Tàctic: Entitats, Agregats i Repositoris
- Mapatge de Contextos (Context Mapping)
Mòdul 7: Dades i Persistència
- Estratègies de Persistència: SQL vs NoSQL
- Patrons d'Accés a Dades: Repository, Unit of Work i DAO
- Base de Dades per Servei i Gestió de Dades Distribuïdes
- Cau i Estratègies d'Invalidació
Mòdul 8: Arquitectura al Núvol i Desplegament
- Fonaments del Cloud Computing (IaaS, PaaS, SaaS)
- Contenidors i Orquestració amb Docker i Kubernetes
- Arquitectura Serverless
- Patrons de Disseny Cloud-Native
- Infraestructura com a Codi (IaC)
Mòdul 9: Qualitat, Seguretat i Observabilitat
- Escalabilitat: Horitzontal vs Vertical i Balanceig de Càrrega
- Alta Disponibilitat i Tolerància a Fallades
- Seguretat per Disseny i Autenticació/Autorització
- Observabilitat: Logging, Mètriques i Traçabilitat
- Rendiment i Proves de Càrrega
