Pregúntale hoy a Marta cómo sabe que la tienda de AlpinaShop funciona. La respuesta honesta es: porque nadie se ha quejado. Y si algo va mal, se entera de una de estas tres formas: un cliente escribe a atención al cliente, Dani abre la web por casualidad y la nota lenta, o Lucía ve al día siguiente que las ventas de ayer fueron raras.

Las tres tienen el mismo defecto: la detección la hace una persona, tarde y por casualidad. Y el coste de esa forma de enterarse es alto y silencioso. Un incidente de veinte minutos en plena campaña de otoño puede pasar completamente desapercibido y llevarse por delante cientos de pedidos.

Esta lección cambia eso. Al terminar, AlpinaShop tendrá un panel que muestra el estado de la tienda de un vistazo, comprobaciones que la vigilan desde cuatro continentes, alertas que llegan al móvil de Marta antes de que ningún cliente escriba, y un agrupador automático de excepciones que avisa cuando un despliegue introduce un error nuevo.

Una nota previa sobre el nombre. Stackdriver fue una empresa que Google adquirió en 2014 y cuyo producto dio origen a toda la suite de operaciones. El nombre se retiró en 2020 y hoy los servicios se llaman Cloud Monitoring, Cloud Logging, Cloud Trace, Cloud Profiler y Error Reporting. Verás "Stackdriver" en documentación antigua, en nombres de bibliotecas heredadas y en conversaciones de gente con cierta veteranía; conviene reconocerlo, pero es un nombre histórico.

Contenido

  1. Observabilidad y sus tres pilares
  2. El modelo de datos de métricas
  3. El espacio de métricas: ver los tres proyectos a la vez
  4. Métricas de plataforma que ya tienes gratis
  5. Explorar: alineadores, agregaciones y por qué la media miente
  6. El panel de la campaña de otoño
  7. El panel como JSON versionable
  8. MQL y PromQL para consultas avanzadas
  9. Alertas: anatomía de una política
  10. Canales de notificación y las tres alertas de AlpinaShop
  11. Fatiga de alertas: la conversación incómoda
  12. Métricas personalizadas desde la aplicación
  13. Comprobaciones de disponibilidad
  14. Error Reporting: excepciones agrupadas
  15. El agente de operaciones en las VM del MIG
  16. Coste de la observabilidad

  1. Observabilidad y sus tres pilares

Monitorización es comprobar si las cosas que sabías que podían fallar están fallando. Observabilidad es la propiedad de un sistema que permite entender qué le está pasando por dentro a partir de lo que emite hacia fuera, incluidos los fallos que no anticipaste.

La diferencia no es académica. Un panel con la CPU de las VM es monitorización: responde a "¿está alta la CPU?". Poder responder a "¿por qué los clientes de Canarias tienen el checkout lento desde el martes?" sin desplegar nada nuevo es observabilidad.

Se apoya en tres pilares:

Pilar Qué responde Naturaleza Servicio Lección
Métricas ¿Cuánto? ¿Cuántos? ¿Qué tendencia? Números agregados en el tiempo Cloud Monitoring Esta
Logs ¿Qué pasó exactamente en este caso? Eventos discretos con detalle Cloud Logging 06-06
Trazas ¿Dónde se fue el tiempo en esta petición? Recorrido entre componentes Cloud Trace 06-06

Cada uno tiene un perfil distinto de coste y de utilidad, y por eso conviven:

  • Las métricas son baratas de almacenar y consultar porque son agregados, permiten ver meses de historia y son la base natural de las alertas. Pero no te dicen qué le pasó a un cliente concreto: te dicen que el p95 subió.
  • Los logs tienen todo el detalle de cada evento, y por eso son caros y hay que ser selectivo. Responden preguntas concretas sobre casos concretos.
  • Las trazas muestran cómo se reparte el tiempo de una petición entre servicios, y son lo único que responde a "¿quién está tardando?" en un sistema con varias piezas.

El recorrido típico de un incidente los usa los tres en orden: una alerta sobre una métrica avisa de que algo pasa, el panel de métricas acota qué y dónde, los logs dicen qué está fallando exactamente, y la traza explica por qué. Ese recorrido completo se hace de principio a fin en 06-06.

Un aviso de alcance: aquí se construyen métricas, paneles y alertas. Los objetivos de nivel de servicio (SLO) y los presupuestos de error —definir formalmente qué significa "funcionar bien" y cuánto fallo es tolerable— llegan en 07-06. Aquí se instalan los instrumentos; allí se decide qué números son aceptables.

  1. El modelo de datos de métricas

Casi todos los problemas que la gente tiene con Cloud Monitoring vienen de no tener claro este modelo. Merece cinco minutos.

Una serie temporal es la unidad fundamental, y se identifica por la combinación de tres cosas:

serie temporal = tipo de métrica + recurso monitorizado + valores de las etiquetas
Componente Qué es Ejemplo
Tipo de métrica Qué se mide loadbalancing.googleapis.com/https/request_count
Recurso monitorizado Qué objeto lo emite https_lb_rule con su proyecto y su nombre
Etiquetas Dimensiones para filtrar y agrupar response_code_class="500", matched_url_path_rule="/catalogo"
Puntos Pares (instante, valor) (2026-08-05T10:00:00Z, 142)

Ese diseño explica una cosa que sorprende al principio: el número de series temporales se multiplica con las etiquetas. Si una métrica tiene 3 clases de código de respuesta, 5 rutas y 2 regiones, son 30 series. Si alguien añade una etiqueta con el identificador de cliente, y hay 50.000 clientes, son 1.500.000 series. Eso se llama explosión de cardinalidad, se paga y puede llegar a hacer inutilizable la métrica. Volveremos a ello en el apartado 12, que es donde se comete el error.

Los tres tipos de métrica

Distinguirlos es imprescindible porque cada uno se consulta de forma distinta:

Tipo Qué representa Ejemplo Cómo se consulta
Medidor (gauge) Un valor instantáneo que sube y baja CPU al 42 %, 87 conexiones abiertas Se lee directamente
Contador acumulado (cumulative) Un total que solo crece desde un origen Peticiones totales servidas Hay que derivarlo: tasa por segundo
Distribución (distribution) Un histograma de valores en un intervalo Latencias de todas las peticiones Se extraen percentiles

El contador es el que más confusión causa. request_count del balanceador es acumulado: su valor crece indefinidamente. Si lo pintas tal cual, ves una rampa ascendente que no dice nada. Lo que quieres es la tasa: cuántas peticiones por segundo. Por eso a los contadores se les aplica siempre un alineador rate o delta.

La distribución es la más valiosa y la más desaprovechada. Una métrica de latencia como distribución no guarda un número por intervalo: guarda un histograma completo. Eso permite preguntar el percentil 50, el 95 y el 99 a posteriori, sin haber decidido de antemano cuál te interesaba. Si en su lugar guardaras solo la latencia media, habrías perdido la información para siempre, y la media es precisamente el estadístico menos útil aquí, como veremos en el apartado 5.

  1. El espacio de métricas: ver los tres proyectos a la vez

AlpinaShop tiene sus recursos repartidos en tres proyectos: la tienda en alpinashop-prod, las pruebas en alpinashop-dev y la analítica en alpinashop-datos. Por defecto, cada proyecto tiene su propia vista de métricas, lo que obliga a saltar entre tres consolas para entender un incidente. Insostenible.

Un espacio de métricas (metrics scope) resuelve esto: un proyecto actúa de proyecto de ámbito y agrega las métricas de varios proyectos monitorizados.

flowchart TD
    A[alpinashop-prod<br/>PROYECTO DE ÁMBITO] --> D[Espacio de métricas único:<br/>paneles y alertas de los tres]
    B[alpinashop-dev] --> D
    C[alpinashop-datos] --> D
# Añadir los otros dos proyectos al espacio de métricas de alpinashop-prod
gcloud beta monitoring metrics-scopes create \
  --monitored-project=alpinashop-dev \
  --project=alpinashop-prod

gcloud beta monitoring metrics-scopes create \
  --monitored-project=alpinashop-datos \
  --project=alpinashop-prod

