Mejores prácticas de almacenamiento de OCI Database with PostgreSQL

Descubre las mejores prácticas para identificar, supervisar y resolver problemas relacionados con el almacenamiento al utilizar OCI Database with PostgreSQL.

OCI Database with PostgreSQL es un servicio totalmente gestionado que gestiona el almacenamiento automáticamente. A diferencia de la PostgreSQL tradicional que requiere que asigne espacio en disco manualmente, OCI PostgreSQL utiliza almacenamiento optimizado para bases de datos que se escala independientemente de los recursos informáticos.

OCI Database with PostgreSQL se basa en el estándar PostgreSQL y sigue las directrices de la comunidad para la seguridad y el diseño del disco, lo que garantiza una experiencia familiar para los usuarios de PostgreSQL. Para obtener más información, consulte el siguiente blog: Presentación de OCI Database with PostgreSQL: Completing Our Cloud Database Suite for Every Need.

Tipos de Almacenamiento

OCI Database with PostgreSQL utiliza las siguientes categorías de almacenamiento primario con diferentes características y requisitos de gestión:

Almacenamiento compartido de escala automática

El almacenamiento compartido de escala automática gestiona los datos de la base de datos y los archivos log de escritura anticipada (WAL). Este tipo de almacenamiento proporciona alta disponibilidad mediante la replicación entre dominios de disponibilidad.

Estas son las características clave del almacenamiento compartido de escala automática:

  • Escala dinámica: el almacenamiento se escala automáticamente a medida que crea y borra objetos de base de datos. No se requiere aprovisionamiento previo y no se produce tiempo de inactividad durante la ampliación.
  • Arquitectura desacoplada: los recursos informáticos y el almacenamiento están separados, lo que permite que cada uno se amplíe de forma independiente en función de sus necesidades.
  • Alta disponibilidad: los datos se replican en los dominios de disponibilidad, lo que permite un failover rápido sin pérdida de datos.
  • Límite estricto: la capacidad máxima es de 32 TB por sistema de base de datos.

El almacenamiento compartido de escala automática almacena los siguientes tipos de contenido:

  • Datos de base de datos, como tablas, índices y otros objetos de base de datos.
  • Archivos WAL para durabilidad y replicación de transacciones.

Almacenamiento temporal

El almacenamiento temporal se asigna por nodo y maneja archivos operativos que no requieren persistencia a largo plazo. Este almacenamiento no se escala automáticamente y su tamaño se basa en la unidad de computación. La fórmula para este tamaño de almacenamiento se basa en Max(50 GB, 2 GB + numOCPU × 32 GB).

Estas son las características clave del almacenamiento temporal:

  • No se escala automáticamente: para aumentar la capacidad, debe actualizar a una unidad de computación más grande.
  • Aislado de datos críticos: si se llena el almacenamiento temporal, los datos de la base de datos y el WAL no se verán afectados.

El almacenamiento temporal almacena los siguientes tipos de contenido:

  • Archivos temporales/derrames de pgsql_tmp/pg_tempdir y pg_replslot, que se crean cuando las consultas superan la memoria disponible.
  • Archivos log PostgreSQL para supervisión y depuración.
  • Archivos de desbordamiento de ranuras de replicación (para replicación lógica).

El resto de este tema aborda las mejores prácticas para gestionar los problemas de agotamiento del almacenamiento para estos tipos de almacenamiento.

Agotamiento del almacenamiento compartido

Las ranuras de replicación garantizan que los archivos WAL se retengan hasta que los suscriptores los hayan consumido. Cuando una ranura de replicación se vuelve inactiva o se queda atrás, PostgreSQL continúa acumulando archivos WAL, que eventualmente pueden agotar el almacenamiento compartido.

A continuación, se muestran escenarios comunes en los que puede producirse el agotamiento del almacenamiento compartido:

  • Ranuras abandonadas: se ha desactivado un suscriptor, pero no se ha borrado la ranura de replicación
  • Problemas de red: los problemas de alta latencia o conectividad entre la base de datos principal y la base de datos en espera hacen que la base de datos en espera se quede atrás
  • Suscriptores lentos: herramientas de CDC de terceros o suscriptores federados que no pueden seguir el ritmo de la actividad de escritura
  • Transacciones de ejecución incorrecta: las sesiones inactivas en transacción bloquean el buffer de reordenación, lo que hace que se acumule WAL

