Réplicas de lectura: cuándo el enrutamiento supera al caché
El caché desplaza la carga de lectura fuera de la base de datos hasta que las tormentas de invalidación o los datos obsoletos rompen la confianza. Las réplicas de lectura con enrutamiento explícito de queries cambian complejidad operativa por latencia predecible — y un camino que sobrevive cuando el caché no puede.
El tráfico de lectura se duplicó. El equipo añadió Redis. Las tasas de acierto se veían bien — 94%. Luego una actualización masiva de admin invalidó la mitad del keyspace y Postgres absorbió la estampida de todos modos. El p99 del dashboard subió a cuatro segundos. Cache-aside había ocultado la carga de lectura hasta que ocultar falló. El enrutamiento de réplicas de lectura en Postgres aborda un problema distinto: distribuir queries de lectura a nodos standby con trade-offs de lag de replicación conocidos — en lugar de esperar que la lógica de invalidación siga correcta bajo cada patrón de escritura.
Caché y réplicas son complementos, no sustitutos. El caché gana en claves calientes con staleness tolerable. Las réplicas ganan en queries analíticas de mucha lectura, patrones de acceso impredecibles y cargas donde invalidar el caché es más difícil que gestionar el lag de replicación.
Cuándo el caché deja de bastar
| Symptom | Likely cause | Replica vs cache |
|---|---|---|
| Tormentas de invalidación tras escrituras masivas | Explosión de claves de caché | Las réplicas absorben el pico de lectura directamente |
| Lecturas obsoletas rompen la confianza del usuario | TTL demasiado largo o invalidación omitida | Réplicas: lag acotado, a menudo subsegundo |
| El costo de memoria supera el costo de lectura en DB | Working set grande | Réplicas más baratas por GB escaneado |
| Patrones de query complejos | Difícil clavear entradas de caché | Las réplicas ejecutan SQL; el caché necesita claves a medida |
| Caché frío tras deploy | Todos los misses a la vez | Las réplicas siempre calientes para la ruta SQL |
El caché oculta carga. No la elimina — la retrasa y la concentra en el momento del miss. Las réplicas reparten carga de forma continua a costa de lag de replicación y complejidad operativa de enrutamiento.
Un caché con invalidación incorrecta es una máquina de lecturas obsoletas con buenas métricas de hit rate.
Arquitectura de enrutamiento a réplicas de lectura
El primary maneja escrituras y, opcionalmente, lecturas con consistencia fuerte.
Las réplicas manejan queries de solo lectura enrutadas de forma explícita — no por accidente.
Capas de enrutamiento:
-
A nivel de aplicación. El código pasa un flag
read_consistency: strong | eventual; el pool de conexiones selecciona datasource primary o réplica. -
ORM / middleware. Un splitter read/write intercepta
SELECTfrente aINSERT/UPDATE/DELETE. -
Proxy. PgBouncer, RDS Proxy o router custom — centraliza el enrutamiento; el riesgo es magia opaca si los equipos no entienden las reglas.
-
Modelos de lectura CQRS. Tablas de proyección dedicadas en réplica o almacén de lectura separado — ver modelo de lectura CQRS para cuándo las proyecciones reemplazan el enrutamiento ad hoc a réplicas.
Las reglas de enrutamiento explícitas superan al implícito "todos los SELECT van a réplica":
| Query type | Route | Reason |
|---|---|---|
| Comprobación de auth de sesión de usuario | Primary | Debe ver el estado más reciente de credenciales |
| Estado de pedido post-checkout | Primary | El usuario acaba de pagar — lag inaceptable |
| Dashboard analítico | Replica | Segundos de lag OK |
| Paginación de búsqueda/listado | Replica | Alto volumen, eventual OK |
| Exportaciones de reporting | Replica | Escaneos largos dañan al primary |
| Read-after-write en la misma request | Primary | Bug clásico de lag de replicación |
El lag de replicación es el TTL del caché de la réplica
Las réplicas son eventualmente consistentes. El lag varía:
- Normal: milisegundos a pocos segundos
- Carga de escritura pesada: segundos
- Mantenimiento de réplica, blip de red: minutos posibles
Mitigaciones:
Monitoreo de lag. Alertar cuando el lag de réplica supera el SLO — la misma disciplina que SLIs sin equipo SRE.
Pinning de lecturas críticas. Tras una escritura, enrutar lecturas subsecuentes en la misma sesión al primary durante N segundos o hasta confirmar catch-up de replicación.
Conciencia de RPO/RTO. La promoción de réplica para failover es distinta del escalado de lectura — saber qué réplicas son candidatas a promoción frente a analytics de solo lectura.
Evitar queries de "lectura" con mucha escritura. Informes largos que bloquean filas en réplica siguen dañando — las réplicas no son compute gratis, son copia de la ruta de escritura del primary.
Combinar caché y réplicas
Un stack sano usa ambos:
Write → Primary
Read (hot, stale-OK) → Cache → on miss → Replica
Read (must be fresh) → Primary
Read (heavy scan) → Replica (bypass cache — don't cache 10MB result sets)
Cachear los resultados computados costosos de lecturas en réplica — no cada lookup de fila. Los triggers de invalidación en escritura siguen siendo necesarios, pero la réplica absorbe la carga SQL de cache miss.
No cachear lo que las réplicas manejan barato a la escala actual. No enrutar a réplicas lo que requiere lecturas frescas al milisegundo.
El dimensionado del pool de conexiones se reparte entre primary y réplicas — connection pooling en serverless aplica a ambos; pools de réplica hambrientos causan timeouts en la app que parecen fallos de base de datos.
Checklist operativo para enrutamiento a réplicas
- Documentar el requisito de consistencia por endpoint — strong vs eventual.
- Tests de integración que afirmen que las rutas read-after-write golpean el primary.
- Load test de la ruta de réplica de forma independiente — la saturación de réplica es un incidente aparte.
- Revisión de queries: patrones N+1 de lectura dañan réplicas igual que al primary — arreglar queries antes de añadir infra.
- Indexar réplicas igual que el primary — las réplicas ejecutan los mismos planes; índices faltantes duelen el doble.
¿Cómo deben elegir los equipos enrutamiento a réplicas frente a más caché?
Estas decisiones aclaran cuándo invertir en complejidad de enrutamiento.
¿Cuándo es aceptable el lag de replicación?
Cuando el producto tolera datos de hace segundos en lectura — dashboards, listados, recomendaciones. No cuando el usuario acaba de mutar una entidad y espera reflejo inmediato — pin al primary.
¿Cuántas réplicas bastan?
Escalar hasta que el p99 de lectura en rutas enrutadas cumpla el SLO en pico. Una réplica es single point of failure para la ruta de lectura — planificar pérdida de réplica con failover de lecturas al primary con headroom de capacidad o segunda réplica.
¿Debería el ORM auto-enrutar todos los SELECT a réplica?
Default peligroso. Auto-enrutamiento sin flags de consistencia por query causa bugs sutiles — estado de checkout desde réplica, comprobaciones de permisos desde réplica. Lo explícito supera a la magia.
Una visión opuesta
La postura contraria sostiene que las réplicas duplican costo y complejidad — que mejor caché y optimización de queries eliminan la carga de lectura en el primary.
La optimización de queries es obligatoria en cualquier caso. El caché ayuda en rutas calientes. Las réplicas abordan volumen de lectura de cola larga y escaneos impredecibles que resisten el keying de caché. Con ratio lectura/escritura suficiente, el costo de réplica es predecible; las tormentas de cache miss no lo son.
Las ofertas de Postgres serverless suelen incluir réplicas de lectura — la disciplina de enrutamiento importa incluso cuando la infra está gestionada.
Key takeaways
- El caché oculta carga de lectura hasta que la invalidación falla; las réplicas reparten carga con lag de replicación acotado.
- Enrutamiento explícito por query — lecturas strong al primary, lecturas eventual a réplica.
- Read-after-write en la misma sesión debe pin al primary o esperar catch-up.
- Combinar caché (resultados calientes) con réplicas (ejecución SQL) — no uno u otro.
- Monitorear lag de réplica como SLI; alertar antes de que los usuarios vean datos obsoletos.
- Indexar y optimizar queries antes de escalar réplicas — SQL malo escala mal en todas partes.
Conclusion
El enrutamiento a réplicas de lectura es honestidad sobre consistencia: algunas lecturas toleran lag, otras no. Caché sin esa honestidad produce hit rates que mienten sobre la salud del sistema. Los equipos que documentan reglas de enrutamiento por endpoint duermen durante actualizaciones masivas; los que enrutan todos los SELECT a una réplica se preguntan por qué el checkout muestra pedidos pagados como pendientes.
Empezar con inventario de endpoints: ¿qué lecturas requieren consistencia fuerte? Todo lo demás es candidato a réplica — luego medir lag, luego añadir caché encima donde la economía lo justifique.