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
- Observabilidad y sus tres pilares
- El modelo de datos de métricas
- El espacio de métricas: ver los tres proyectos a la vez
- Métricas de plataforma que ya tienes gratis
- Explorar: alineadores, agregaciones y por qué la media miente
- El panel de la campaña de otoño
- El panel como JSON versionable
- MQL y PromQL para consultas avanzadas
- Alertas: anatomía de una política
- Canales de notificación y las tres alertas de AlpinaShop
- Fatiga de alertas: la conversación incómoda
- Métricas personalizadas desde la aplicación
- Comprobaciones de disponibilidad
- Error Reporting: excepciones agrupadas
- El agente de operaciones en las VM del MIG
- Coste de la observabilidad
- 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.
- 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:
| 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.
- 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-prodUn 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.
- 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.
- 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:
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:
- 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.
- 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_95como alineador ysumcomo agregación de distribuciones; hacerlo al revés produce basura. - 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.
- 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.
- 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-prodUn 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.
- 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.
- 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-prodEl 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.
- 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-prodEl 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.
- 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:
- Alguien monta una alerta por cada métrica disponible, "por si acaso".
- Los umbrales se ponen a ojo, sin mirar los valores históricos.
- No hay duración, así que cualquier pico dispara.
- Todas van al mismo canal con la misma urgencia.
- 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.
- 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.
- 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-prodCuatro decisiones que conviene entender:
- La ruta
/saludes el mismo endpoint que la comprobación de estadohc-catalogodel 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/saludque solo devuelve200 OKsin 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-contentcomprueba 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-prodLa 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.
- 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"), 500El 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.
- 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-installY 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.
- 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:
- 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.
- No inventes métricas que ya existen. Antes de instrumentar, comprueba si GCP ya la emite. Muchas métricas personalizadas duplican métricas gratuitas.
- 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.
- 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.
- 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
- ¿Qué es Google Cloud Platform?
- Configuración de tu cuenta de GCP
- Descripción general de la consola de GCP
- Proyectos, jerarquía de recursos y facturación
- Regiones, zonas y modelo de responsabilidad compartida
- Cloud Shell y la CLI de gcloud
Módulo 2: Servicios principales de GCP
- Compute Engine: máquinas virtuales en Google Cloud
- Cloud Storage: almacenamiento de objetos
- Cloud SQL: bases de datos relacionales gestionadas
- App Engine: plataforma como servicio
- Google Kubernetes Engine (GKE)
- Bases de datos NoSQL: Firestore, Bigtable y Spanner
- Cómo elegir el servicio de cómputo adecuado
Módulo 3: Redes y seguridad
- Redes VPC
- Balanceo de carga en la nube
- Cloud CDN
- Gestión de identidad y acceso (IAM)
- Cloud Armor
- Secretos y cifrado: Secret Manager y Cloud KMS
- Cloud DNS, certificados TLS y publicación segura de servicios
Módulo 4: Datos y análisis
- BigQuery: el almacén de datos analítico
- Cloud Dataflow: procesamiento de datos por lotes y en streaming
- Cloud Dataproc: Spark y Hadoop gestionados
- Cloud Pub/Sub: mensajería asíncrona
- Cloud Data Fusion: integración de datos sin código
- Orquestación de pipelines con Cloud Composer y Workflows
- Gobierno del dato y cuadros de mando con Dataplex y Looker Studio
Módulo 5: Aprendizaje automático e IA
- Vertex AI: la plataforma de machine learning de GCP
- AutoML: modelos a medida sin escribir código
- TensorFlow en GCP: entrenamiento y servicio de modelos
- API de lenguaje natural
- API de visión
- IA generativa en Vertex AI: modelos Gemini y embeddings
- MLOps: del modelo al producto con Vertex AI Pipelines
Módulo 6: DevOps y monitoreo
- Cloud Build: integración continua en GCP
- Cloud Source Repositories y gestión del código fuente
- Cloud Functions: funciones sin servidor
- Cloud Monitoring (antes Stackdriver): métricas, paneles y alertas
- Cloud Deployment Manager e infraestructura como código nativa
- Cloud Logging y Cloud Trace: logs, trazas y diagnóstico
- Terraform en GCP: infraestructura como código en la práctica
Módulo 7: Temas avanzados de GCP
- Híbrido y multinube con Anthos
- Computación sin servidor con Cloud Run
- Redes avanzadas: VPC compartida, peering y conectividad híbrida
- Mejores prácticas de seguridad
- Gestión y optimización de costos
- Fiabilidad: SLO, alta disponibilidad y recuperación ante desastres
- Gobierno a escala: organización, políticas y auditoría
