StackPractices
intermediate Por Mathias Paulenko

Plantilla de Presupuesto de Rendimiento de API

Una plantilla para establecer y rastrear presupuestos de rendimiento de latencia y throughput para APIs.

Visión General

Cada endpoint de API consume recursos: CPU, memoria, conexiones de base de datos y ancho de banda de red. Sin presupuestos explícitos, los equipos agregan capacidades hasta que el sistema colapsa bajo carga. Esta plantilla define presupuestos de rendimiento como un contrato entre requisitos de producto y capacidad de infraestructura, haciendo explícitos los trade-offs antes de que se conviertan en caídas. Documentos relacionados: Diseñar un API Gateway Escalable para Microservicios, Construir Sistemas Resilientes con el Circuit Breaker y Inyección de Dependencias.

Cuándo Usar

Usa este recurso cuando:

  • Diseñas una nueva API o agregas un nuevo endpoint a una existente
  • Planificas capacidad para una campaña de marketing o pico de tráfico estacional
  • Investigas por qué una API es lenta bajo carga
  • Negocias qué significa “suficientemente rápido” entre producto e infra — la decisión GraphQL vs REST suele disparar la revisión de presupuestos

Sáltalo cuando: tu API tiene un único consumidor interno sin SLO — empieza con un dashboard de latencia y vuelve cuando haya un contrato que honrar. Para presupuestos de frontend (LCP, tamaño de bundle, web vitals), usa la plantilla de presupuesto de rendimiento.

Solución

# Presupuesto de Rendimiento de API: `<Nombre de la API>`

## 1. Presupuestos por Endpoint

### 1.1. Presupuesto de Latencia (p95)

| Endpoint | Objetivo | Actual | Margen | Notas |
|----------|----------|--------|--------|-------|
| `GET /health` | < 10ms | 8ms | 2ms | No debe depender de DB |
| `GET /users/{id}` | < 100ms | 85ms | 15ms | Solo una query de DB permitida |
| `POST /orders` | < 250ms | 210ms | 40ms | Transacción multi-tabla |
| `GET /reports/aggregate` | < 2s | 1.8s | 200ms | Réplica de lectura permitida |

### 1.2. Presupuesto de Throughput

| Endpoint | RPS Objetivo | Burst Máximo | Pool de Conexiones | Notas |
|----------|--------------|--------------|--------------------|-------|
| `GET /products` | 5,000 | 10,000 | 50 | Cacheado en Redis |
| `POST /checkout` | 500 | 1,000 | 20 | Escritura DB, idempotente |

### 1.3. Presupuesto de Payload

| Dirección | Tamaño Máximo | Típico | Compresión |
|-----------|---------------|--------|------------|
| Request body | 1 MB | 10 KB | Gzip |
| Response body | 5 MB | 50 KB | Gzip + Brotli |
| Header total | 16 KB | 1 KB | Ninguna |

### 1.4. Presupuesto de Dependencias

| Dependencia | Contribución Máxima de Latencia | Llamadas Concurrentes Máximas | Fallback |
|-------------|-----------------------------------|-------------------------------|----------|
| PostgreSQL | 40ms | 20 | Réplica de lectura |
| Redis | 5ms | 100 | Saltear caché (más lento) |
| Payment Gateway | 200ms | 10 | Encolar para async |
| Search Service | 100ms | 50 | Query LIKE básica |

## 2. Presupuestos de Recursos

| Recurso | Línea Base | Margen | Máximo | Alertar En |
|---------|------------|--------|--------|------------|
| CPU / núcleo | 40% | 30% | 70% | 60% |
| Memoria / pod | 512 MB | 256 MB | 1 GB | 800 MB |
| Conexiones DB | 50 | 30 | 80 | 70 |
| Egress de red | 100 Mbps | 50 Mbps | 200 Mbps | 150 Mbps |

## 3. Aplicación de Presupuestos

- [ ] Aserciones de latencia en CI (fallar build si p95 excede presupuesto)
- [ ] Gates de load test en pipeline de despliegue
- [ ] Validación de tamaño de payload en API gateway
- [ ] Circuit breaker en llamadas a dependencias que excedan latencia máxima
- [ ] Autoscaling disparado al 60% de CPU, no al 80%

## 4. Cadencia de Revisión

| Disparador | Acción | Responsable |
|------------|--------|-------------|
| Semanal | Revisar dashboards por desviación sobre presupuesto | SRE |
| Mensual | Ajustar presupuestos basado en crecimiento de tráfico | Plataforma |
| Trimestral | Re-negociar presupuestos con equipo de producto | Engineering Lead |
| Incidente | Auditoría de presupuesto post-incidente | Incident Commander |

