Saltar al contenido

Fundamentos de Service Mesh: redes a nivel de infraestructura

Un service mesh saca los reintentos, el circuit breaking, mTLS y la observabilidad del código de la aplicación y los lleva a la infraestructura.

3 min de lectura
Arquitectura de un service mesh con sidecar proxies gestionando la comunicación entre servicios

En una arquitectura de microservicios, cada servicio necesita reintentos, timeouts, circuit breaking, TLS mutuo, división de tráfico y observabilidad. Implementar todo esto en el código de cada servicio genera duplicación e inconsistencias. Un service mesh se encarga de todo esto a nivel de infraestructura: un sidecar proxy intercepta cada llamada de red y aplica las políticas de forma uniforme, sin modificar el código de la aplicación.

El patrón sidecar

Cada instancia de un servicio recibe un sidecar proxy (normalmente Envoy). Todo el tráfico entrante y saliente pasa por el proxy, que aplica las políticas de red de forma transparente.

ymlyaml
# Without service mesh: application handles networking
# Every service needs retry logic, circuit breakers, TLS, etc.
 
# With service mesh: sidecar proxy handles networking
# Kubernetes pod with a sidecar injected by Istio
apiVersion: v1
kind: Pod
metadata:
  name: order-service
  labels:
    app: order-service
  annotations:
    sidecar.istio.io/inject: "true"  # Istio injects the sidecar automatically
spec:
  containers:
    - name: order-service
      image: registry.example.com/order-service:v1.2.0
      ports:
        - containerPort: 3000
    # Istio automatically adds:
    # - name: istio-proxy
    #   image: docker.io/istio/proxyv2
    #   ports:
    #     - containerPort: 15001 (outbound)
    #     - containerPort: 15006 (inbound)

Gestión del tráfico

Los service mesh ofrecen enrutamiento de tráfico sofisticado sin necesidad de modificar el código de la aplicación.

ymlyaml
# Retry policy — automatically retry failed requests
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: payment-service
spec:
  hosts:
    - payment-service
  http:
    - route:
        - destination:
            host: payment-service
      retries:
        attempts: 3
        perTryTimeout: 2s
        retryOn: "5xx,reset,connect-failure,retriable-4xx"
 
---
# Timeout policy — fail fast if the service is slow
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: recommendation-service
spec:
  hosts:
    - recommendation-service
  http:
    - route:
        - destination:
            host: recommendation-service
      timeout: 5s  # Fail after 5 seconds instead of waiting indefinitely

TLS mutuo (mTLS)

Un service mesh puede exigir mTLS entre todos los servicios: cada conexión queda cifrada y autenticada sin que la aplicación tenga que gestionar certificados.

ymlyaml
# ❌ Without mesh: plaintext HTTP between services
# Any compromised pod can eavesdrop on inter-service traffic
 
# ✅ With Istio: strict mTLS for all services in the namespace
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: production
spec:
  mtls:
    mode: STRICT  # All traffic must use mTLS
 
---
# Authorization policy — only specific services can call payment
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: payment-service-access
  namespace: production
spec:
  selector:
    matchLabels:
      app: payment-service
  rules:
    - from:
        - source:
            principals:
              - "cluster.local/ns/production/sa/order-service"
              - "cluster.local/ns/production/sa/refund-service"
      to:
        - operation:
            methods: ["POST"]
            paths: ["/api/charge", "/api/refund"]

Circuit breaking a nivel del mesh

En lugar de implementar circuit breakers en cada servicio, se configuran una sola vez en el mesh.

ymlyaml
# ❌ Every service implements its own circuit breaker in application code
# Inconsistent thresholds, different libraries, duplicated logic
 
# ✅ Mesh-level circuit breaking — consistent across all services
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: payment-service
spec:
  host: payment-service
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        h2UpgradePolicy: DEFAULT
        http1MaxPendingRequests: 50
        http2MaxRequests: 100
    outlierDetection:
      consecutive5xxErrors: 5        # Eject after 5 consecutive errors
      interval: 10s                   # Check every 10 seconds
      baseEjectionTime: 30s           # Eject for 30 seconds minimum
      maxEjectionPercent: 50          # Never eject more than 50% of hosts

Observabilidad sin cambios en el código

El sidecar proxy captura métricas, trazas y logs de acceso de cada solicitud, sin necesidad de instrumentar el código de la aplicación.

tstypescript
// Without service mesh: manual instrumentation required
app.use((req, res, next) => {
  const start = Date.now();
  res.on("finish", () => {
    metrics.histogram("http_duration", Date.now() - start, {
      method: req.method,
      path: req.path,
      status: res.statusCode,
    });
  });
  next();
});
 
// With service mesh: metrics are collected automatically by the proxy
// Available as Prometheus metrics:
// istio_requests_total{source_app="order-service", destination_app="payment-service", response_code="200"}
// istio_request_duration_milliseconds{...}
// istio_tcp_sent_bytes_total{...}
ymlyaml
# Grafana dashboard JSON model for mesh metrics
# These metrics exist without any application instrumentation
panels:
  - title: "Request Rate"
    targets:
      - expr: 'sum(rate(istio_requests_total{destination_app="payment-service"}[5m]))'
  - title: "P99 Latency"
    targets:
      - expr: 'histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{destination_app="payment-service"}[5m])) by (le))'
  - title: "Error Rate"
    targets:
      - expr: 'sum(rate(istio_requests_total{destination_app="payment-service",response_code=~"5.."}[5m])) / sum(rate(istio_requests_total{destination_app="payment-service"}[5m]))'

Cuándo no usar un service mesh

Los service mesh añaden latencia (el salto adicional por el sidecar proxy), sobrecarga de memoria (un proxy por cada pod) y complejidad operativa (la gestión del control plane). Se justifican cuando hay muchos servicios con requisitos de red complejos. Para un puñado de servicios, las bibliotecas a nivel de aplicación son más sencillas.

Puntos clave

  1. Los service mesh gestionan la red a nivel de infraestructura: reintentos, timeouts y circuit breaking sin cambios en el código de la aplicación
  2. mTLS cifra y autentica todo el tráfico entre servicios: el mesh gestiona los certificados automáticamente
  3. Las políticas de tráfico son declarativas: el enrutamiento, los reintentos y el circuit breaking se configuran con YAML
  4. La observabilidad viene incluida: el sidecar captura métricas, trazas y logs de cada solicitud
  5. Las políticas de autorización controlan el acceso entre servicios: definen qué servicios pueden llamar a qué endpoints
  6. Evalúa la sobrecarga: un mesh añade latencia y memoria por pod, así que solo se justifica con suficientes servicios y complejidad
Wilfredo Rujel

Wilfredo Rujel

Ingeniero de Software Full Stack

Compartir esta publicaciónX