Estrategias de escalamiento de bases de datos: réplicas de lectura, fragmentación y más

Escale su base de datos con réplicas de lectura, fragmentación horizontal, agrupación de conexiones y estrategias de almacenamiento en caché. Cubre PostgreSQL, MySQL y servicios de bases de datos administradas.

E
ECOSIRE Research and Development Team
|16 de marzo de 20268 min de lectura1.8k Palabras|

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 ANALYZE para 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 instanciaCPU virtualRAMConexionesCosto Mensual (RDS)
db.t3.medio24 GB100$65
db.r6g.grande216 GB200$175
db.r6g.xlarge432 GB400$350
db.r6g.2xlarge864 GB800$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&lt;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ónDescripciónMejor para
Basado en hashHash la clave del fragmento, distribuir uniformementeDistribución uniforme de datos
Basado en rangoAsignar rangos a fragmentos (por ejemplo, A-M, N-Z)Series temporales, datos geográficos
Basado en inquilinosUn fragmento por inquilino/organizaciónSaaS 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étricaHerramientaUmbral de alerta
Latencia de consulta (P95)pg_stat_statements>500ms
Conexiones activaspg_stat_actividad>80% del máximo
Proporción de aciertos de cachépg_stat_database<95%
Retraso de replicaciónpg_stat_replication>1 segundo
Hinchazón de mesapg_stat_user_tables>20% tuplas muertas
Espera de E/S de discoiostato / 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

¿Cómo sabemos cuándo es el momento de escalar?

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.

Leer réplicas o almacenamiento en caché: ¿cuál primero?

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.

¿Cómo funciona el escalado de bases de datos con Odoo?

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.

¿Vale la pena pagar una prima por la base de datos administrada (RDS/Cloud SQL)?

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.

E

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.

Chatea en whatsapp