Un detalle de diseño que conviene pensar antes de ejecutar: ¿cuál debe ser el proyecto de ámbito? Usar alpinashop-prod es lo más habitual y lo más simple. La alternativa —crear un proyecto dedicado, por ejemplo alpinashop-observabilidad— es más limpia conceptualmente porque separa "operar la plataforma" de "ser la plataforma", y permite dar acceso de lectura a las métricas sin dar ningún acceso a producción. Para AlpinaShop, con tres proyectos y tres personas, alpinashop-prod es suficiente; en una organización con veinte proyectos, el proyecto dedicado gana claramente.

Y una advertencia importante: el espacio de métricas unifica la vista, no los permisos. Quien consulta un panel que muestra métricas de alpinashop-datos necesita permisos de lectura de monitorización sobre ese proyecto. Es coherente con 03-04, y evita que agregar la vista se convierta en una vía indirecta de exponer información.

  1. Métricas de plataforma que ya tienes gratis

Aquí hay una buena noticia que mucha gente desconoce: GCP ya está recogiendo cientos de métricas de tus recursos, sin que hayas hecho nada y sin coste añadido. Toda la infraestructura de los módulos 2, 3 y 4 lleva meses emitiendo datos que nadie ha mirado.

Las que importan para AlpinaShop:

Recurso Métrica Qué indica
Balanceador https/request_count Peticiones por segundo, con clase de código
Balanceador https/total_latencies Latencia extremo a extremo (distribución)
Balanceador https/backend_latencies Latencia solo del backend
Balanceador https/backend_request_count Peticiones que llegan al backend (frente a CDN)
Compute Engine / MIG instance/cpu/utilization Saturación de CPU
Compute Engine instance/disk/read_ops_count Presión de disco
Cloud SQL database/cpu/utilization CPU de alpinashop-pedidos
Cloud SQL database/network/connections Conexiones abiertas
Cloud SQL database/disk/utilization Espacio ocupado
Cloud SQL database/replication/replica_lag Retraso de la réplica
Pub/Sub subscription/num_undelivered_messages Mensajes sin confirmar
Pub/Sub subscription/oldest_unacked_message_age Antigüedad del más viejo
BigQuery query/scanned_bytes Bytes procesados: coste directo
GKE container/cpu/limit_utilization Uso frente al límite
Cloud Functions function/execution_count Invocaciones (recuerda 06-03)
Cloud Functions function/execution_times Duración (distribución)
Cloud Run request_count, request_latencies Igual que el balanceador
Cloud CDN https/request_count filtrado por cache_result Ratio de aciertos

La tabla que de verdad se usa en un incidente es la inversa: del síntoma a la métrica.

Síntoma observado Métrica que hay que mirar Qué significa si está mal
"La web va lenta" https/total_latencies p95 y p99 Confirma o desmiente la percepción
"Va lenta" y el backend está bien Comparar total_latencies con backend_latencies Si difieren mucho, el problema es de red o de cliente
Errores 500 https/request_count filtrado response_code_class=500 Cuántos y desde cuándo
Lentitud + CPU alta en el MIG instance/cpu/utilization Falta capacidad: revisar el autoescalado
Lentitud + CPU baja en todas partes database/network/connections Probable agotamiento del pool de conexiones
Errores tras un despliegue request_count 5xx + Error Reporting Regresión introducida por el despliegue
Datos analíticos desactualizados num_undelivered_messages El consumidor no da abasto o está caído
Factura de BigQuery alta query/scanned_bytes por usuario Alguien hace SELECT * sobre el histórico
Factura de red alta https/request_count por cache_result El ratio de aciertos de CDN ha caído

Esa última fila conecta directamente con 03-03: si el ratio de aciertos de Cloud CDN cae, el tráfico va al backend, la factura de salida sube y la latencia empeora. Es un fallo silencioso perfecto —nada se rompe, todo se degrada— y solo se detecta mirando la métrica.

  1. Explorar: alineadores, agregaciones y por qué la media miente

El explorador de métricas es la herramienta de consulta interactiva. Su modelo tiene cuatro pasos y conviene entenderlos porque son los mismos que después aparecen en paneles y alertas.

flowchart LR
    A[1. Seleccionar<br/>métrica y recurso] --> B[2. Filtrar<br/>por etiquetas]
    B --> C[3. ALINEAR<br/>dentro de cada serie]
    C --> D[4. AGREGAR<br/>entre series]
    D --> E[Gráfico]

Alinear convierte los puntos crudos de cada serie en puntos regulares de un intervalo fijo. Agregar combina varias series en menos series o en una sola. El orden importa y confundirlos produce números sin sentido.

Alineador Qué hace Para qué tipo Ejemplo
rate Variación por segundo Contadores Peticiones por segundo
delta Diferencia en el intervalo Contadores Peticiones en 60 s
mean Media del intervalo Medidores CPU media por minuto
max / min Extremos del intervalo Medidores Pico de conexiones
percentile_95 Percentil dentro del intervalo Distribuciones Latencia p95
Agregación Qué hace Ejemplo
sum Suma entre series Total de peticiones de todas las instancias
mean Media entre series CPU media del MIG
max Máximo entre series La instancia más cargada
count Cuántas series hay Número de instancias vivas
Agrupar por etiqueta Una serie por valor Latencia por ruta

Por qué la media miente

Este es el concepto más importante del apartado, y probablemente el que más veces se explica mal en el sector.

Imagina 1.000 peticiones al catálogo en un minuto. 950 tardan 100 ms y 50 tardan 8 segundos. La media es:

(950 × 100 ms + 50 × 8000 ms) / 1000 = 495 ms

Un panel con la media muestra 495 ms. Parece aceptable. Y sin embargo 50 clientes por minuto están esperando ocho segundos, que es tiempo de sobra para irse a otra web. La media ha ocultado exactamente el problema que buscabas.

Los percentiles cuentan otra historia:

Estadístico Valor Qué significa de verdad
Media 495 ms Un número que no le ocurre a nadie
p50 (mediana) 100 ms La mitad de los clientes ven esto
p95 ~100 ms El 95 % está bien
p99 8.000 ms El 1 % peor sufre 8 segundos

Tres reglas prácticas que conviene adoptar sin excepciones:

  1. Para latencia, siempre percentiles, nunca media. El p50 dice cómo es la experiencia típica; el p95 y el p99 dicen cómo de mal está lo malo.
  2. Nunca promedies percentiles entre series. La media de los p95 de diez instancias no es el p95 del conjunto: es un número sin significado estadístico. Cloud Monitoring calcula el percentil sobre la distribución combinada si le pides percentile_95 como alineador y sum como agregación de distribuciones; hacerlo al revés produce basura.
  3. El p99 importa más de lo que su nombre sugiere. Con un millón de peticiones al día, el p99 son 10.000 peticiones. Y no le tocan al azar a 10.000 clientes distintos: suelen concentrarse en los que tienen carritos grandes o históricos largos, es decir, los mejores clientes.

  1. El panel de la campaña de otoño

La campaña de otoño es el pico comercial de AlpinaShop. Marta quiere una pantalla que responda de un vistazo a "¿está la tienda bien?".

El principio de diseño, importado de la práctica de SRE: un panel debe contar una historia de arriba abajo, empezando por lo que percibe el cliente y terminando por las causas técnicas. Si al mirarlo hay que pensar, el panel está mal.

Fila Gráfico Métrica Por qué está ahí
1. ¿Llega tráfico? Peticiones/s https/request_count con rate y sum Un desplome es tan grave como un pico
1 Tasa de error 5xx request_count filtrado / total El indicador más directo de dolor
2. ¿Es rápido? Latencia p50/p95/p99 https/total_latencies Tres líneas en el mismo gráfico
2 Latencia por ruta Igual, agrupado por matched_url_path_rule Aísla qué parte va lenta
3. ¿Aguanta? CPU del MIG instance/cpu/utilization, mean y max La media oculta la instancia caliente
3 Instancias activas count de series del MIG ¿Está escalando?
4. ¿Y la BD? Conexiones a Cloud SQL database/network/connections Causa habitual de lentitud sin CPU
4 CPU de Cloud SQL database/cpu/utilization Consultas pesadas
5. ¿Y la CDN? Ratio de aciertos request_count por cache_result Coste y latencia
5 Bytes servidos https/response_bytes_count Detecta cambios de patrón

