La confiabilidad es una propiedad importante de cualquier sistema de base de datos serio, y PostgreSQL hace todo lo posible para garantizar un funcionamiento confiable. Un aspecto del funcionamiento confiable es que todos los datos registrados por una transacción comprometida deben almacenarse en un área no volátil que esté a salvo de pérdidas de energía, fallos del sistema operativo y fallos de hardware (excepto el fallo de la propia área no volátil, por supuesto). El escribir con éxito los datos en el almacenamiento permanente de la computadora (unidad de disco o equivalente) normalmente cumple con este requisito. De hecho, incluso si una computadora resulta gravemente dañada, si las unidades de disco sobreviven, se pueden mover a otra computadora con hardware similar y todas las transacciones comprometidas permanecerán intactas.
Aunque forzar los datos a los platos del disco periódicamente pueda parecer una operación simple, no lo es. Debido a que las unidades de disco son dramáticamente lentas que la memoria principal y las CPU, existen varias capas de almacenamiento en caché entre la memoria principal de la computadora y los platos del disco. Primero, está el buffer cache del sistema operativo, que almacena en caché los bloques de disco solicitados con frecuencia y combina las escrituras de disco. Afortunadamente, todos los sistemas operativos brindan a las aplicaciones una forma de forzar las escrituras desde el buffer cache al disco, y PostgreSQL utiliza esas características. (Consulta el parámetro wal_sync_method para ajustar cómo se hace esto).
A continuación, podría haber una caché en el controlador de la unidad de disco; esto es particularmente común en las tarjetas controladoras RAID. Algunas de estas cachés son write-through (de escritura inmediata), lo que significa que las escrituras se envían a la unidad tan pronto como llegan. Otras son write-back (de escritura diferida), lo que significa que los datos se envían a la unidad en algún momento posterior. Estas cachés pueden ser un peligro para la confiabilidad porque la memoria en la caché del controlador de disco es volátil y perderá su contenido en caso de un fallo de energía. Las mejores tarjetas controladoras tienen unidades de batería de respaldo (BBUs), lo que significa que la tarjeta tiene una batería que mantiene la energía en la caché en caso de pérdida de energía del sistema. Una vez que se restablece la energía, los datos se escribirán en las unidades de disco.
And finalmente, la mayoría de las unidades de disco tienen cachés. Algunas son write-through mientras que otras son write-back, y existen las mismas preocupaciones sobre la pérdida de datos para las cachés de unidades write-back que para las cachés de controladores de disco. Las unidades IDE y SATA de grado de consumo son particularmente propensas a tener cachés write-back que no sobrevivirán a un fallo de energía. Muchas unidades de estado sólido (SSD) también tienen cachés write-back volátiles.
Estas cachés normalmente se pueden desactivar; sin embargo, el método para hacerlo varía según el sistema operativo y el tipo de unidad:
En Linux, las unidades IDE y SATA se pueden consultar utilizando
hdparm -I; la caché de escritura está habilitada si hay
un * junto a Write cache. Se puede usar
hdparm -W 0 para desactivar la caché de escritura. Las
unidades SCSI se pueden consultar utilizando
sdparm.
Utiliza sdparm --get=WCE para comprobar si la caché de escritura está
habilitada y sdparm --clear=WCE para desactivarla.
En FreeBSD, las unidades IDE se pueden consultar utilizando
camcontrol identify y la caché de escritura se puede desactivar utilizando
hw.ata.wc=0 en /boot/loader.conf; las unidades
SCSI se pueden consultar utilizando camcontrol identify, y la
caché de escritura se puede consultar y cambiar utilizando sdparm cuando
esté disponible.
En Solaris, la caché de escritura del disco se controla mediante
format -e. (El sistema de archivos ZFS de Solaris es seguro con la
caché de escritura de disco habilitada porque emite sus propios comandos de vaciado de caché de disco).
En Windows, si wal_sync_method es
open_datasync (el valor por defecto), la caché de escritura se puede desactivar
desmarcando Mi PC\Abrir\.
Alternativamente, establece unidad de disco\Propiedades\Hardware\Propiedades\Directivas\Habilitar caché de escritura en el discowal_sync_method en
fdatasync (sólo NTFS) o fsync,
que evitan la caché de escritura.
En macOS, la caché de escritura se puede evitar
estableciendo wal_sync_method en fsync_writethrough.
Las unidades SATA recientes (aquellas que siguen ATAPI-6 o posterior)
ofrecen un comando de vaciado de caché de la unidad (FLUSH CACHE EXT),
mientras que las unidades SCSI admiten desde hace mucho tiempo un comando similar
SYNCHRONIZE CACHE. Estos comandos no son directamente
accesibles para PostgreSQL, pero algunos sistemas de
archivos (por ejemplo, ZFS, ext4) pueden
utilizarlos para vaciar los datos a los platos en unidades con write-back habilitado.
Desafortunadamente, tales sistemas de archivos se comportan de manera subóptima
cuando se combinan con controladores de disco con unidad de batería de respaldo
(BBU). En tales configuraciones, el comando de sincronización
fuerza todos los datos desde la caché del controlador a los discos, eliminando
gran parte del beneficio de la BBU. Puedes ejecutar el programa
pg_test_fsync para ver si estás afectado. Si lo estás, los beneficios
de rendimiento de la BBU se pueden recuperar desactivando las barreras de escritura
(write barriers) en el sistema de archivos o reconfigurando el controlador de disco,
si esa es una opción. Si se desactivan las barreras de escritura, asegúrate de que
la batería siga funcionando; una batería defectuosa puede provocar una pérdida de
datos. Con suerte, los diseñadores de sistemas de archivos y controladores de disco
eventualmente abordarán este comportamiento subóptimo.
Cuando el sistema operativo envía una solicitud de escritura al hardware de almacenamiento,
es poco lo que puede hacer para asegurarse de que los datos hayan llegado a un área de
almacenamiento verdaderamente no volátil. Más bien, es responsabilidad del administrador
asegurarse de que todos los componentes de almacenamiento garanticen la integridad
tanto de los datos como de los metadatos del sistema de archivos. Evita los controladores
de disco que tengan cachés de escritura sin batería de respaldo. A nivel de unidad,
desactiva la caché write-back si la unidad no puede garantizar que los datos se escribirán
antes del apagado. Si utilizas unidades SSD, ten en cuenta que muchas de ellas no
respetan los comandos de vaciado de caché por defecto. Puedes probar el comportamiento
confiable del subsistema de E/S utilizando diskchecker.pl.
Otro riesgo de pérdida de datos lo plantean las propias operaciones de escritura en los platos del disco. Los platos del disco se dividen en sectores, comúnmente de 512 bytes cada uno. Cada operación física de lectura o escritura procesa un sector completo. Cuando llega una solicitud de escritura a la unidad, puede ser por algún múltiplo de 512 bytes (PostgreSQL normalmente escribe 8192 bytes, o 16 sectores, a la vez), y el proceso de escritura podría fallar debido a una pérdida de energía en cualquier momento, lo que significa que algunos de los sectores de 512 bytes se escribieron mientras que otros no. Para protegerse contra tales fallos, PostgreSQL escribe periódicamente imágenes de página completa en el almacenamiento permanente de WAL antes de modificar la página real en el disco. Al hacer esto, durante la recuperación de un fallo, PostgreSQL puede restaurar las páginas parcialmente escritas desde el WAL. Si tienes un software de sistema de archivos que evita las escrituras parciales de páginas (por ejemplo, ZFS), puedes desactivar esta generación de imágenes de página desactivando el parámetro full_page_writes. Los controladores de disco con unidad de batería de respaldo (BBU) no evitan las escrituras parciales de páginas a menos que garanticen que los datos se escriban en la BBU como páginas completas (de 8 kB).
PostgreSQL también protege contra algunos tipos de corrupción de datos en dispositivos de almacenamiento que pueden ocurrir debido a errores de hardware o fallos del medio con el paso del tiempo, como la lectura/escritura de datos basura.
Cada registro individual en un archivo WAL está protegido por una comprobación CRC-32C (de 32 bits) que nos permite saber si el contenido del registro es correcto. El valor CRC se establece cuando escribimos cada registro WAL y se comprueba durante la recuperación de fallos, la recuperación de archivos y la replicación.
Las páginas de datos tienen suma de comprobación (checksum) por defecto, y las imágenes de página completa registradas en los registros WAL siempre están protegidas por suma de comprobación.
Las estructuras de datos internas como pg_xact, pg_subtrans,
pg_multixact, pg_serial, pg_notify,
pg_stat, pg_snapshots no tienen suma de comprobación
directamente, ni las páginas están protegidas por escrituras de página completa. Sin embargo,
cuando dichas estructuras de datos son persistentes, se escriben registros WAL que permiten
reconstruir con precisión los cambios recientes en la recuperación de fallos y esos registros WAL
están protegidos como se explicó anteriormente.
Los archivos de estado individuales en pg_twophase están protegidos por CRC-32C.
Los archivos de datos temporales utilizados en consultas SQL grandes para ordenamientos, materializaciones y resultados intermedios no tienen suma de comprobación actualmente, ni se escribirán registros WAL para los cambios en esos archivos.
PostgreSQL no protege contra errores de memoria corregibles y se asume que operarás utilizando memoria RAM que use Códigos de Corrección de Errores (ECC) estándar de la industria o una protección mejor.