En la siguiente tabla, se muestran los parámetros clave de retención de WAL. El uso del disco WAL depende de estos parámetros combinados con ranuras de replicación activas o inactivas.

Parámetros de retención de WAL
Parámetro Descripción
max_slot_wal_keep_size

Límite de retención de WAL para ranuras de replicación (-1 = ilimitado, lo que supone el riesgo de llenar el disco). Por ejemplo:

max_slot_wal_keep_size = 20GB

Siempre mantiene 20 GB de WAL de replay_lsn de cada ranura.

max_wal_size

Tamaño máximo de WAL antes de forzar un CHECKPOINT. Por ejemplo:

max_wal_size = 5GB

obliga a CHECKPOINT cuando WAL alcanza los 5 GB.

wal_keep_size

Mínimo de archivos WAL que conservar para seguridad en espera (sin ranuras de replicación). Por ejemplo:

wal_keep_size = 10GB

Siempre mantiene 10 GB de WAL del LSN actual.

En la siguiente tabla, se muestran los beneficios y los riesgos de las configuraciones de WAL.

Beneficios y riesgos de la configuración de parámetros
Configuración de Parámetros Beneficio Riesgo
max_slot_wal_keep_size = -1 La replicación no se interrumpe debido a la eliminación de WAL. El disco principal se puede llenar.
max_slot_wal_keep_size = 50GB El elemento primario está protegido contra el agotamiento del disco. La replicación podría interrumpirse si la espera se retrasa demasiado.

Supervisión y alertas

Utilice la siguiente consulta para identificar la retención de WAL por ranuras de replicación:

SELECT 
    slot_name,
    active,
    pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS wal_retained,
    pg_size_pretty(safe_wal_size) AS safe_wal_remaining
FROM pg_replication_slots;

En este ejemplo de un retorno, se retienen 15 GB de WAL y solo se pueden retener 5 GB más antes de que la ranura se invalide (si se configura max_slot_wal_keep_size). Si max_slot_wal_keep_size = -1, safe_wal_remaining muestra NULL.

 slot_name | active | wal_retained | safe_wal_remaining
-----------+--------+--------------+--------------------
 replica_1 | t      | 15 GB        | 5 GB

Para obtener instrucciones sobre la configuración de alarmas personalizadas, consulte Creación de alarmas y paneles de control de supervisión de OCI personalizados de PostgreSQL mediante Container Instances

Le recomendamos que configure alertas si se produce alguna de las siguientes condiciones:

  • wal_retained supera el 50 % de la capacidad disponible.
  • Cualquier espacio tiene active = false durante más de una hora.

Mitigación y prevención

Utilice las siguientes medidas de mitigación según sea necesario:

  • Borrar ranuras abandonadas: si un suscriptor ya no es necesario o se puede volver a crear, borre la ranura de replicación:
    SELECT pg_drop_replication_slot('slot_name');
  • Definir límite de retención finito: configure max_slot_wal_keep_size en un valor que equilibre la estabilidad de la replicación con la protección principal.
Le recomendamos que siga estas medidas de prevención:
  • Seleccione el valor max_slot_wal_keep_size adecuado según los siguientes requisitos:
    • Para la replicación crítica: defina un valor superior o -1, pero supervise de cerca el uso del disco.
    • Para protección principal: defina un valor finito y acepte que la replicación se pueda interrumpir durante interrupciones prolongadas.
    • Para suscriptores que se pueden volver a crear: utilice valores inferiores porque el suscriptor se puede volver a crear si es necesario.
  • Implantar la supervisión de ranuras: configure alertas automatizadas antes de que las ranuras causen problemas de almacenamiento.
  • Propiedad de espacio de documento: mantenga un registro del cual la aplicación o el equipo sea propietario de cada espacio de replicación.
  • Planificación de problemas de red: garantiza un ancho de banda adecuado y una baja latencia entre las réplicas y las primarias.

Agotamiento de almacenamiento temporal