Dos decisiones de diseño que merecen explicación.

La CPU del MIG se muestra dos veces, mean y max. Si diez instancias están al 20 % y una al 98 %, la media dice 27 % —aparentemente sano— mientras esa instancia está saturada y sirviendo peticiones lentísimas. Es el mismo error conceptual que promediar latencias, aplicado a la capacidad. La media oculta los desequilibrios; el máximo los delata.

Latencia y errores están arriba, la infraestructura abajo. El orden refleja la pregunta que se hace de verdad en un incidente: primero "¿sufren los clientes?" y solo después "¿por qué?". Un panel que empieza por la CPU invita a mirar métricas de infraestructura que pueden estar perfectas mientras la tienda está caída.

  1. El panel como JSON versionable

Un panel construido a clics en la consola es un activo frágil: nadie sabe quién lo cambió, no se puede replicar en otro proyecto y desaparece si alguien lo borra. Todo panel de Cloud Monitoring tiene una representación en JSON que se puede exportar, versionar en Git —siguiendo 06-02— y recrear.

# Exportar un panel existente
gcloud monitoring dashboards list --project=alpinashop-prod --format=json
gcloud monitoring dashboards describe DASHBOARD_ID \
  --project=alpinashop-prod --format=json > paneles/campana-otono.json

# Crear o actualizar desde el fichero
gcloud monitoring dashboards create --config-from-file=paneles/campana-otono.json \
  --project=alpinashop-prod

Un fragmento con los dos gráficos de la fila 1, que muestra la estructura sin abrumar:

{
  "displayName": "AlpinaShop - Campaña de otoño",
  "mosaicLayout": {
    "columns": 12,
    "tiles": [
      {
        "width": 6, "height": 4, "xPos": 0, "yPos": 0,
        "widget": {
          "title": "Peticiones por segundo",
          "xyChart": {
            "dataSets": [{
              "timeSeriesQuery": {
                "timeSeriesFilter": {
                  "filter": "metric.type=\"loadbalancing.googleapis.com/https/request_count\" resource.type=\"https_lb_rule\" resource.label.\"url_map_name\"=\"alpinashop-url-map\"",
                  "aggregation": {
                    "alignmentPeriod": "60s",
                    "perSeriesAligner": "ALIGN_RATE",
                    "crossSeriesReducer": "REDUCE_SUM"
                  }
                }
              },
              "plotType": "LINE"
            }]
          }
        }
      },
      {
        "width": 6, "height": 4, "xPos": 6, "yPos": 0,
        "widget": {
          "title": "Latencia p50 / p95 / p99 (ms)",
          "xyChart": {
            "dataSets": [
              {
                "legendTemplate": "p50",
                "timeSeriesQuery": {
                  "timeSeriesFilter": {
                    "filter": "metric.type=\"loadbalancing.googleapis.com/https/total_latencies\" resource.type=\"https_lb_rule\"",
                    "aggregation": {
                      "alignmentPeriod": "60s",
                      "perSeriesAligner": "ALIGN_PERCENTILE_50",
                      "crossSeriesReducer": "REDUCE_MEAN"
                    }
                  }
                },
                "plotType": "LINE"
              },
              {
                "legendTemplate": "p99",
                "timeSeriesQuery": {
                  "timeSeriesFilter": {
                    "filter": "metric.type=\"loadbalancing.googleapis.com/https/total_latencies\" resource.type=\"https_lb_rule\"",
                    "aggregation": {
                      "alignmentPeriod": "60s",
                      "perSeriesAligner": "ALIGN_PERCENTILE_99",
                      "crossSeriesReducer": "REDUCE_MEAN"
                    }
                  }
                },
                "plotType": "LINE"
              }
            ]
          }
        }
      }
    ]
  }
}

Fíjate en la correspondencia con el apartado 5: perSeriesAligner es el alineador —ALIGN_RATE para el contador, ALIGN_PERCENTILE_99 para la distribución— y crossSeriesReducer es la agregación. El JSON no es más que la forma escrita de lo que hiciste en el explorador.

La forma práctica de trabajar es construir el panel en la consola hasta que quede bien, exportarlo, guardarlo en alpinashop-infra/paneles/ y a partir de ahí gestionarlo como código. Y cuando llegue Terraform en 06-07, el recurso google_monitoring_dashboard consume exactamente este JSON, de modo que el panel pasa a crearse junto a la infraestructura que monitoriza.

  1. MQL y PromQL para consultas avanzadas

La interfaz de filtros y agregaciones cubre la mayoría de los casos, pero hay preguntas que no expresa: proporciones entre dos métricas, uniones, cálculos derivados. Para eso hay dos lenguajes.

MQL (Monitoring Query Language) es el lenguaje propio de Cloud Monitoring, con sintaxis de tubería:

fetch https_lb_rule
| metric 'loadbalancing.googleapis.com/https/request_count'
| filter resource.url_map_name == 'alpinashop-url-map'
| align rate(1m)
| every 1m
| group_by [metric.response_code_class], [valor: sum(value.request_count)]

Y el caso donde MQL se vuelve imprescindible, la tasa de error como proporción:

{
  fetch https_lb_rule :: loadbalancing.googleapis.com/https/request_count
  | filter metric.response_code_class == '500'
  | align rate(1m) | every 1m | group_by [], [errores: sum(value.request_count)]
  ;
  fetch https_lb_rule :: loadbalancing.googleapis.com/https/request_count
  | align rate(1m) | every 1m | group_by [], [total: sum(value.request_count)]
}
| join
| value [tasa_error: errores / total * 100]

Eso —dividir dos series distintas— no se puede expresar con filtros y agregaciones. Y es justo lo que quieres para alertar: el 2 % de errores es lo relevante, no "200 errores", porque 200 errores sobre 100.000 peticiones es ruido y sobre 500 es una catástrofe.

PromQL es el lenguaje de Prometheus, soportado en Cloud Monitoring a través de Managed Service for Prometheus. La misma consulta:

sum(rate(loadbalancer_googleapis_com:https_request_count{response_code_class="500"}[1m]))
/
sum(rate(loadbalancer_googleapis_com:https_request_count[1m])) * 100
Criterio MQL PromQL
Alcance Solo GCP Estándar del sector
Portabilidad Ninguna Alta: Prometheus, Grafana, otras nubes
Métricas de GKE Funciona Natural: es lo que emiten las aplicaciones
Comunidad y ejemplos Limitada Enorme
Recomendación 2026 Para casos puntuales en GCP Preferible si vienes de Kubernetes

Para AlpinaShop, que tiene la tienda en GKE y aspira a no atarse en exceso a un proveedor, PromQL es la apuesta más sensata a medio plazo. MQL sigue siendo útil para consultas puntuales sobre métricas de plataforma que no tienen equivalente Prometheus.

  1. Alertas: anatomía de una política

Un panel solo sirve si alguien lo mira. Una alerta trabaja por ti.

Una política de alerta tiene cuatro piezas, y cada una responde a una pregunta distinta:

flowchart LR
    A[CONDICIÓN<br/>qué medir y qué umbral] --> B[DURACIÓN<br/>cuánto tiempo mal]
    B --> C[AGREGACIÓN<br/>sobre qué conjunto]
    C --> D[NOTIFICACIÓN<br/>a quién y cómo]
    D --> E[DOCUMENTACIÓN<br/>qué hacer al recibirla]

La duración es la pieza más infravalorada. Sin ella, cualquier pico instantáneo dispara una alerta. Un pico de latencia de 15 segundos porque el autoescalador arrancó una instancia no es un incidente: es el sistema funcionando. Una alerta que salta por eso enseña al equipo a ignorarla, que es lo peor que le puede pasar a una alerta.