Explicación

Un presupuesto de latencia es una cadena: frontend (100ms) + red (50ms) + API (200ms) + base de datos (40ms) = 390ms total. Si cualquier eslabón excede su asignación, toda la experiencia de usuario se degrada. La columna de margen existe porque el rendimiento del mundo real es ruidoso. Los presupuestos de dependencias evitan que un servicio downstream lento consuma todo el presupuesto de la API. Los presupuestos de throughput definen pools de conexiones y tamaños de caché. Los presupuestos de recursos evitan que un endpoint pesado límite recursos de otros en el mismo host.

Ejemplo de Cadena de Presupuesto de Latencia

Cuando un usuario hace clic en “Realizar Pedido”, la solicitud atraviesa múltiples capas. Cada capa tiene su propio presupuesto:

Usuario hace clic (0ms)
  └─ Renderizado del navegador (50ms)
       └─ CDN edge (20ms)
            └─ API gateway (10ms)
                 └─ Servicio de pedidos (80ms)
                      ├─ PostgreSQL (30ms)
                      ├─ Pasarela de pago (150ms)
                      └─ Servicio de inventario (40ms)
                 └─ Serializacion de respuesta (5ms)
            └─ Retorno CDN edge (20ms)
       └─ Renderizado del navegador (50ms)
Total: ~455ms (dentro del presupuesto de 500ms)

Si la pasarela de pago tarda 300ms en lugar de 150ms, el total salta a 605ms y el presupuesto se excede. El presupuesto de dependencia para la pasarela (200ms max) detectaría esto como violación antes que el presupuesto del endpoint.

Aplicación en CI con k6 Load Tests

Usa k6 para aplicar presupuestos de latencia en tu pipeline de CI:

import http from "k6/http";
import { check } from "k6";

export const options = {
  stages: [
    { duration: "30s", target: 50 },
    { duration: "1m", target: 100 },
    { duration: "30s", target: 0 },
  ],
  // Thresholds gate the build: tagged metrics enforce per-endpoint budgets
  thresholds: {
    'http_req_duration{endpoint:health}': ["p(95)<10"],
    'http_req_duration{endpoint:user}': ["p(95)<100"],
    'http_req_duration{endpoint:order}': ["p(95)<250"],
  },
};

export default function () {
  const healthRes = http.get(`${__ENV.BASE_URL}/health`, {
    tags: { endpoint: "health" },
  });
  check(healthRes, {
    "health p95 < 10ms": (r) => r.timings.duration < 10,
  });

  const userRes = http.get(`${__ENV.BASE_URL}/users/123`, {
    tags: { endpoint: "user" },
  });
  check(userRes, {
    "búsqueda de usuario p95 < 100ms": (r) => r.timings.duration < 100,
  });

  const orderRes = http.post(
    `${__ENV.BASE_URL}/orders`,
    JSON.stringify({ productId: 1, quantity: 2 }),
    { headers: { "Content-Type": "application/json" }, tags: { endpoint: "order" } }
  );
  check(orderRes, {
    "creación de pedido p95 < 250ms": (r) => r.timings.duration < 250,
  });
}

Ejecutar en CI con aplicación de presupuesto:

k6 run --env BASE_URL=https://staging.example.com load-test.js
# Exit code 1 si cualquier threshold se viola, fallando el build de CI

Monitoreo de Cumplimiento de Presupuesto con Prometheus

Rastrea violaciónes de presupuesto en producción con PromQL:

# Porcentaje de solicitudes dentro del presupuesto (por endpoint)
sum(rate(http_request_duration_seconds_bucket{le="0.1", endpoint="GET /users"}[5m]))
/
sum(rate(http_request_duration_seconds_count{endpoint="GET /users"}[5m]))
* 100

# Alertar cuando más del 1% de solicitudes exceden el presupuesto
(
  sum(rate(http_request_duration_seconds_count{endpoint="GET /users"}[5m]))
  -
  sum(rate(http_request_duration_seconds_bucket{le="0.1", endpoint="GET /users"}[5m]))
)
/
sum(rate(http_request_duration_seconds_count{endpoint="GET /users"}[5m]))
> 0.01

Dashboard de Seguimiento de Presupuesto