El almacenamiento temporal se puede agotar debido a un registro excesivo, una configuración de memoria inadecuada que causa archivos de desbordamiento o archivos de desbordamiento de ranuras de replicación. En esta sección se trata cada escenario con orientación de supervisión y resolución.

Registro excesivo de PostgreSQL

PostgreSQL proporciona amplios parámetros de registro útiles para la depuración. Sin embargo, la configuración de registro agresiva puede generar una E/S de disco excesiva durante el tráfico máximo, llenando rápidamente el volumen de almacenamiento temporal.

Estas son las configuraciones problemáticas comunes:

  • log_statement = 'all': registra cada sentencia SQL, generando volúmenes de log masivos en sistemas ocupados.
  • log_min_duration_statement = 0: registra cada sentencia con su duración.
  • log_connections/log_disconnections = on: en sistemas de alto tráfico, genera entradas para cada conexión.
  • Registro de nivel de depuración activado: los parámetros como log_executor_stats, log_parser_stats, log_planner_stats generan una salida detallada.

Los síntomas del registro excesivo de PostgreSQL incluyen:

  • El uso de almacenamiento temporal aumenta rápidamente.
  • E/S de disco alto en el volumen de registro.

Mitigación y prevención

Siga estas directrices para mitigar y evitar problemas relacionados con el registro excesivo:

  • Revise y ajuste los parámetros de registro según los requisitos de la aplicación.
  • Desactive el registro detallado una vez finalizada la depuración.
  • Evite dejar activado el registro de nivel de depuración en producción, ya que esto agrega una carga innecesaria al servidor de la base de datos.
  • Si el registro legítimo necesita más espacio, aumente la unidad del nodo o escale verticalmente el sistema de base de datos.

En la siguiente tabla, se muestran los parámetros de registro y la información relacionada.

Parámetros de Log
Parámetro Descripción Valor problemático Valor Recomendado
log_statement Controla qué sentencias SQL se registran todos Ninguno o ddl o mod
log_min_duration_statement Sentencias de logs que superan los milisegundos especificados 0 -1 o ≥1000
log_connections Registra cada conexión correcta en (alto tráfico) desactivado
log_disconnections Registra terminaciones de sesiones, incluida la duración en (alto tráfico) desactivado
log_autovacuum_min_duration Registra acciones de vacío automático que exceden los milisegundos especificados 0 -1 o ≥60000
log_error_verbosity Controla el nivel de detalle de los mensajes de error detallado por defecto
log_executor_stats Logs de estadísticas de rendimiento del ejecutor activado desactivado
log_parser_stats Estadísticas de rendimiento del analizador de logs activado desactivado
log_planner_stats Registra estadísticas de rendimiento del planificador activado desactivado
log_statement_stats Logs de estadísticas de rendimiento total de sentencias activado desactivado
log_duration Registra la duración de cada sentencia completada en (alto tráfico) desactivado

Configuración de memoria inadecuada (archivos temporales/de recarga)

PostgreSQL utiliza memoria adicional más allá de shared_buffers para el procesamiento de consultas. Mientras que shared_buffers maneja el almacenamiento en caché de datos y las operaciones DML en memoria, work_mem se utiliza para operaciones de consulta como la ordenación, la unión y la agregación.

Cuando una consulta implica operaciones JOIN, AGGREGATE o SORT, PostgreSQL primero comprueba si las columnas relevantes tienen índices preordenados. Si los índices no están disponibles, PostgreSQL intenta realizar estas operaciones en la memoria.

Si el valor work_mem no es suficiente para los datos que se están procesando, PostgreSQL genera archivos temporales y utiliza disco en lugar de memoria.

A continuación, se muestran escenarios comunes en los que se puede producir una configuración de memoria inadecuada:

  • Consultas analíticas complejas: consultas con varias JOIN, ordenaciones grandes o agregaciones en juegos de datos grandes.
  • Valor por defecto work_mem demasiado bajo: el valor por defecto de 4 MB puede ser insuficiente para consultas complejas.
  • Alta simultaneidad con consultas que hacen un uso intensivo de la memoria: muchas consultas simultáneas consumen work_mem cada una.
  • Operaciones de mantenimiento: las operaciones como CREATE INDEX, REINDEX, CLUSTER o REFRESH MATERIALIZED VIEW utilizan maintenance_work_mem y pueden generar archivos temporales si el tamaño es bajo.