El criterio para elegir la duración es honesto y sencillo: ¿cuánto tiempo tiene que estar mal esto para que merezca despertar a alguien? Si la respuesta es "cinco minutos", pon cinco minutos.

Una política completa en JSON, la de la tasa de error de AlpinaShop:

{
  "displayName": "AlpinaShop - Tasa de error 5xx elevada",
  "combiner": "OR",
  "conditions": [
    {
      "displayName": "Errores 5xx por encima del 2% durante 5 minutos",
      "conditionMonitoringQueryLanguage": {
        "query": "{ fetch https_lb_rule :: loadbalancing.googleapis.com/https/request_count | filter metric.response_code_class == '500' | align rate(1m) | every 1m | group_by [], [e: sum(value.request_count)] ; fetch https_lb_rule :: loadbalancing.googleapis.com/https/request_count | align rate(1m) | every 1m | group_by [], [t: sum(value.request_count)] } | join | value [tasa: e / t * 100] | condition tasa > 2 '%'",
        "duration": "300s",
        "trigger": { "count": 1 }
      }
    }
  ],
  "alertStrategy": {
    "autoClose": "1800s"
  },
  "notificationChannels": [
    "projects/alpinashop-prod/notificationChannels/CANAL_SLACK_ALERTAS",
    "projects/alpinashop-prod/notificationChannels/CANAL_CORREO_INFRA"
  ],
  "documentation": {
    "mimeType": "text/markdown",
    "content": "## Tasa de error 5xx elevada\n\n**Qué significa:** más del 2 % de las peticiones a la tienda devuelven error de servidor.\n\n**Impacto:** los clientes ven páginas de error. Se están perdiendo pedidos.\n\n**Primeros pasos:**\n1. Panel *Campaña de otoño*: ¿la latencia también ha subido?\n2. ¿Hubo un despliegue en los últimos 30 minutos? Revisar Cloud Build.\n3. Explorador de logs: `severity=ERROR` en los últimos 15 minutos (06-06).\n4. Comprobar conexiones de Cloud SQL: causa frecuente.\n\n**Vuelta atrás:** promocionar la imagen anterior con el pipeline de 06-01.\n\n**Escalado:** si en 15 minutos no hay diagnóstico, avisar a Marta."
  }
}
gcloud alpha monitoring policies create \
  --policy-from-file=alertas/tasa-error-5xx.json \
  --project=alpinashop-prod

El campo documentation es el que separa una alerta útil de una alerta que genera ansiedad. Llega al móvil de alguien a las once de la noche; sin instrucciones, esa persona empieza desde cero, con sueño y con prisa. Con las cuatro primeras comprobaciones escritas, sabe qué mirar. Y el autoClose de 30 minutos evita que un incidente ya resuelto deje un incidente abierto para siempre.

  1. Canales de notificación y las tres alertas de AlpinaShop

Un canal define cómo llega la alerta:

Canal Latencia Interrumpe Uso en AlpinaShop
Correo Minutos No Avisos informativos, resúmenes
Slack Segundos Poco Canal #alpinashop-alertas, el principal
SMS Segundos Sí Solo para lo crítico
PagerDuty / Opsgenie Segundos Sí, con escalado Cuando haya guardias formales (07-06)
Webhook Segundos Depende Automatizaciones propias
Pub/Sub Segundos No Reaccionar con una función (06-03)
gcloud beta monitoring channels create \
  --display-name="Slack alertas AlpinaShop" \
  --type=slack \
  --channel-labels=channel_name="#alpinashop-alertas" \
  --project=alpinashop-prod

El canal de Pub/Sub merece una mención por lo que habilita: una alerta puede publicar en un topic y una Cloud Function de 06-03 puede reaccionar automáticamente —crear una incidencia, ejecutar un diagnóstico, o incluso una acción correctora acotada—. Es la puerta a la respuesta automática, con la precaución evidente de que una automatización que actúa sobre producción debe estar muy bien acotada.

Las tres alertas con las que arranca AlpinaShop

Deliberadamente tres. No treinta.

Alerta 1 — Tasa de error 5xx > 2 % durante 5 minutos. Canal: Slack + SMS a Marta.

Razonamiento del umbral: la tasa de error normal de la tienda es del 0,1-0,3 %, dominada por peticiones a URLs que ya no existen. El 2 % es un orden de magnitud por encima del ruido: no salta por variación natural, y a ese nivel hay clientes viendo errores. Es proporción, no valor absoluto, por lo dicho en el apartado 8. Cinco minutos filtran los picos de un despliegue.

Alerta 2 — Latencia p95 > 2 segundos durante 10 minutos. Canal: Slack.

Razonamiento: el p95 habitual de la tienda ronda los 400 ms. Dos segundos es el punto donde la percepción cambia de "va bien" a "va lento" y el abandono de carrito empieza a subir. Se elige p95 y no p99 porque el p99 es más volátil y generaría más ruido; y se elige una duración larga, 10 minutos, porque la lentitud transitoria es habitual y no requiere acción inmediata. Sin SMS: es un problema que se atiende en horario laboral.

Alerta 3 — Mensajes sin confirmar en pedidos-nuevos > 1.000 durante 15 minutos. Canal: Slack + correo.

Razonamiento: en operación normal la cola está prácticamente vacía porque los consumidores van al día. Mil mensajes acumulados quince minutos significa que el consumidor está caído o no da abasto, y eso quiere decir que hay pedidos que no se están procesando. Es el ejemplo de alerta que detecta un fallo invisible desde fuera: la web funciona, los clientes compran, todo parece bien, y los pedidos se están apilando sin procesar.

Alerta Umbral Duración Canales Qué protege
Errores 5xx > 2 % 5 min Slack + SMS Clientes viendo errores
Latencia p95 > 2 s 10 min Slack Experiencia degradada
Cola de pedidos > 1.000 msg 15 min Slack + correo Fallo invisible desde fuera

Fíjate en el patrón: cada alerta detecta un tipo distinto de fallo —error visible, degradación visible y fallo invisible—. Diez alertas más sobre CPU no habrían añadido nada, porque la CPU alta ya se manifiesta en la latencia.

  1. Fatiga de alertas: la conversación incómoda

Esto merece un apartado propio porque es el problema real de la observabilidad, y casi nunca se dice con claridad.

La fatiga de alertas es el estado en el que un equipo recibe tantas alertas que deja de reaccionar a ellas. No es un fallo de disciplina: es una respuesta racional. Si de veinte alertas diarias diecinueve son ruido, ignorarlas todas es una estrategia con un 95 % de acierto y un coste enorme cuando falla.

Cómo se llega ahí, casi siempre por el mismo camino:

  1. Alguien monta una alerta por cada métrica disponible, "por si acaso".
  2. Los umbrales se ponen a ojo, sin mirar los valores históricos.
  3. No hay duración, así que cualquier pico dispara.
  4. Todas van al mismo canal con la misma urgencia.
  5. Nadie revisa ni retira las que no aportan.

Los cinco antídotos, en orden de importancia:

Antídoto Regla concreta
Alertar sobre síntomas, no sobre causas Alerta si los clientes sufren, no si la CPU está al 80 %
Umbrales desde datos históricos Mira el valor real de las últimas 4 semanas antes de decidir
Duración siempre Ninguna alerta sin ventana de tiempo
Niveles de urgencia ¿Esto justifica despertar a alguien? Si no, correo o Slack
Revisión periódica Cada trimestre: ¿saltó? ¿fue útil? Si no, se retira

La primera es la más importante y la más contraintuitiva. Una CPU al 90 % no es un problema si los clientes no lo notan: puede ser el sistema aprovechando bien sus recursos. Alertar de la CPU produce falsos positivos —CPU alta sin impacto— y falsos negativos —clientes sufriendo con CPU baja, por ejemplo por un bloqueo en la base de datos—. Las causas se investigan con el panel después de que un síntoma haya avisado.

Y una pregunta de control que vale más que cualquier lista, para cada alerta que se vaya a crear:

Si esta alerta salta a las 3 de la madrugada, ¿hay algo que alguien deba hacer inmediatamente?

