Estrategias de escalamiento de bases de datos: réplicas de lectura, fragmentación y más
El rendimiento de la base de datos es el cuello de botella en el 78 % de los problemas de escalado de aplicaciones web. Las aplicaciones pueden escalar horizontalmente con un esfuerzo mínimo, pero las bases de datos se resisten al escalamiento horizontal. Las estrategias que elija para el escalado de la base de datos determinan si su aplicación atiende a 100 usuarios o a 100 000 usuarios con un rendimiento aceptable.
Esta guía cubre el espectro completo de estrategias de escalado de bases de datos, desde optimizaciones simples que retrasan la necesidad de escalar hasta técnicas avanzadas como la fragmentación horizontal.
Conclusiones clave
- Optimice las consultas y agregue índices antes de agregar infraestructura: esto resuelve el 60% de los problemas de rendimiento de la base de datos
- Las réplicas de lectura son la estrategia de escalamiento de menor riesgo y manejan el 80 % de las cargas de trabajo con mucha lectura.
- La agrupación de conexiones es obligatoria una vez que su aplicación ejecuta más de 10 instancias
- La fragmentación horizontal es un último recurso que introduce una complejidad significativa en la aplicación.
La escalera de ascenso
Escale en este orden. Cada paso es más barato y menos riesgoso que el siguiente:
Paso 1: Optimización de consultas (gratis)
Antes de agregar infraestructura, asegúrese de que su base de datos existente esté funcionando de manera óptima.
-- Find slow queries in PostgreSQL
SELECT
calls,
mean_exec_time::numeric(10,2) AS avg_ms,
total_exec_time::numeric(10,2) AS total_ms,
query
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 20;
Optimizaciones comunes:
- Agregar índices faltantes para columnas filtradas con frecuencia
- Reemplace
SELECT *con listas de columnas específicas - Utilice
EXPLAIN ANALYZEpara identificar escaneos secuenciales en tablas grandes - Agregar índices compuestos para cláusulas WHERE de varias columnas
- Implementar paginación con paginación de conjunto de claves en lugar de
OFFSET
-- Bad: OFFSET pagination (scans all skipped rows)
SELECT * FROM orders ORDER BY created_at DESC LIMIT 20 OFFSET 10000;
-- Good: Keyset pagination (index-only scan)
SELECT * FROM orders
WHERE created_at < '2026-03-15T10:00:00Z'
ORDER BY created_at DESC
LIMIT 20;
Paso 2: Escala vertical ($)
Aumente la CPU, la RAM y el almacenamiento en su servidor de base de datos existente. Esto gana tiempo y no requiere cambios en la aplicación.
| Tamaño de instancia | CPU virtual | RAM | Conexiones | Costo Mensual (RDS) |
|---|---|---|---|---|
| db.t3.medio | 2 | 4 GB | 100 | $65 |
| db.r6g.grande | 2 | 16 GB | 200 | $175 |
| db.r6g.xlarge | 4 | 32 GB | 400 | $350 |
| db.r6g.2xlarge | 8 | 64 GB | 800 | $700 |
La mayoría de las aplicaciones alcanzan su límite con 64 GB de RAM y 8 vCPU. Más allá de eso, el escalamiento vertical tiene un costo prohibitivo.
Paso 3: Agrupación de conexiones ($)
Application (50 pods x 20 connections = 1,000 connections)
|
v
PgBouncer (25 database connections, transaction pooling)
|
v
PostgreSQL (25 active connections, manageable)
Configuración de PgBouncer:
[databases]
app = host=db.example.com port=5432 dbname=production
[pgbouncer]
listen_port = 6432
listen_addr = 0.0.0.0
auth_type = md5
pool_mode = transaction
default_pool_size = 25
max_client_conn = 1000
min_pool_size = 5
reserve_pool_size = 5
reserve_pool_timeout = 3
Paso 4: Leer réplicas ($$)
Las réplicas de lectura manejan consultas SELECT, descargando entre el 60% y el 90% de la carga de la base de datos de la principal.
Arquitectura:
Write queries --> Primary database
|
Replication (async)
|
+----+----+
| |
Read queries --> Replica 1 Replica 2
Enrutamiento a nivel de aplicación (ejemplo de Drizzle ORM):
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';
const primaryPool = new Pool({ connectionString: process.env.DATABASE_URL });
const replicaPool = new Pool({ connectionString: process.env.DATABASE_REPLICA_URL });
export const primaryDb = drizzle(primaryPool);
export const replicaDb = drizzle(replicaPool);
// In service code:
// Write operations use primaryDb
async createOrder(data: OrderInput) {
return primaryDb.insert(orders).values(data).returning();
}
// Read operations use replicaDb
async getOrders(organizationId: string) {
return replicaDb.select().from(orders)
.where(eq(orders.organizationId, organizationId))
.orderBy(desc(orders.createdAt));
}
Consideraciones sobre el retraso de la replicación: la replicación asíncrona introduce un retraso (normalmente de 10 a 100 ms). Inmediatamente después de una escritura, la lectura de la réplica puede devolver datos obsoletos. Utilice el primario para lecturas que siguen a escrituras en el mismo flujo de usuario.
Paso 5: Almacenamiento en caché ($$)
El almacenamiento en caché de Redis elimina por completo las consultas repetidas a la base de datos.
async getProduct(id: string): Promise<Product> {
const cacheKey = `product:${id}`;
// Check cache first
const cached = await this.redis.get(cacheKey);
if (cached) return JSON.parse(cached);
// Cache miss: query database
const product = await this.db.select().from(products)
.where(eq(products.id, id))
.limit(1);
// Cache for 5 minutes
await this.redis.setex(cacheKey, 300, JSON.stringify(product[0]));
return product[0];
}
Estrategia de invalidación de caché: Invalidar al escribir. Cuando se actualiza un producto, elimine la clave de caché. Utilice un patrón de caché aparte (la aplicación administra el caché) en lugar de escritura simultánea (la base de datos administra el caché).
Paso 6: fragmentación horizontal ($$$)
La fragmentación distribuye datos entre múltiples instancias de bases de datos según una clave de fragmentación.
| Estrategia de fragmentación | Descripción | Mejor para |
|---|---|---|
| Basado en hash | Hash la clave del fragmento, distribuir uniformemente | Distribución uniforme de datos |
| Basado en rango | Asignar rangos a fragmentos (por ejemplo, A-M, N-Z) | Series temporales, datos geográficos |
| Basado en inquilinos | Un fragmento por inquilino/organización | SaaS multiinquilino |
Cuándo fragmentar:
- La base de datos única supera 1 TB y sigue creciendo
- El rendimiento de escritura supera lo que puede manejar un único primario
- Los costos de escalamiento vertical superan los $2000/mes sin margen de maniobra
Cuándo NO fragmentar:
- No has agotado los pasos 1-5
- Tus datos caben en una única base de datos de 500 GB
- Las consultas entre fragmentos son comunes en su aplicación.
Optimizaciones específicas de PostgreSQL
Partición (antes de fragmentar)
La partición de tablas de PostgreSQL divide tablas grandes en tablas físicas más pequeñas mientras mantiene una única tabla lógica:
-- Partition orders by month
CREATE TABLE orders (
id UUID PRIMARY KEY,
organization_id UUID NOT NULL,
created_at TIMESTAMP NOT NULL,
total DECIMAL(10,2)
) PARTITION BY RANGE (created_at);
CREATE TABLE orders_2026_01 PARTITION OF orders
FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
CREATE TABLE orders_2026_02 PARTITION OF orders
FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');
CREATE TABLE orders_2026_03 PARTITION OF orders
FOR VALUES FROM ('2026-03-01') TO ('2026-04-01');
La partición mejora el rendimiento de las consultas de rango de tiempo entre 10 y 100 veces en tablas grandes porque PostgreSQL solo escanea las particiones relevantes.
Aspiración y mantenimiento
-- Check table bloat
SELECT
schemaname,
relname,
n_live_tup,
n_dead_tup,
round(n_dead_tup::numeric / greatest(n_live_tup, 1) * 100, 2) AS dead_pct
FROM pg_stat_user_tables
WHERE n_dead_tup > 1000
ORDER BY n_dead_tup DESC;
Configure autovacuum agresivamente para tablas de alta escritura:
ALTER TABLE orders SET (
autovacuum_vacuum_threshold = 100,
autovacuum_vacuum_scale_factor = 0.05,
autovacuum_analyze_threshold = 50,
autovacuum_analyze_scale_factor = 0.02
);
Supervisión del rendimiento de la base de datos
Realice un seguimiento de estas métricas para comprender cuándo y cómo escalar:
| Métrica | Herramienta | Umbral de alerta |
|---|---|---|
| Latencia de consulta (P95) | pg_stat_statements | >500ms |
| Conexiones activas | pg_stat_actividad | >80% del máximo |
| Proporción de aciertos de caché | pg_stat_database | <95% |
| Retraso de replicación | pg_stat_replication | >1 segundo |
| Hinchazón de mesa | pg_stat_user_tables | >20% tuplas muertas |
| Espera de E/S de disco | iostato / CloudWatch | >20ms |
Una tasa de aciertos de caché inferior al 95% es el indicador más claro de que necesita más memoria. Aumentar shared_buffers y effective_cache_size suele ser más económico y rápido que agregar réplicas de lectura.
Seguimiento del rendimiento de consultas
-- Enable pg_stat_statements (postgresql.conf)
-- shared_preload_libraries = 'pg_stat_statements'
-- Find the top 10 most time-consuming queries
SELECT
queryid,
calls,
mean_exec_time::numeric(10,2) AS avg_ms,
total_exec_time::numeric(10,2) AS total_ms,
rows,
query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
Revise las 10 consultas principales semanalmente. Optimizar incluso una única consulta ejecutada con frecuencia puede reducir la carga general de la base de datos entre un 10 y un 30 %.
Preguntas frecuentes
Supervise tres métricas: latencia de consulta P95 (alerta a 500 ms), utilización de la conexión (alerta al 80%) y utilización de la CPU (alerta al 70% sostenida). Si alcanza estos umbrales con regularidad, pase al siguiente paso en la escalera de ascenso. No optimice previamente --- escale cuando los datos se lo indiquen.
Comience con el almacenamiento en caché. El almacenamiento en caché de Redis es más sencillo de implementar, elimina más carga (los accesos al caché omiten la base de datos por completo) y cuesta menos. Agregue réplicas de lectura cuando su tasa de aciertos de caché ya sea superior al 80 % pero la base de datos principal todavía esté bajo presión por errores de caché y operaciones de escritura.
Odoo utiliza PostgreSQL exclusivamente. Comience con la optimización de consultas (Odoo genera consultas complejas para generar informes). Agregue PgBouncer para agrupar conexiones cuando supere los 50 usuarios simultáneos. Utilice réplicas de lectura para consultas de informes (configure la opción --db-replica de Odoo). ECOSIRE proporciona optimización del rendimiento de Odoo incluido el ajuste de la base de datos.
Sí, para la mayoría de las empresas. Las bases de datos administradas manejan copias de seguridad, parches, conmutación por error y monitoreo automatizados. La prima de costo del 30 al 40 % sobre PostgreSQL autoadministrado se compensa con el tiempo de ingeniería que ahorra. La excepción son las implementaciones a gran escala donde la prima de costo de una instancia grande excede el costo de un DBA a tiempo parcial.
¿Qué viene después?
El escalamiento de la base de datos es un componente de una estrategia más amplia de escalamiento de infraestructura. Combínelo con optimización de CDN para activos estáticos, escalado automático de Kubernetes para pods de aplicaciones y pruebas de carga para validar sus decisiones de escalado en condiciones realistas.
Comuníquese con ECOSIRE para obtener consultoría sobre optimización de bases de datos, o consulte nuestra guía DevOps para obtener la hoja de ruta completa de la infraestructura.
Publicado por ECOSIRE: ayuda a las empresas a escalar la infraestructura de datos con confianza.
Escrito por
ECOSIRE Research and Development Team
Construyendo productos digitales de nivel empresarial en ECOSIRE. Compartiendo perspectivas sobre integraciones Odoo, automatización de eCommerce y soluciones empresariales impulsadas por IA.
Artículos relacionados
Patrones de puerta de enlace API y mejores prácticas para aplicaciones modernas
Implemente patrones de puerta de enlace API que incluyen limitación de velocidad, autenticación, enrutamiento de solicitudes, disyuntores y control de versiones de API para arquitecturas web escalables.
Optimización del rendimiento de CDN: la guía completa para una entrega global más rápida
Optimice el rendimiento de la CDN con estrategias de almacenamiento en caché, informática de punta, optimización de imágenes y arquitecturas multi-CDN para una entrega de contenido global más rápida.
Mejores prácticas de canalización de CI/CD: automatice su camino hacia implementaciones confiables
Cree canales de CI/CD confiables con las mejores prácticas para pruebas, preparación, automatización de implementación, estrategias de reversión y escaneo de seguridad en flujos de trabajo de producción.