Crea un panel de dashboard en Grafana para cada endpoint mostrando:

  1. p95 de latencia actual como un stat único, coloreado verde/amarillo/rojo segun el presupuesto
  2. Tendencia de latencia de los últimos 7 días con una línea horizontal en el umbral del presupuesto
  3. Tasa de violación de presupuesto como porcentaje de solicitudes que exceden el objetivo
  4. Throughput vs presupuesto mostrando RPS actual contra el objetivo de RPS
  5. Desglose de latencia por dependencia mostrando la contribucion de cada servicio upstream a la latencia total

JSON de dashboard para un panel de presupuesto de latencia:

{
  "panels": [
    {
      "title": "GET /users - p95 Latencia vs Presupuesto",
      "type": "stat",
      "targets": [
        {
          "expr": "histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{endpoint=\"GET /users\"}[5m])) * 1000",
          "legendFormat": "p95 latencia (ms)"
        }
      ],
      "fieldConfig": {
        "defaults": {
          "thresholds": {
            "steps": [
              { "value": null, "color": "green" },
              { "value": 80, "color": "yellow" },
              { "value": 100, "color": "red" }
            ]
          },
          "unit": "ms"
        }
      }
    }
  ]
}

Los umbrales verde/amarillo/rojo mapean directamente al presupuesto: verde esta dentro del 80% del presupuesto, amarillo es 80-100%, y rojo esta sobre el presupuesto.

Cómo Derivar los Primeros Números del Presupuesto

No inventes objetivos de la nada — mide primero. Extrae 30 días de métricas de producción y toma el p95 por endpoint, luego fija el presupuesto en el p95 actual más un 20-30% de margen. Si no tienes datos de producción, parte de endpoints similares del mismo servicio o del presupuesto de dependencias: la dependencia más lenta más el overhead del gateway y la serialización marca tu piso. Tres errores a evitar en esta etapa: medir en ventanas cortas (el p95 de 5 minutos oscila salvajemente), promediar percentiles entre endpoints con perfiles de costo distintos, y medir rendimiento con caché caliente cuando la mayoría del tráfico de producción llega en frío. Los cold starts merecen su propia línea en arquitecturas serverless — un init de Lambda de 800ms se come por sí solo la mayor parte de un presupuesto de 1s.

Despliegue de Presupuestos Cuando Ya Estás por Encima

La mayoría de las APIs conocen los presupuestos cuando ya los están violando. No fijes números aspiracionales que nadie pueda cumplir — el presupuesto se vuelve decoración. En su lugar, aprieta gradualmente: fija el presupuesto en el p95 actual, registra violaciónes sin fallar el build durante dos semanas, y luego endurece un 10-15% por sprint mientras el equipo corrige a los principales infractores. Cuando un endpoint excede el presupuesto de forma permanente, escala explícitamente: o el producto acepta un SLO relajado para ese endpoint, o ingeniería recibe un ítem de trabajo para arreglarlo. Un presupuesto que todos ignoran es peor que no tener presupuesto — entrena al equipo para ignorar todas las métricas.

Errores de Medición

  • Promediar percentiles: el p95 de p95s por hora no es p95 — agrega latencia cruda y luego calcula el percentil.
  • Ventanas cortas: un p95 de 5 minutos en horas valle esconde la latencia de cola real; usa ventanas de 1h+ para presupuestos.
  • Atribución de dependencias ausente: un endpoint sobre presupuesto suele ser un servicio downstream sobre el suyo — revisa primero la latencia de dependencias.
  • Contaminación de health checks: excluye /health y el tráfico sintético de los percentiles o tus números se verán mejor que la realidad.
  • Medición en una sola región: los presupuestos medidos desde la misma región del servidor pierden el costo WAN que pagan los usuarios reales.

Gobernanza: Responsables, Excepciones y Burn Rate

Un presupuesto sin responsable se degrada. Asigna uno por capa: los presupuestos de endpoint pertenecen al equipo del servicio, los de dependencias a plataforma y los de recursos a SRE. El responsable revisa la desviación semanalmente y es la primera llamada cuando un gate falla.

Las excepciones necesitan fecha de caducidad. Cuando un equipo pide un presupuesto relajado — “checkout no puede cumplir 250ms este trimestre” — apruébalo con una fecha y un ticket de remediación adjunto. Una excepción sin caducidad se convierte silenciosamente en el nuevo presupuesto. Registra las excepciones abiertas en el mismo documento para que los revisores vean cuánta parte de la API corre fuera de contrato.