Si la respuesta es no, no es una alerta: es un gráfico en un panel. Marta y Dani solo tienen tres alertas configuradas, y esa es deliberadamente la señal de un sistema de alertas sano.

  1. Métricas personalizadas desde la aplicación

Las métricas de plataforma cuentan qué hace la infraestructura. No cuentan qué hace el negocio. Ninguna métrica de GCP sabe cuántos pedidos por minuto entran en AlpinaShop, y esa es probablemente la métrica más importante de todas: si los pedidos caen a cero, algo va mal aunque todos los indicadores técnicos estén verdes.

# catalogo/metricas.py
from google.cloud import monitoring_v3
import time, os

cliente = monitoring_v3.MetricServiceClient()
PROYECTO = f"projects/{os.environ['GOOGLE_CLOUD_PROJECT']}"

def registrar_pedido(importe_euros: float, canal: str) -> None:
    """Escribe un punto en la métrica personalizada de pedidos."""
    serie = monitoring_v3.TimeSeries()
    serie.metric.type = "custom.googleapis.com/tienda/pedidos"

    # ETIQUETAS: pocas y de BAJA cardinalidad. Ver la advertencia de abajo.
    serie.metric.labels["canal"] = canal          # web | movil | telefono
    serie.metric.labels["entorno"] = os.environ.get("ENTORNO", "prod")

    serie.resource.type = "generic_task"
    serie.resource.labels.update({
        "project_id": os.environ["GOOGLE_CLOUD_PROJECT"],
        "location": "europe-west1",
        "namespace": "tienda",
        "job": "catalogo-web",
        "task_id": os.environ.get("HOSTNAME", "desconocido"),
    })

    ahora = time.time()
    punto = monitoring_v3.Point({
        "interval": {"end_time": {"seconds": int(ahora)}},
        "value": {"double_value": 1.0},
    })
    serie.points = [punto]
    cliente.create_time_series(name=PROYECTO, time_series=[serie])

La advertencia sobre las etiquetas es la parte crítica de este apartado. Es tentador añadir serie.metric.labels["id_cliente"] = cliente_id. No lo hagas. Con 50.000 clientes activos crearías 50.000 series temporales por cada combinación del resto de etiquetas, y eso es la explosión de cardinalidad del apartado 2: coste alto, consultas lentas y una métrica inservible.

Etiqueta Valores posibles ¿Aceptable?
canal 3 Sí
entorno 2-3 Sí
categoria_producto ~20 Sí
codigo_postal ~11.000 No
id_cliente 50.000+ Nunca
id_pedido Ilimitado Nunca

La regla: una etiqueta de métrica debe tener decenas de valores posibles, no miles. Lo de alta cardinalidad —el identificador de cliente, el de pedido— va en los logs, que están diseñados para eso, y se consulta desde ahí. Es una de las razones por las que los tres pilares son tres y no uno.

Hay un camino alternativo que en 2026 suele ser mejor si ya vives en Kubernetes: exponer un endpoint /metrics en formato Prometheus y dejar que Managed Service for Prometheus lo recoja. Evita una llamada a la API por evento, es el estándar del sector y encaja con PromQL. Para el catálogo en GKE, es la opción que recomendaría.

También existen las métricas basadas en logs: contar entradas de log que cumplen un filtro y convertirlas en métrica, sin tocar el código de la aplicación. Es una técnica muy potente para instrumentar rápido lo que ya se está registrando, y se desarrolla en 06-06.

  1. Comprobaciones de disponibilidad

Todo lo anterior mide el sistema desde dentro. Las comprobaciones de disponibilidad (uptime checks) lo miden desde fuera: Google lanza peticiones desde varias regiones del mundo y comprueba que la tienda responde.

Esa diferencia de punto de vista detecta clases enteras de fallos que ninguna métrica interna ve: un certificado TLS caducado, un registro DNS mal propagado, una regla de Cloud Armor demasiado agresiva que bloquea a clientes legítimos, un balanceador mal configurado o una caída completa de la región.

gcloud monitoring uptime create tienda-alpinashop \
  --resource-type=uptime-url \
  --resource-labels=host=www.alpinashop.example,project_id=alpinashop-prod \
  --path=/salud \
  --port=443 \
  --protocol=https \
  --period=1 \
  --timeout=10 \
  --regions=EUROPE,USA_OREGON,ASIA_PACIFIC,SOUTH_AMERICA \
  --content-matchers-content='"estado":"ok"' \
  --project=alpinashop-prod

Cuatro decisiones que conviene entender:

  • La ruta /salud es el mismo endpoint que la comprobación de estado hc-catalogo del balanceador de 03-02. Reutilizarlo tiene sentido, pero con un matiz importante: la comprobación del balanceador decide si una instancia recibe tráfico y debe ser rápida y superficial; la de disponibilidad mide si el servicio está sano de verdad. Un /salud que solo devuelve 200 OK sin comprobar nada dará verde con la base de datos caída. El endpoint debería verificar al menos la conectividad con Cloud SQL, con un timeout corto para no convertirse él mismo en un problema.
  • --content-matchers-content comprueba que la respuesta contiene lo esperado, no solo que el código es 200. Un servidor que devuelve una página de error con código 200 —más común de lo que parece— se detecta así.
  • Cuatro regiones repartidas distinguen un problema global de uno regional. Si solo falla la comprobación desde Asia, el problema es de red o de DNS, no de la aplicación.
  • Periodo de 1 minuto es el equilibrio razonable entre detección rápida y coste.

Y la alerta asociada, con un detalle deliberado:

gcloud alpha monitoring policies create \
  --notification-channels=CANAL_SMS_MARTA \
  --display-name="AlpinaShop - Tienda no responde" \
  --condition-display-name="Uptime check fallando en 2+ regiones" \
  --condition-filter='metric.type="monitoring.googleapis.com/uptime_check/check_passed" resource.type="uptime_url"' \
  --duration=180s \
  --project=alpinashop-prod

La condición exige fallo desde dos regiones o más. Un fallo desde una sola región suele ser un problema de la red intermedia, no de la tienda, y alertar por ello genera exactamente el ruido del apartado 11. Exigir dos regiones convierte esta en la alerta más fiable de todo el sistema: si la tienda no responde desde dos continentes, la tienda está caída. Es la única alerta de AlpinaShop que va directa a SMS sin pasar por Slack.

  1. Error Reporting: excepciones agrupadas

Cuando el catálogo Flask lanza una excepción no capturada, el rastreo de pila acaba en los logs. Con miles de peticiones al día, encontrar en los logs que hay un error nuevo es buscar una aguja en un pajar.

Error Reporting resuelve exactamente eso: recoge las excepciones, las agrupa por su firma —el tipo de excepción y la pila, no el mensaje literal— y presenta una lista de problemas distintos con su frecuencia, su primera aparición y su última.

La diferencia práctica: en lugar de 4.000 líneas de log, ves "KeyError: 'talla' en catalogo/carrito.py:87, 340 ocurrencias, primera vez hace 2 horas, afecta a 89 usuarios". Y ese "primera vez hace 2 horas" es oro puro, porque suele coincidir con un despliegue.

Instrumentar Flask es sencillo:

# catalogo/app.py
import google.cloud.logging
from google.cloud.error_reporting import Client as ErrorClient

cliente_logging = google.cloud.logging.Client()
cliente_logging.setup_logging()          # los logs de Python van a Cloud Logging
cliente_errores = ErrorClient(service="catalogo-web", version=os.environ["VERSION_IMAGEN"])

@app.errorhandler(Exception)
def gestionar_error(e):
    # report_exception captura el traceback completo del contexto actual
    cliente_errores.report_exception()
    app.logger.exception("Error no controlado sirviendo %s", request.path)
    return render_template("error.html"), 500

El parámetro version es más importante de lo que parece: al pasar el SHA de la imagen desplegada, Error Reporting sabe en qué versión apareció cada error. Eso conecta directamente con 06-01 y convierte una pregunta difícil —"¿este error es nuevo?"— en un dato. Con esa información, Error Reporting notifica las regresiones: avisa cuando aparece un tipo de error que no existía, y cuando reaparece uno que se había marcado como resuelto.