En el siguiente ejemplo, se muestra una entrada de log de ejemplo cuando el disco se llena:

2025-12-03 10:55:25.650 UTC [249610] ERROR: could not write block 196800198 of temporary file: No space left on device

Los síntomas de una configuración de memoria inadecuada excesiva incluyen:

  • El almacenamiento temporal se completa durante la ejecución de consultas complejas.
  • Rendimiento de consultas lento en operaciones JOIN, SORT o AGGREGATE.
  • Aumento de E/S de disco durante el procesamiento de consultas.

Supervisión y alertas

Utilice la siguiente consulta para identificar el uso de archivos temporales por base de datos:

SELECT 
    datname,
    temp_files,
    pg_size_pretty(temp_bytes) AS temp_size
FROM pg_stat_database
WHERE temp_bytes > 0
ORDER BY temp_bytes DESC;

A continuación, se muestra un ejemplo de lo que se devuelve:

 datname  | temp_files | temp_size  
----------+------------+------------
 app      |       1523 | 45 GB      
 postgres |         12 | 120 MB  
Nota

Estos valores son acumulativos. A medida que la base de datos continúa generando archivos temporales, estos valores aumentan con el tiempo.

Utilice la siguiente consulta para comprobar el uso de archivos temporales activos:

SELECT * FROM pg_ls_tmpdir();

A continuación, se muestra un ejemplo de lo que se devuelve:

       name        |   size   |      modification      
-------------------+----------+------------------------
 pgsql_tmp249610.3 | 14000000 | 2025-12-03 10:20:16+00
 pgsql_tmp249696.0 | 12394496 | 2025-12-03 10:20:16+00
 pgsql_tmp249610.2 | 13860864 | 2025-12-03 10:20:16+00
 pgsql_tmp249697.0 | 12910592 | 2025-12-03 10:20:16+00

Introduzca los siguientes comandos para comprobar la configuración de memoria actual:

SHOW work_mem;
SHOW hash_mem_multiplier;
SHOW maintenance_work_mem;

Para obtener instrucciones sobre la configuración de alarmas personalizadas, consulte Creación de alarmas y paneles de control de supervisión de OCI personalizados de PostgreSQL mediante Container Instances

Le recomendamos que configure alertas si se produce alguna de las siguientes condiciones:

  • TempStorageUsedPercent supera los umbrales definidos.
  • El uso de archivos temporales (de pg_ls_tmpdir()) muestra un crecimiento sostenido.

Mitigación y prevención

Siga estas prácticas para mitigar y evitar los problemas asociados con una configuración de memoria inadecuada:

  • Identificar consultas que generan archivos temporales

    Active el registro para capturar consultas que generan archivos temporales:

    • Defina log_temp_files = 0 para registrar toda la creación de archivos temporales
    • Defina log_min_error_statement = log para incluir el texto de consulta SQL

    A continuación, se muestra un ejemplo de entrada de archivo log temporal:

    2025-12-03 10:45:17.650 UTC [249610] LOG: temporary file: path "pg_tempdir/pgsql_tmp/pgsql_tmp249610.5", size 14000000
    
  • Optimización de consultas

    Revise las consultas registradas y optimícelas cuando sea posible. El ajuste de consultas debe ser el primer enfoque antes de aumentar la configuración de memoria. Considere la posibilidad de agregar índices adecuados para evitar ordenaciones en memoria.

  • Ajustar work_mem (si no es posible la optimización de consultas)

    Si no se pueden mejorar las consultas, considere aumentar work_mem. Utilice la siguiente fórmula como punto de partida:

    work_mem <= (Available Memory) / (max_connections + max_parallel_workers)

    Donde Available Memory es la memoria total del sistema menos shared_buffers y oci.pagecache_size.

    Nota

    En el peor de los casos, cada sesión puede consumir esta cantidad de memoria. Si todas las sesiones requieren work_mem simultáneamente, podría agotar la memoria disponible del sistema.

    Reducir la generación temporal de archivos, pero no eliminarlos por completo. La eliminación de todos los archivos temporales puede requerir una unidad de computación más grande o el consumo de toda la memoria disponible.

  • Ajustar hash_mem_multiplier (para operaciones hash)

    Si las consultas siguen generando archivos temporales e implican operaciones hash (no SORT), aumente hash_mem_multiplier:

    SHOW hash_mem_multiplier;
     hash_mem_multiplier 
    ---------------------
     1
    (1 row)
    

    Al aumentar este valor, se asigna más memoria para las operaciones hash. La memoria hash efectiva es work_mem × hash_mem_multiplier.

  • Ajustar maintenance_work_mem para operaciones de mantenimiento

    Las consultas regulares de aplicaciones no son el único origen de archivos temporales. Las operaciones de mantenimiento también generan archivos temporales:

    • REFRESH MATERIALIZED VIEW
    • CREATE INDEX
    • CLUSTER
    • REINDEX

    Estas operaciones utilizan maintenance_work_mem en lugar de work_mem:

SHOW maintenance_work_mem;

Si las operaciones de mantenimiento se ejecutan en juegos de datos grandes y maintenance_work_mem es insuficiente, se generan archivos temporales.

En la siguiente tabla, se muestran los parámetros de memoria y la información relacionada.

Referencia de parámetros de memoria
Parámetro Descripción Riesgo si está mal configurado Valor Recomendado
work_mem Memoria base por operación de ordenación/hash antes de derramarse al disco Demasiado alto con alta simultaneidad Menor para OLTP y mayor para análisis
hash_mem_multiplier Multiplicador para operaciones hash: hash_mem = work_mem × este valor Demasiado alto (≥8.0) con alta simultaneidad 2.0 (valor por defecto)
maintenance_work_mem Memoria para operaciones VACUUM, CREATE INDEX, REFRESH MATERIALIZED VIEW Demasiado alto con muchos trabajadores de autovacuum Saldo con autovacuum_max_workers

Archivos de desbordamiento de ranuras de replicación (replicación lógica)

La replicación lógica PostgreSQL utiliza la descodificación lógica para transformar los registros WAL raw en cambios significativos y estructurados a nivel de fila. A diferencia de la replicación física que copia bloques de disco de byte a byte, la descodificación lógica interpreta los datos transaccionales y los convierte en cambios lógicos (INSERT, UPDATE, DELETE) con valores de columna reales.

Cada ranura de replicación lógica tiene un proceso de remitente WAL asociado responsable de los cambios de transmisión en los suscriptores de destino. Las transacciones se envían en orden de confirmación, y el suscriptor recibe, descodifica y aplica estos cambios al sistema de destino.

PostgreSQL soporta la replicación lógica nativa donde el suscriptor es otra instancia PostgreSQL. A partir de PostgreSQL 14, los suscriptores pueden gestionar grandes transacciones en curso de forma eficaz con el modo streaming=on activado:

  • Las transacciones en curso (todavía no confirmadas) se transmiten de forma incremental al suscriptor.
  • El suscriptor aplica los cambios a un estado temporal/pendiente inmediatamente.
  • Una vez que la transacción se confirma en el editor, el suscriptor confirma esos cambios.
  • Si se realiza un rollback de la transacción, el suscriptor descarta los cambios pendientes.

Este enfoque evita que el editor acumule grandes cantidades de datos descodificados en la memoria o derrame archivos mientras espera que se completen las transacciones de larga ejecución.

Los suscriptores federados o de terceros también pueden consumir de ranuras de replicación lógicas PostgreSQL mediante el protocolo de replicación PostgreSQL. Sin embargo, a diferencia de los suscriptores PostgreSQL nativos, los suscriptores federados normalmente no soportan el modo streaming=on porque no pueden controlar cómo se comporta el sistema de destino subyacente.

Cuando un suscriptor no admite streaming=on, el remitente de WAL de PostgreSQL mantiene los cambios descodificados para las transacciones en curso en los archivos de vertido en:

pg_replslot/<slot_name>/xid-<xid>-lsn-<lsn>.spill

