Ir al contenido

Configuración recomendada por tamaño de empresa (Odoo + PgBouncer + PostgreSQL)

27 de diciembre de 2025 por
Configuración recomendada por tamaño de empresa (Odoo + PgBouncer + PostgreSQL)
John Wolf
| Todavía no hay comentarios

No todas las empresas necesitan “arquitectura enterprise”, pero todas necesitan estabilidad. La forma más práctica de acertar en Odoo es elegir una configuración base según tamaño (y luego ajustar con métricas).

En este post te dejo tres perfiles (pequeña, mediana, grande) con valores recomendados para:

  • Odoo: workers, max_cron_threads, db_maxconn

  • PgBouncer: pool_mode, default_pool_size, reserve_pool_size, max_client_conn

  • PostgreSQL: max_connections (orientativo)

  • Observabilidad mínima

Supuestos:

  • Odoo detrás de Nginx/HAProxy (TLS)

  • PgBouncer en pool_mode=transaction para el tráfico ORM (lo típico con Odoo)

  • 1 DB principal por instancia (si tienes multi-tenant, ver nota al final)


0) Regla rápida para leer esta guía

  • Workers te dan concurrencia web (capacidad de atender requests).

  • PgBouncer convierte esa concurrencia en un número controlado de conexiones reales a Postgres.

  • Cron jobs pueden destruir tu p99 si corren demasiado en paralelo.

  • Si dudas: empieza conservador, mide SHOW POOLS; y ajusta.


Perfil 1: Empresa pequeña (PyME / 10–50 usuarios)

Hardware típico

  • Odoo/App: 2–4 vCPU, 8–16 GB RAM

  • Postgres: mismo host o separado (ideal 2–4 vCPU, 8–16 GB RAM)


Odoo (odoo.conf)

  • workers = 5–9

  • max_cron_threads = 1

  • db_maxconn = 32

Por qué así:

El enemigo #1 aquí es swap y crons que se pisan. Mejor menos concurrencia, pero estable.


PgBouncer (pgbouncer.ini)

  • pool_mode = transaction

  • default_pool_size = 20–40

  • reserve_pool_size = 5–10

  • reserve_pool_timeout = 5

  • max_client_conn = 500–1000


PostgreSQL (orientativo)

  • max_connections = 150–250 (no lo inflas “por si acaso”; PgBouncer manda)

“Señales” a vigilar

  • cl_waiting en PgBouncer (si aparece sostenido, primero mira crons/locks)

  • duración del cron más pesado


Perfil 2: Empresa mediana (50–300 usuarios)

Hardware típico

  • Odoo/App: 8 vCPU, 32 GB RAM

  • Postgres: 8 vCPU, 32–64 GB RAM (ideal separado)

Odoo

  • workers = 13–17

  • max_cron_threads = 2

  • db_maxconn = 64

Por qué así:

Acá ya importa el throughput. Dos crons en paralelo está bien, pero si tienes crons masivos, tendrás que hacer batching.

PgBouncer

  • pool_mode = transaction

  • default_pool_size = 60–100

  • reserve_pool_size = 15–30

  • reserve_pool_timeout = 5

  • max_client_conn = 1500–3000

Tip: si default_pool_size sube y Postgres empeora, no sigas subiendo: estás en contención/locks.

PostgreSQL (orientativo)

  • max_connections = 250–400

“Señales” a vigilar

  • maxwait en PgBouncer

  • transacciones > 2 min en Postgres (predicen cola)

  • p99 en operaciones críticas (validaciones, cierres, inventario)


Perfil 3: Empresa grande (300–1500+ usuarios / operación intensiva)

Hardware típico (mínimo razonable)

  • Odoo/App: 16–32 vCPU, 64–128 GB RAM (a menudo 2+ nodos Odoo)

  • Postgres: 16–32 vCPU, 128 GB+ RAM, discos rápidos (IOPS importan)

Odoo

  • workers = 25–45 (según cores y RAM)

  • max_cron_threads = 2–4 (solo si crons están bien diseñados)

  • db_maxconn = 64 (muchas veces mejor no subirlo más; escala PgBouncer/DB)

Por qué así:

En grande, el enemigo es la contención (locks) y las transacciones largas. Más threads no arreglan diseño.

PgBouncer

  • pool_mode = transaction

  • default_pool_size = 120–200 (si Postgres lo soporta)

  • reserve_pool_size = 30–60

  • reserve_pool_timeout = 5

  • max_client_conn = 5000–10000

Extra importante: define límites:

  • max_db_connections para no dejar que una DB “se coma” todo

  • y alertas sobre cl_waiting antes de incidentes

PostgreSQL (orientativo)

  • max_connections = 400–800 (con PgBouncer bien hecho, no necesitas miles)

“Señales” a vigilar

  • locks y bloqueos recurrentes (deadlocks/serialization)

  • crecimiento de p99 cuando corren crons o importaciones

  • autovacuum (si se atrasa, el rendimiento se degrada con el tiempo)


Nota: si tienes multi-tenant (varias DBs en el mismo PgBouncer)

Recuerda que PgBouncer crea pools por (db, user). Eso significa que:

  • si tienes N bases, el “presupuesto” de conexiones reales se reparte entre N pools

  • conviene usar max_db_connections y calcular default_pool_size con ese reparto


Config “mínima común” para cualquier tamaño (la base que no falla)

Odoo

  • proxy_mode = True

  • /websocket/ ruteado al gevent_port (si usas livechat/tiempo real)

  • list_db = False

  • logs con rotación

PgBouncer

  • pool_mode = transaction

  • logs útiles (log_pooler_errors=1)

  • SHOW POOLS; como métrica #1

PostgreSQL

  • timeouts razonables (lock_timeout, statement_timeout)

  • monitoreo de transacciones largas


Cierre: el mejor consejo para que esto funcione

No dimensionas “por intuición”, dimensionas por señales:

  • Si hay cl_waiting: o el pool es chico o hay transacciones largas/locks.

  • Si Postgres está al 100%: no subas pool, optimiza queries/índices o baja concurrencia.

  • Si los crons se pisan: reduce paralelismo o haz batching.


Siguiente capítulo ->

Configuración recomendada por tamaño de empresa (Odoo + PgBouncer + PostgreSQL)
John Wolf 27 de diciembre de 2025
Compartir
Etiquetas
Archivo
Iniciar sesión dejar un comentario