Capacidad Qué aporta
Agrupación por firma 4.000 líneas de log → 12 problemas distintos
Recuento y tendencia ¿Está empeorando?
Primera y última aparición Correlación con despliegues
Usuarios afectados Prioriza por impacto real, no por volumen
Notificación de errores nuevos Detecta regresiones automáticamente
Enlace al código fuente Salta a la línea exacta (integración de 06-02)

Un consejo importante sobre el diseño de las excepciones: Error Reporting agrupa por la firma de la pila, así que un error genérico repetido en veinte sitios distintos se agrupa mal. Excepciones específicas y mensajes con contexto —pero sin datos personales— hacen que la agrupación sea útil.

  1. El agente de operaciones en las VM del MIG

Hay una laguna en las métricas de plataforma que sorprende a todo el mundo la primera vez: Google no puede ver dentro de tus máquinas virtuales. Sabe la CPU, la red y las operaciones de disco, porque eso lo mide el hipervisor. No sabe la memoria usada, el espacio libre en el disco ni los procesos que corren, porque eso solo se ve desde dentro del sistema operativo.

El agente de operaciones (Ops Agent) es un único agente que recoge métricas del sistema y envía logs desde las VM. Sustituye a los antiguos agentes separados de Stackdriver de monitorización y de logging.

Instalarlo en las plantillas del MIG alpinashop-web-mig, mediante el startup script de 02-01:

#!/bin/bash
# Fragmento del startup script de la plantilla de instancia
curl -sSO https://dl.google.com/cloudagents/add-google-cloud-ops-agent-repo.sh
sudo bash add-google-cloud-ops-agent-repo.sh --also-install

Y su configuración, en /etc/google-cloud-ops-agent/config.yaml:

logging:
  receivers:
    catalogo_app:
      type: files
      include_paths: [/var/log/alpinashop/catalogo.log]
  service:
    pipelines:
      catalogo:
        receivers: [catalogo_app]

metrics:
  receivers:
    hostmetrics:
      type: hostmetrics
      collection_interval: 60s
  service:
    pipelines:
      predeterminada:
        receivers: [hostmetrics]

Lo que aparece en Cloud Monitoring una vez instalado:

Métrica Por qué es importante
agent.googleapis.com/memory/percent_used La causa más común de reinicios inexplicables
agent.googleapis.com/disk/percent_used Un disco lleno tumba la aplicación en silencio
agent.googleapis.com/processes/count_by_state Procesos zombis, fugas de procesos
agent.googleapis.com/swap/percent_used Si hay swap activo, falta memoria

La memoria merece énfasis: una fuga de memoria en la aplicación acaba con el sistema matando el proceso. Desde fuera se ve como reinicios aleatorios y peticiones perdidas, sin ninguna métrica que lo explique. Sin el agente, ese diagnóstico es prácticamente imposible.

Y una nota de futuro: cuando AlpinaShop mueva el catálogo a Cloud Run (DA-001, 07-02), el agente deja de hacer falta porque la plataforma expone esas métricas por sí misma. Es una ventaja real de los servicios gestionados que rara vez se menciona.

  1. Coste de la observabilidad

Es fácil que la factura de observabilidad crezca sin que nadie se dé cuenta. Conviene conocer el modelo —siempre con los precios vigentes de la documentación oficial—:

Componente Se paga por Nivel gratuito Riesgo
Métricas de plataforma Nada Todas Ninguno
Métricas personalizadas Serie temporal ingerida Un volumen inicial Alto: cardinalidad
Logs GB ingeridos Volumen mensual generoso El mayor de todos (06-06)
Trazas Spans ingeridos Volumen mensual Medio: se controla con muestreo
Comprobaciones de disponibilidad Ejecuciones Amplio Bajo
Paneles y alertas Nada — Ninguno

Que los paneles, las alertas y las métricas de plataforma sean gratuitos es la mejor noticia de esta lección: todo lo construido en los apartados 4 a 11 no añade coste. Lo que se paga es lo que tú ingieres: métricas personalizadas y, sobre todo, logs.

Los cinco consejos para que no se dispare:

  1. Vigila la cardinalidad de las métricas personalizadas. Es la trampa número uno: un identificador de cliente como etiqueta multiplica el coste por miles.
  2. No inventes métricas que ya existen. Antes de instrumentar, comprueba si GCP ya la emite. Muchas métricas personalizadas duplican métricas gratuitas.
  3. Excluye el ruido de los logs. Los sondeos de salud y los assets estáticos generan un volumen enorme sin valor de diagnóstico. Los filtros de exclusión son el tema de 06-06.
  4. Ajusta la retención. No todos los logs necesitan guardarse 30 días; algunos, 7 bastan, y lo que hay que conservar mucho tiempo sale más barato exportado a Cloud Storage.
  5. Pon una alerta de presupuesto sobre el propio coste de observabilidad, con lo aprendido en 01-04. Es irónico y es exactamente lo correcto.

Y la perspectiva que hay que mantener: la observabilidad es cara comparada con nada y barata comparada con un incidente. Veinte minutos de tienda caída en campaña cuestan más que un mes de logs. La decisión no es "cuánto gastar en observabilidad", sino "qué necesito ver para no estar ciego, y qué estoy pagando por ver que nadie mira nunca".

Errores Comunes y Consejos

Usar la media para la latencia. El error conceptual más extendido. La media oculta exactamente el problema que buscas. Percentiles siempre: p50 para lo típico, p95 y p99 para lo malo.

Promediar percentiles entre instancias. La media de los p95 no es el p95 del conjunto. Es un número sin significado. Configura el alineador y la agregación correctamente.

Alertar sobre causas en lugar de síntomas. Una alerta de CPU al 80 % produce falsos positivos y falsos negativos. Alerta cuando los clientes sufren; investiga la causa después con el panel.

Alertas sin duración. Cualquier pico dispara, el equipo aprende a ignorarlas y el sistema de alertas muere. Ninguna alerta sin ventana de tiempo.

Umbrales absolutos en lugar de proporciones. "200 errores" no significa nada sin saber cuántas peticiones hubo. Alerta sobre porcentajes.

Etiquetas de alta cardinalidad en métricas personalizadas. Identificador de cliente o de pedido como etiqueta: coste disparado y métrica inútil. Eso va en los logs.

Crear treinta alertas el primer día. La fatiga aparece rápido y es difícil de revertir. Empieza con tres, vive con ellas un mes, y añade solo cuando un incidente real demuestre que faltaba una.

Alertas sin documentación. Llega al móvil a las once de la noche y quien la recibe no sabe qué mirar. El campo documentation con los cuatro primeros pasos es obligatorio.

Olvidar el agente de operaciones en las VM. Sin él no hay métricas de memoria ni de disco, y esas son las causas de los fallos más difíciles de diagnosticar.

Un endpoint /salud que no comprueba nada. Devolver 200 OK sin verificar dependencias hace que la comprobación esté verde con la base de datos caída. Que compruebe lo esencial, con timeout corto.

Paneles construidos a clics y nunca exportados. Se pierden, no se replican y nadie sabe quién los cambió. Exporta el JSON a Git.

Consejo final: el mejor momento para montar la observabilidad es antes del incidente. Durante un incidente, con la tienda caída y el teléfono sonando, nadie tiene tiempo de construir un panel. Y la observabilidad no se juzga por lo bonita que es en un día normal, sino por lo rápido que te lleva a la causa en el peor día del año.

Ejercicios

Ejercicio 1: diseñar una alerta a partir de datos históricos

AlpinaShop quiere alertar sobre las conexiones a alpinashop-pedidos. Los datos históricos de las últimas 4 semanas: mediana 45 conexiones, p95 120, máximo observado 180 durante una campaña de fin de semana que funcionó correctamente, y el límite configurado de la instancia es 250. Diseña la política de alerta completa —métrica, umbral, duración, canal y documentación— justificando cada número, y explica qué pasaría con un umbral de 100 y con uno de 240.