Estos archivos de derrame pueden crecer debido a la estricta garantía de orden de confirmación de PostgreSQL. Por ejemplo:

  • La transacción TRX1 permanece abierta durante mucho tiempo (inactivo en la transacción o realizando operaciones masivas).
  • Otras transacciones independientes (TRX2, TRX3, TRX4, etc.) continúan confirmándose.
  • El remitente de WAL acumula datos de transacciones confirmadas en los archivos de derrames.
  • Estas transacciones solo se envían al suscriptor después de que TRX1 emita COMMIT o ROLLBACK.

Este es el comportamiento esperado al trabajar con suscriptores federados que no soportan el modo streaming=on.

En el siguiente ejemplo, se muestran los detalles del archivo de derrames (registrados en el nivel DEBUG2) en el registro:

2025-12-03 10:28:14.650 UTC [249610] DEBUG: spill 4096 changes in XID 750 to disk

Si el disco se llena, las entradas del log cambian a lo siguiente:

2025-12-03 10:32:15.550 UTC [249610] ERROR: could not write to data file for XID <xid>: No space left on device
2025-12-03 10:32:15.554 UTC [249610] ERROR: could not read from reorderbuffer spill file: No space left on device

Los síntomas de los archivos de desbordamiento de ranura de replicación incluyen:

  • El uso de almacenamiento temporal aumenta rápidamente.
  • Muchos archivos .spill están presentes en la carpeta pg_replslot.

Supervisión y alertas

Utilice la siguiente consulta para identificar estadísticas de archivos de desbordamiento para ranuras de replicación:

SELECT 
    slot_name,
    spill_txns,
    spill_count,
    pg_size_pretty(spill_bytes) AS spill_size,
    stream_txns,
    stream_count,
    pg_size_pretty(stream_bytes) AS stream_size
FROM pg_stat_replication_slots;

En el siguiente ejemplo de una devolución:

    slot_name     | spill_txns | spill_count | spill_size | stream_txns | stream_count | stream_size 
------------------+------------+-------------+------------+-------------+--------------+-------------
 federated_sub_1  |        847 |       15234 | 2458 MB    |           0 |            0 | 0 bytes
  • spill_size de 2458 MB indica un uso significativo del disco de los archivos de desbordamiento.
  • stream_size de 0 bytes confirma que el suscriptor no es nativo y no soporta el modo de transmisión.
  • El proceso de remitente WAL está reteniendo o derramando transacciones en el disco.

Utilice el siguiente comando para comprobar la configuración actual de logical_decoding_work_mem:

SHOW logical_decoding_work_mem;
 logical_decoding_work_mem 
---------------------------
 64MB

Para obtener instrucciones sobre la configuración de alarmas personalizadas, consulte Creación de alarmas y paneles de control de supervisión de OCI personalizados de PostgreSQL mediante Container Instances

Le recomendamos que configure alertas si se produce alguna de las siguientes condiciones:

  • spill_bytes por espacio supera los umbrales definidos.
  • El uso de archivos de derramamiento muestra un rápido crecimiento.

Mitigación y prevención

Las transacciones de vertido son inevitables cuando están involucrados suscriptores no nativos. Sin embargo, puede reducir la frecuencia y el tamaño de los archivos de derrames siguiendo estas prácticas:

  • Manejar cuidadosamente las transacciones grandes: realice operaciones masivas en lotes más pequeños.
  • Evitar transacciones inactivas de larga ejecución: bloquean el buffer de reordenación y causan la acumulación de archivos de derrame.
  • Aumentar logical_decoding_work_mem: retrasa el derrame al permitir más datos descodificados en la memoria.
  • Definir idle_in_transaction_session_timeout: finaliza las sesiones que permanecen inactivas en la transacción durante demasiado tiempo.

En la siguiente tabla, se muestran los parámetros de descodificación lógica y la información relacionada.

Referencia de parámetros de descodificación lógica
Parámetro Descripción Riesgo si no está configurado correctamente Valor Recomendado
logical_decoding_work_mem Umbral de memoria antes de derramar los cambios descodificados en pg_replslot/<slot>/. Este valor se aplica a cada ranura de replicación lógica. Demasiado bajo con transacciones grandes/largas DE 256 MB A 1 GB
idle_in_transaction_session_timeout Finaliza las sesiones de inactividad en transacción que bloquean la entrega del buffer de reorden 0 (desactivado) 10 min–30 min