Rastrea el burn rate, no solo instantáneas. Un servicio al 96% del presupuesto durante tres semanas seguidas ya lo está violando — el número simplemente no ha cruzado la línea todavía. El burn rate (porcentaje de presupuesto consumido en el tiempo) convierte los presupuestos de artefacto post-mortem en alerta temprana. Grafícalo por endpoint: líneas planas son sanas, líneas ascendentes se priorizan.

Cómo Adaptar la Plantilla

Para una API interna pequeña, recorta la plantilla a latencia y throughput — los presupuestos de recursos y las filas por región añaden ceremonia sin beneficio. Para una API pública o un camino crítico de ingresos, extiéndela: añade presupuestos por región, una línea de cold start y una columna de quién aprobó cada número. La plantilla es una herramienta de negociación: lo que haga explícita la conversación entre producto e infraestructura merece entrar; todo lo demás es peso.

Un ejemplo resuelto ayuda a los equipos primerizos. Supón que /checkout tiene un presupuesto de 500ms: gateway 30ms + auth 40ms + servicio de pedidos 80ms + pasarela de pago 150ms + inventario 60ms + serialización 20ms = 380ms, dejando 120ms de margen. Cuando el pago se degrada a 220ms, el total llega a 450ms — todavía dentro del presupuesto del endpoint, pero el presupuesto de dependencia del pago (200ms) dispara primero. Ese orden es la clave: los presupuestos de dependencia detectan el eslabón que falla antes de que el presupuesto del endpoint se ponga en rojo y los usuarios lo noten.

En organizaciones con varios equipos compartiendo plataforma, trata la plantilla como lenguaje de contrato versionado. El presupuesto de endpoint de un equipo es el presupuesto de dependencia de otro — el techo de 200ms del servicio de pago es a la vez la restricción del servicio de pedidos y la promesa del equipo de pago. Mantén el documento en control de versiones, referéncialo en el checklist de revisión de diseño de API y exige un cambio firmado (aunque sea un PR de una línea) cada vez que un número se mueva. La deriva sin firma es como “el presupuesto dice 250ms” se convierte calladamente en “el presupuesto dice lo que producción haga hoy”. Retira también las filas que dejaron de importar: una dependencia eliminada hace seis meses no debería seguir confundiendo al próximo lector.

Variantes

ContextoEnfoqueNotas
GraphQLPresupuesto de complejidad de queryLimitar costo total de campos por query, no solo profundidad
API de streamingThroughput por shardPresupuesto por particion, no global
SDK móvilTamano de bundle + frecuencia de llamadasPresupuesto incluye tamaño de payload y número de requests paralelos
gRPCPropagacion de deadline por métodoUsar context deadlines para aplicar presupuestos entre hops

Lo que funciona

  1. Establecer presupuestos durante el diseno, no después del lanzamiento
  2. Incluir presupuestos en checklists de revision de diseno de API
  3. Fallar builds de CI cuando tests de latencia excedan el presupuesto por cualquier margen
  4. Reservar 20-30% de margen en cada presupuesto para picos de trafico
  5. Documentar quien puede aprobar excepciones de presupuesto (usualmente el engineering lead)
  6. Rastrear la tasa de quema del presupuesto, no solo valores actuales
  7. Separar presupuestos de lectura y escritura ya que tienen perfiles de costo diferentes

Errores Comunes

  1. Basar presupuestos en condiciones de laboratorio en lugar de percentiles de producción
  2. Ignorar latencia de dependencias al calcular presupuestos de endpoint
  3. Establecer un presupuesto global para todos los endpoints sin importar criticidad
  4. Tratar los presupuestos como decisiones unicas en lugar de documentos vivos
  5. No hacer cumplir presupuestos en CI o gates de despliegue
  6. No contabilizar cold starts en arquitecturas serverless
  7. Establecer presupuestos sin input del equipo de producto, llevando a objetivos irreales

Solución de Problemas

  • Alta latencia entre servicios: traza la ruta de la request. Busca cadenas síncronas, caché ausente y payloads sobredimensionados que cruzan fronteras de red.
  • Punto único de fallo: identifica componentes sin redundancia. Añade réplicas, failover o circuit breakers antes de escalar tráfico.
  • Acoplamiento inesperado entre servicios: revisa bases de datos, librerías y esquemas compartidos. Los contextos acotados deben ser dueños de sus datos y exponer interfaces estables.
  • Picos de costo tras escalar: ajusta el tamaño de las instancias y usa autoscaling con límites. La capacidad reservada o las instancias spot pueden reducir el gasto en estado estable.
  • Difícil razonar sobre el sistema: mantén ADRs y mapas de dependencias de servicios. Valida los diagramas con datos de observabilidad.