Ejercicio 2: elegir qué medir para un problema que nadie ve

Lucía observa que el informe de ventas de la última semana muestra 40 pedidos menos de lo esperado los martes por la mañana, de forma consistente. Ninguna alerta ha saltado, el panel está verde y la comprobación de disponibilidad no ha fallado nunca. Propón qué métricas mirarías, en qué orden, y qué instrumentación nueva añadirías para que este tipo de problema se detecte automáticamente en el futuro.

Ejercicio 3: rediseñar un sistema de alertas con fatiga

Una empresa parecida a AlpinaShop tiene 34 alertas configuradas. En el último mes saltaron 280 veces; de esas, 11 correspondieron a incidentes reales. El equipo ha silenciado el canal de Slack y revisa las alertas "cuando puede". Diagnostica el problema, propón un método concreto para reducir el número de alertas y define el conjunto mínimo con el que arrancarías de nuevo, explicando qué tipo de fallo detecta cada una.

Soluciones

Solución 1

La política:

Elemento Valor Justificación
Métrica cloudsql.googleapis.com/database/network/connections La directa
Alineador ALIGN_MAX sobre 60 s El pico importa, no la media del minuto
Umbral 200 conexiones 80 % del límite de 250
Duración 5 minutos Filtra picos legítimos
Canal Slack + correo a Marta Serio, pero no de madrugada
Gravedad Advertencia Es un aviso previo, no una caída

Por qué 200. Es el 80 % del límite duro de 250. Deja margen para actuar antes de que la instancia empiece a rechazar conexiones, y está muy por encima del máximo histórico observado en operación normal (180), así que no salta por el uso legítimo más extremo conocido. La regla general: alertar en un porcentaje del límite, no en un múltiplo de la mediana, porque lo que hace daño es agotar el recurso.

Con un umbral de 100: saltaría constantemente. El p95 histórico es 120, es decir, el 5 % del tiempo se superan 120 conexiones en operación completamente normal. Una alerta a 100 saltaría varias veces al día sin que nada esté mal. Es el camino directo a la fatiga del apartado 11 y a que se silencie el canal.

Con un umbral de 240: llegaría demasiado tarde. A 240 de 250 quedan diez conexiones de margen; con la velocidad a la que crece este contador durante un pico, el tiempo entre la alerta y el agotamiento se mide en segundos. Marta recibiría la notificación a la vez que los primeros errores de conexión de los clientes, y la alerta habría dejado de ser preventiva para ser un aviso de que ya es tarde.

Documentación asociada, que es la mitad del valor:

## Conexiones a Cloud SQL elevadas

**Qué significa:** alpinashop-pedidos supera 200 de sus 250 conexiones máximas.

**Impacto si llega a 250:** la aplicación empieza a recibir errores de conexión
y la tienda devuelve 500. Todavía no ha pasado.

**Primeros pasos:**
1. ¿Hay un pico de tráfico legítimo? Panel Campaña de otoño, peticiones/s.
2. Si NO hay pico de tráfico: probable fuga de conexiones tras un despliegue.
   Revisar Cloud Build: ¿hubo despliegue en las últimas 2 horas?
3. Comprobar el número de instancias del MIG y de pods: ¿ha escalado mucho?
4. Comprobar Cloud Functions con --max-instances alto conectadas a la BD (06-03).

**Mitigación inmediata:** reducir --max-instances de las funciones conectadas.
**Mitigación de fondo:** revisar el pool de conexiones de la aplicación.

Y una recomendación adicional que mejora bastante el diseño: añadir una segunda condición sobre la tendencia, no solo el nivel. Un salto de 45 a 190 conexiones en cinco minutos es una señal de fuga muchísimo más fiable que el valor absoluto, y avisaría antes. La mayoría de las fugas de conexiones se manifiestan como una rampa que sube y nunca baja, y eso es detectable mucho antes de llegar al 80 % del límite.

Solución 2

Lo primero es reconocer qué tipo de problema es: un fallo parcial y silencioso. No hay caída, no hay errores masivos, no hay lentitud generalizada. Algo falla para un subconjunto de usuarios o de operaciones, y todos los indicadores agregados lo diluyen. Son los fallos más caros porque duran semanas.

Métricas a mirar, en este orden:

Paso Qué mirar Qué buscas
1 https/request_count martes por la mañana frente a otros días ¿Cae el tráfico o solo los pedidos?
2 Tasa de error 5xx agrupada por matched_url_path_rule Un error localizado en una ruta concreta
3 Latencia p95 por ruta, especialmente /carrito y /pago Lentitud localizada
4 request_count agrupado por user_agent o país ¿Afecta a un segmento?
5 Error Reporting filtrado por franja horaria Excepciones nuevas o que aumentan
6 Métricas de trabajos programados de los martes La hipótesis más probable

La hipótesis principal, y por qué. La regularidad —martes por la mañana, sistemáticamente— apunta con fuerza a algo programado que se ejecuta los martes: una copia de seguridad, un proceso de reindexación, un informe pesado sobre alpinashop_analitica, una tarea de mantenimiento. Ese proceso compite por recursos con la tienda: satura la CPU de Cloud SQL, ocupa conexiones o bloquea tablas, y durante ese rato una fracción de los intentos de compra falla o se abandona por lentitud.

El paso 1 es especialmente informativo y merece detallarse: si el tráfico es normal pero los pedidos caen, el problema está en el embudo de compra; si el tráfico también cae, el problema es de acceso —DNS, CDN, una campaña de marketing que no salió—. Son diagnósticos completamente distintos y esa única comparación los separa.

Instrumentación nueva a añadir, que es el objetivo real del ejercicio:

Instrumentación Qué detecta Prioridad
Métrica de negocio tienda/pedidos (apartado 12) La caída de pedidos, directamente Alta
Métrica del embudo por etapa: vistas → carrito → pago → confirmado En qué paso se pierde la gente Alta
Alerta sobre pedidos/hora comparados con la misma hora de la semana anterior Anomalías, no umbrales fijos Alta
Latencia p95 por ruta en el panel Lentitud localizada Media
Métrica de duración de los trabajos programados Correlación con la ventana de degradación Media

La métrica de embudo es la clave del ejercicio. Con contadores por etapa, la pregunta "¿dónde se pierden los pedidos?" tiene respuesta inmediata: si las vistas de producto son normales, los carritos son normales y los pagos confirmados caen, el problema está en la pasarela o en el paso final. Sin ella, hay que reconstruirlo a mano desde los logs cada vez.

Y la alerta correcta no es de umbral fijo, sino comparativa. "Menos de X pedidos por hora" es inservible porque el volumen varía enormemente entre las 4 de la madrugada y las 8 de la tarde, y entre un martes de julio y un sábado de campaña. Lo que funciona es comparar con la misma franja horaria de la semana anterior y alertar ante una desviación superior al 30 %. Esa comparación absorbe la estacionalidad diaria y semanal.

Y la lección de fondo: todos los indicadores técnicos estaban verdes mientras se perdían 40 pedidos semanales. La observabilidad técnica no sustituye a la observabilidad de negocio. La métrica más importante de una tienda es cuántos pedidos entran, y ninguna métrica de plataforma la conoce. Este caso es el mejor argumento posible a favor de las métricas personalizadas del apartado 12.

Solución 3

Diagnóstico numérico, que es demoledor. 280 alertas para 11 incidentes reales significa una precisión del 3,9 %: 96 de cada 100 alertas son ruido. Con esa proporción, silenciar el canal es la decisión racional, y el equipo no ha hecho nada reprochable. El sistema de alertas está roto, no las personas.

El coste real no son las 280 interrupciones: es que los 11 incidentes reales quedaron enterrados. Un sistema con esa precisión no solo es inútil, es peor que no tener alertas, porque genera la ilusión de estar vigilado.

Las causas casi seguras, deducibles del patrón:

Causa Síntoma Corrección
Alertas sobre causas y no síntomas Muchas de CPU, memoria, disco Retirarlas: son gráficos, no alertas
Umbrales puestos a ojo Saltan en operación normal Recalcular con 4 semanas de histórico
Sin duración Saltan con cualquier pico Mínimo 5 minutos en todas
Umbrales absolutos "N errores" sin contexto Convertir a proporciones
Todo al mismo canal Lo urgente y lo informativo mezclados Separar por nivel
Nunca se revisan 34 alertas acumuladas Revisión trimestral obligatoria

Método concreto de reducción, en cinco pasos:

Paso 1, medir cada alerta. Para cada una de las 34: cuántas veces saltó, cuántas correspondieron a un incidente real y qué acción provocó. Es un ejercicio de una tarde con los datos de Cloud Monitoring.

Paso 2, aplicar la pregunta de las 3 de la madrugada. Para cada alerta: si esto salta de madrugada, ¿hay algo que alguien deba hacer inmediatamente? Todas las que respondan "no" se retiran. Mi apuesta: de 34 caen unas 20.

Paso 3, clasificar las supervivientes.

Clase Criterio Destino
Precisión alta y acción clara Saltó pocas veces y siempre fue real Se conserva
Concepto correcto, umbral malo Detecta lo adecuado pero salta demasiado Se recalibra
Duplicada Otra alerta detecta lo mismo antes Se retira
Nunca saltó Cero disparos en un mes Se revisa si sigue teniendo sentido

Paso 4, recalibrar con datos. Para cada superviviente, mirar el valor real de las últimas cuatro semanas y poner el umbral por encima del p99 histórico o en un porcentaje del límite duro, con duración mínima de 5 minutos.

Paso 5, empezar de cero con el conjunto mínimo. Y aquí viene la parte que cuesta aceptar: es preferible desactivar las 34 y arrancar con 4 que intentar arreglar las 34. Un sistema de alertas ya desacreditado no recupera la confianza retocándolo; hay que refundarlo.

El conjunto mínimo con el que arrancar, cada una detectando una clase distinta de fallo:

Alerta Umbral Duración Fallo que detecta Canal
Disponibilidad desde 2+ regiones Fallo 3 min Caída total SMS
Tasa de error 5xx > 2 % 5 min Fallo funcional visible Slack + SMS
Latencia p95 > 2 s 10 min Degradación visible Slack
Pedidos/hora frente a la semana anterior −30 % 30 min Fallo silencioso de negocio Slack

Cuatro alertas. Y el criterio para añadir la quinta es estricto y muy útil: solo se añade una alerta cuando un incidente real ha ocurrido y ninguna de las existentes lo detectó. Cada alerta nueva debe justificarse con un incidente concreto, no con un "por si acaso". Así el sistema crece guiado por la realidad, y cada alerta que existe tiene una historia que la respalda.

Cierre del ejercicio, con la lección que se lleva uno: un sistema de alertas se juzga por su precisión, no por su cobertura. Cuatro alertas con un 80 % de precisión valen infinitamente más que treinta y cuatro con un 4 %, porque las primeras se atienden y las segundas se silencian. Y una alerta silenciada no protege nada.

Conclusión

AlpinaShop ya no se entera de sus problemas por correo electrónico de un cliente.

Sabes qué es la observabilidad —entender qué le pasa por dentro a un sistema desde lo que emite hacia fuera, incluidos los fallos que no anticipaste— y sus tres pilares, con su perfil distinto: métricas baratas y agregadas para tendencias y alertas, logs con detalle para casos concretos, trazas para saber dónde se fue el tiempo. Y sabes que Stackdriver es solo un nombre histórico.

Dominas el modelo de datos: una serie temporal es tipo de métrica + recurso monitorizado + etiquetas, con la consecuencia de que las etiquetas multiplican series y producen explosión de cardinalidad. Distingues medidor, contador y distribución, con las implicaciones prácticas: un contador hay que derivarlo con rate o no significa nada, y una distribución conserva el histograma completo para poder pedir percentiles a posteriori.

Tienes los tres proyectos en un solo espacio de métricas, con la advertencia de que unifica la vista pero no los permisos. Conoces las métricas de plataforma gratuitas que llevan meses acumulándose sin que nadie las mire, y la tabla que de verdad se usa en un incidente: del síntoma a la métrica.

Sabes explorar con alineadores y agregaciones en el orden correcto, y sobre todo por qué la media miente: 495 ms de media mientras 50 clientes por minuto esperan ocho segundos. Percentiles siempre, nunca promediar percentiles entre series, y el p99 importa más de lo que su nombre sugiere porque suele tocarles a los mejores clientes.

Tienes el panel de la campaña de otoño construido para contar una historia de arriba abajo —primero si sufren los clientes, después por qué— con la CPU del MIG mostrada en media y máximo porque la media oculta la instancia caliente. Y lo tienes como JSON versionable en Git, listo para pasar a Terraform en 06-07. Conoces MQL para lo que los filtros no expresan —la tasa de error como proporción— y PromQL como apuesta más portable si vives en Kubernetes.

Sabes montar una política de alerta con sus cuatro piezas, con la duración como pieza infravalorada y el campo documentation como lo que separa una alerta útil de una que genera ansiedad. Tienes las tres alertas de AlpinaShop, cada una con su umbral razonado y cada una detectando un tipo distinto de fallo: error visible, degradación visible y fallo invisible desde fuera. Y has tenido la conversación incómoda sobre la fatiga de alertas, con la pregunta de control que vale por todo el apartado: si esto salta a las 3 de la madrugada, ¿hay algo que hacer inmediatamente? Si no, es un gráfico, no una alerta.

Sabes emitir métricas personalizadas de negocio —los pedidos por minuto que ninguna métrica de GCP conoce— con la regla de oro sobre las etiquetas: decenas de valores, nunca miles, y lo de alta cardinalidad va a los logs. Tienes comprobaciones de disponibilidad desde cuatro continentes que detectan lo que ninguna métrica interna ve, con la condición de dos regiones que las convierte en la alerta más fiable del sistema. Tienes Error Reporting agrupando excepciones de Flask por firma y notificando regresiones, con el version que enlaza cada error con el despliegue que lo introdujo. Y tienes el agente de operaciones en las VM del MIG, sin el cual no hay métricas de memoria ni de disco y los reinicios inexplicables se quedan inexplicables.

Y conoces el coste: paneles, alertas y métricas de plataforma son gratuitos; lo que se paga es lo que tú ingieres, con la cardinalidad y el volumen de logs como las dos trampas. Con la perspectiva correcta: la observabilidad es cara comparada con nada y barata comparada con veinte minutos de tienda caída en campaña.

Pero fíjate en lo que las métricas no pueden hacer. Cuando la alerta de errores 5xx salta a las once de la noche, te dice que el 4 % de las peticiones fallan. No te dice qué falla. No te dice a qué cliente le pasó, ni con qué producto, ni en qué línea de código. Y cuando la latencia p99 se dispara, la métrica te dice que algo tarda tres segundos, pero no quién tarda: ¿la aplicación, la base de datos, la llamada a la Vision API, la red?

Para eso hacen falta los otros dos pilares. En 06-06 llegan Cloud Logging y Cloud Trace: los logs que responden qué pasó exactamente en este caso, y las trazas que responden dónde se fue el tiempo. Y con ellos, el recorrido completo de un incidente de AlpinaShop desde la alerta hasta la línea de código.

Antes, sin embargo, hay una deuda pendiente que ya no se puede aplazar. Toda esta infraestructura —la VPC, el balanceador, el clúster, las alertas que acabas de crear— sigue existiendo únicamente porque alguien ejecutó los comandos correctos en el orden correcto, y ese alguien fue Marta, y el registro de lo que hizo está en el historial de su terminal. En 06-05 se ataca ese problema de frente.

Curso de Google Cloud Platform (GCP)

Módulo 1: Introducción a Google Cloud Platform

Módulo 2: Servicios principales de GCP

Módulo 3: Redes y seguridad

Módulo 4: Datos y análisis

Módulo 5: Aprendizaje automático e IA

Módulo 6: DevOps y monitoreo

Módulo 7: Temas avanzados de GCP

Módulo 8: Proyecto final

© Copyright 2026. Todos los derechos reservados