Mermaid flowchart LR diagram

Errores Comunes en Producción

  • Escribir “rápido” o “baja latencia” en la columna de notas en lugar de números — un presupuesto sin número es un deseo.
  • Fijar el presupuesto una vez y nunca revisarlo cuando el tráfico se duplica.
  • Guardar el presupuesto en una wiki que nadie abre durante una revisión de incidente.
  • Presupuestos sin responsable asignado — cuando el p95 deriva, nadie responde por el ajuste.
  • Copiar la tabla de ejemplo sin eliminar filas que no aplican (no toda API tiene un servicio de búsqueda).

Lectura Adicional

Preguntas frecuentes

Que pasa cuando un endpoint excede su presupuesto?

Primero, optimiza: agrega caching, desnormaliza queries o pagina. Si el endpoint fundamentalmente necesita más tiempo, escala al engineering lead quien puede aprobar un aumento de presupuesto o degradar el SLO. Nunca ignores violaciónes de presupuesto silenciosamente.

Como presupuesto para endpoints con patrones de trafico desconocidos?

Comienza con estimaciones conservadoras basadas en endpoints similares. Monitorea por 2 semanas después del lanzamiento, luego ajusta. Usa feature flags para rampar trafico gradualmente y observar rendimiento real antes de comprometerte con un presupuesto.

Deberian los presupuestos aplicar a endpoints batch / async?

Si, pero usa métricas diferentes. Para async, presupuesta profundidad de cola, tasa de procesamiento (items/segundo) y latencia end-to-end desde enqueue hasta completion. El throughput importa mas que el tiempo de respuesta para jobs batch.

Como manejo violaciónes de presupuesto durante un pico de trafico?

El autoscaling debería dispararse antes del agotamiento del presupuesto (al 60% de CPU, no al 80%). Si el pico es inesperado, aumenta temporalmente el presupuesto y programa una revision post-incidente. Si el pico es esperado (campaña, lanzamiento), pre-aprovisiona capacidad y eleva los presupuestos con anticipación.

Cual es la diferencia entre un presupuesto de rendimiento y un SLO?

Un SLO es un objetivo de confiabilidad acordado con consumidores (ej. 99.9% de solicitudes bajo 200ms). Un presupuesto de rendimiento es una restriccion interna de ingenieria que te ayuda a cumplir el SLO (ej. queries de base de datos bajo 40ms para que la API pueda mantenerse bajo 200ms). Los presupuestos son la descomposicion de los SLOs en asignaciónes por capa.

Deberia usar p95 o p99 para presupuestos de latencia?

Usa p95 para endpoints orientados al usuario donde la mayoría de la experiencia importa. Usa p99 para caminos criticos como pago y autenticación donde cada solicitud cuenta. Usar p50 (mediana) oculta problemas de latencia de cola que afectan a usuarios reales.

Con que frecuencia debo revisar y ajustar los presupuestos?

Revisar mensualmente para servicios de rápido crecimiento. Trimestralmente para servicios estables. Despues de cualquier incidente P1, auditar si el presupuesto era realista o necesita ajuste. Un presupuesto que nadie actualiza es un presupuesto que nadie revisa.

Como establezco un presupuesto de tamaño de payload?

Mide el percentil 95 de tamaños de request y response en producción. Establece el presupuesto en 2x el p95 para permitir margen. Aplica el presupuesto en el API gateway con un rechazo duro para payloads que excedan el límite. Para respuestas, usa paginación y selección de campos para mantener los tamaños de payload dentro del presupuesto.

Puedo tener presupuestos diferentes para el mismo endpoint en diferentes regiónes?

Si. Los presupuestos de latencia deben contabilizar la distancia geográfica. Un endpoint que sirve usuarios en Europa desde un data center en EE.UU. tendra mayor latencia que el mismo endpoint sirviendo usuarios de EE.UU. Establece presupuestos por región y considera edge caching o despliegues regiónales para endpoints sensibles a latencia.

Que herramientas debo usar para rastrear el cumplimiento del presupuesto?

Usa Prometheus para recolección de métricas, Grafana para dashboards, y k6 o Locust para load testing en CI. Para alertas de presupuesto, configura Prometheus alertmanager para notificar a on-call cuando la tasa de violación de presupuesto exceda 1% en 5 minutos.