Skip to content

Disco do servidor 100% cheo (0 bytes libres): recuperando unha base de datos accidentada cando rm e apt Fallo por falta de inodos/espazo

Os números de emerxencia varían segundo o país. Esta páxina usa 911, o número dos Estados Unidos e Canadá. Moitos outros países usan 112, 999 ou outro número. Busca o número do teu país.

Descubrindo que un servidor Linux de produción chegou 100% utilización do disco (0 bytes free) ou 100% utilización de inodos (df -i) mentres se executa unha base de datos PostgreSQL, MySQL/InnoDB, MariaDB ou SQLite activa é un dos modos de falla máis perigosos na administración de sistemas. A cero bytes ou cero inodos libres, a crise cae en cascada rapidamente: o núcleo do sistema operativo xa non pode crear sockets de dominio Unix en /tmp ou /var/run, bash non pode completar a tabulación porque non pode escribir shell pipes temporais, apt ou dnf non se pode executar para limpar paquetes porque os xestores de paquetes requiren ficheiros de bloqueo temporais e o seu motor de base de datos falla no medio dun rexistro de escritura anticipada (WAL) ou rexeita apagarse de forma limpa porque non pode asignar un só bloque de 4 kilobytes (0,004 megabytes) para o seu .pid ou bloquear o ficheiro. Peor aínda, os administradores en pánico adoitan executarse rm -rf /var/log/*.log en ficheiros de rexistro de varios gigabytes e mira con horror como df -h aínda informa 100% Use% (0 Avail), ou eliminan fatalmente pg_wal (pg_xlog) ou ib_logfile0 para liberar espazo, corrompindo permanentemente a base de datos máis aló da recuperación da transacción. Se eliminou accidentalmente ficheiros de base de datos críticos durante un intento de limpeza, pare inmediatamente e cambie a accidental rm -rf ou Shift-Delete de só lectura remonta e escultura de inodo; se o seu hardware de almacenamento subxacente está lanzando erros de E/S ou se bloqueou contra as escrituras, consulte Modo de só lectura súbito SSD e NVMe e o rescate desactivando TRIM ou recuperación de ficheiros de Word, Excel, PDF e bases de datos corruptos. Se esta interrupción afecta aos sistemas de seguridade dos hospitais, ao envío de emerxencias ou aos servizos públicos críticos, chame ao número de emerxencia local (911 nos Estados Unidos e Canadá, 112 en toda a Unión Europea, 999 no Reino Unido) ou consulte o noso directorio global de números de emerxencia.

Fai isto agora

  1. ** NON borrar pg_wal/, pg_xlog/, pg_multixact/, ib_logfile*, undo_*, ou -wal / -shm ficheiros para facer espazo**: a eliminación dos ficheiros de rexistro de Write-Ahead ou de InnoDB refacer/desfacer mentres unha base de datos está bloqueada ou desactivada destrúe o único rexistro de páxinas non comprometidas e en voo. Unha base de datos cun disco cheo é recuperable ao 100 por cento unha vez que se libera espazo; unha base de datos cuxos ficheiros WAL foron eliminados manualmente rm sufrirá unha corrupción irreversible da árbore B e do montón.
  2. Diagnóstica en 5 segundos se estás sen bloques de disco (df -h), fóra dos inodos do sistema de ficheiros (df -i), ou mantendo abertos ficheiros desvinculados (lsof +L1):
  3. Corre df -h para comprobar a capacidade do bloque e df -i para comprobar a capacidade do inodo. Un servidor con 50 gigabytes (53.600 millóns de bytes) de espazo libre en disco aínda No space left on device (ENOSPC) se df -i mostra IUse% = 100% (normalmente causado por millóns de pequenos ficheiros de sesión, caché ou spool de correo).
  4. Se df -h mostra 100% usado (0 Avail) mesmo despois de correr rm en ficheiros de rexistro enormes, executa sudo lsof +L1. Calquera ficheiro eliminado con rm mentres nginx, rsyslog, docker, postgres, ou mysqld aínda ten un descritor de ficheiro aberto segue consumindo o 100 por cento dos seus bloques de disco ata que se reinicie o proceso ou trunque o descritor directamente.
  5. Gigabytes gratuítos de espazo en 1 segundo sen reiniciar os daemons truncando os ficheiros abertos no seu lugar (: > /path/to/logfile ou : > /proc/<pid>/fd/<n>):
  6. No canto de rm /var/log/syslog (o que deixa os bloques bloqueados polo rexistrador en execución), cero o ficheiro no seu lugar usando a redirección nula de shell: sudo sh -c ': > /var/log/syslog' ou sudo truncate -s 0 /var/log/syslog.
  7. Se xa correches rm nun ficheiro de rexistro masivo e df -h non caeu, busque o seu ID de proceso (PID) e o descritor do ficheiro (FD) en sudo lsof +L1 e trunqueo directamente a través da interface procfs do núcleo: sudo sh -c ': > /proc/<PID>/fd/<FD>'. O espazo volverá df -h instantáneamente.
  8. ** Desbloquea a sala de respiración de emerxencia instantánea activada ext4 / ext3 reducindo a porcentaxe de bloque raíz reservado (tune2fs -m 1)**: Por defecto, ext4 reserva o 5 por cento de toda a partición (25 gigabytes sobre a 500 gigabyte disco) exclusivamente para UID 0 (root), é dicir, servizos non root como postgres (UID 109), mysql, e www-data bater No space left on device ao 95 por cento de utilización. Recupera o 80 por cento desa reserva en liña en 1 segundo sen tempo de inactividade correndo sudo tune2fs -m 1 /dev/sda1 (ou o seu dispositivo de bloqueo raíz de findmnt /).
  9. ** Baleiro systemd-journald rexistros binarios e cachés de paquetes antigos con seguridade**: Executar sudo journalctl --vacuum-size=50M (que xira con seguridade e purga o binario /var/log/journal arquivos ata 50 megabytes) e sudo apt-get clean (ou sudo dnf clean all), que elimina os descargados .deb / .rpm arquivos en /var/cache/apt/archives/ sen necesidade de escribir na base de datos dpkg.
  10. Unha vez que polo menos 1 gigabyte a 5 gigabytes (de 1.070 a 5.360 millóns de bytes) de espazo estean libres, abra a base de datos en modo de usuario único ou de recuperación para completar o seu punto de control WAL antes de permitir o tráfico do cliente: Permita que PostgreSQL, MySQL/InnoDB ou SQLite reproduzan o seu rexistro de escritura anticipada (WAL), limpa as páxinas sucias aos ficheiros de datos principais e recicla os seus segmentos WAL inchados limpamente antes de volver abrir o teu firewall de aplicacións ou o servidor web.

Danger

Nunca corres pg_resetwal (ou pg_resetxlog) en PostgreSQL ou innodb_force_recovery = 6 en MySQL simplemente porque o disco se encheu: En execución pg_resetwal borra os punteiros do rexistro de transaccións e obriga a PostgreSQL a comezar con páxinas de datos a medio escribir, o que garante a perda de filas silenciosas, as claves primarias duplicadas e as árbores B de claves estranxeiras rotas. No 99,9 por cento dos fallos de bases de datos con disco cheo, simplemente liberar de 2 gigabytes a 10 gigabytes (de 2.100 a 10.700 millóns de bytes) de espazo na partición e iniciar o daemon da base de datos normalmente permite a recuperación automática do fallo (REDO fase) para rematar limpamente sen perda de datos.


Árbore de decisións: servidor de espazo cero e triaxe de bases de datos fallidas

Use esta árbore de decisións para identificar por que o sistema operativo está a informar ENOSPC (No space left on device) e seleccione o camiño exacto de recuperación non destrutivo:

flowchart TD
    Start["Lanzamento do servidor ou da base de datos: non queda espazo no dispositivo (ENOSPC)"] --> CheckDF["Executar: df -h E df -i"]

    CheckDF --> DiagType{"Que informa df?"}

    DiagType -->|"df -h Mostra o 100 % de uso (0 Dispoñibilidade) E df -i < 95 %"| BlockFull["Esgotamento do bloque: comproba se du -shx / Coincide con df -h"]
    DiagType -->|"df -h mostra GB gratuítos PERO df -i mostra 100% de uso"| InodeFull["Esgotamento do inodo: millóns de ficheiros pequenos de 0 a 4 KB"]
    DiagType -->|"Tanto df -h como df -i amosan < 90 % de uso"| RamOrQuota["Límite oculto: verifique df -h /tmp (tmpfs RAM chea), Docker Overlay2 ou XFS/ext4 Disk Quotas"]

    BlockFull --> GhostCheck{"Xa executaches rm en ficheiros grandes sen soltar df?"}
    GhostCheck -->|"Si: du é moito máis pequeno que df"| UnlinkedFD["Executar: sudo lsof +L1 -> Truncar Ghost File a través de: > /proc/PID/fd/FD"]
    GhostCheck -->|"Non: os ficheiros reais están enchendo o disco"| EmergencySpace["Crear unha sala de respiración inmediata (de 1 GB a 5 GB)"]

    EmergencySpace --> Ext4Check{"O sistema de ficheiros é ext4/ext3?"}
    Ext4Check -->|"Si"| Tune2fs["Executar: sudo tune2fs -m 1 /dev/root_dev (libera instantáneamente o 4% do disco para usuarios de base de datos non root)"]
    Ext4Check -->|"Non (XFS/Btrfs/ZFS)"| TruncLogs["Trunca os rexistros no lugar (: > /var/log/syslog) e executa journalctl --vacuum-size=50M"]

    InodeFull --> InodeClean["Buscar directorio con millóns de ficheiros usando find / -xdev -printf '%h\n' | ordenar | uniq -c | ordenar -k 1 -r | cabeza -20 -> Eliminar con find -delete"]

    UnlinkedFD --> DBRecover["Vaia a Database Engine WAL & B-Tree Recovery"]
    Tune2fs --> DBRecover
    TruncLogs --> DBRecover
    InodeClean --> DBRecover
    RamOrQuota --> DBRecover

    DBRecover --> WhichDB{"Que motor de base de datos fallou?"}
    WhichDB -->|"PostgreSQL"| PGFlow["Mantén pg_wal intacto -> Iniciar Postgres para reproducir WAL -> Executar CHECKPOINT; -> Eliminar ranuras de replicación obsoletas"]
    WhichDB -->|"MySQL / MariaDB (InnoDB)"| MyFlow["Manter ib_logfile* intacto -> Iniciar mysqld -> Purgar rexistros binarios mediante PURGAR REGISTROS BINARIOS -> Optimizar táboas"]
    WhichDB -->|"SQLite 3"| SqFlow["Facer unha copia de seguridade .db + .db-wal + .db-shm -> Executa PRAGMA wal_checkpoint (TRUNCATE) ou sqlite3 broken.db '.recover'"]

Fase 1: Por que os comandos estándar (rm, apt, tab-completion) falla en 0 bytes libres

Cando unha partición de Linux alcanza o 100 por cento de bloqueo ou esgotamento do inodo, os comandos de corrección estándar fallan de xeito inesperado: - Presionando Tab en bash lanzamentos cannot create temp file for here-document: No space left on device: Moderno bash-completion scripts crean ficheiros temporais en /tmp. Se /tmp reside na raíz / partición en lugar de a tmpfs Montaxe de RAM, finalización de shell e heredocs (<<EOF) falla. Corrixa isto inmediatamente apuntando TMPDIR á memoria RAM compartida:

export TMPDIR=/dev/shm
- apt-get autoremove ou dpkg --configure -a falla con No space left on device: Cando /boot ou / está cheo ao 100%, apt non pode eliminar núcleos antigos porque dpkg primeiro debe escribir as actualizacións de estado /var/lib/dpkg/updates/. Pola contra, corre sudo apt-get clean (que desliga da caché .deb arquivos en /var/cache/apt/archives/ directamente), ou trunque unha imaxe do núcleo non utilizada /boot (sudo sh -c ': > /boot/initrd.img-<old-unused-version>') dar dpkg os 50 megabytes (52,4 millóns de bytes) que precisa para executarse sudo dpkg --purge linux-image-<old-unused-version>. - rm /path/to/dir/* falla con Argument list too long: Cando df -i está ao 100 por cento porque un directorio como /var/lib/php/sessions contén millóns de ficheiros pequenos, comodíns globbing (*) desborda o núcleo ARG_MAX buffer (2 megabytes) antes rm comeza. Use find con -delete en cambio:
sudo find /var/lib/php/sessions -type f -delete

As 5 causas distintas de No space left on device (ENOSPC)

Antes de tocar calquera ficheiro de base de datos, compare estes cinco escenarios para confirmar que recurso está realmente esgotado:

Comando de diagnóstico Síntoma observado Causa raíz Corrección inmediata de 10 segundos
df -h vs sudo du -shx / df -h mostra 100% usado (0 Avail), pero du -shx / suma só 60% do tamaño do disco. Abrir ficheiros sen ligar ("Ficheiros pantasma"): alguén correu rm nun enorme ficheiro de rexistro ou temporal durante un proceso (nginx, java, postgres, docker) aínda o tiña aberto. Corre sudo lsof +L1, localiza o PID e FD da (deleted) arquivo e executalo sudo sh -c ': > /proc/<PID>/fd/<FD>'.
df -h espectáculos 95% usado, 0 Avail Used + Avail non é igual Size; root pode escribir ficheiros, pero postgres ou mysql recibe ENOSPC. ext4 Bloques raíz reservados (5 % predeterminado): ext4 Retén o 5 por cento dos bloques de usuarios non root (UID > 0) para evitar bloqueos de raíz e fragmentación. Corre sudo tune2fs -m 1 /dev/<partition> para baixar a reserva do 5 por cento ao 1 por cento inmediatamente en liña.
df -i df -h mostra gigabytes de espazo libre, pero df -i mostra IUse% = 100% (IFree = 0). Egotamento do inodo: ext4 ten un número fixo de inodos creados en mkfs tempo; millóns de ficheiros pequenos consumiron cada ranura de inodo. Atopar o cartafol culpable (sudo find / -xdev -printf '%h\n' \ | ordenar \ | uniq -c \ | ordenar -k 1 -r \ | cabeza -10) and run sudo find /culprit/dir -type f -delete.
sudo mount\ | grep /ruta du -sh /var/log é pequeno, aínda / ten 40 gigabytes de espazo perdido. Ficheiros ocultos baixo un punto de montaxe: un proceso escribiu 40 gigabytes /mnt/backup mentres que a unidade externa estaba desmontada, e máis tarde alguén montou un disco enriba de /mnt/backup, ocultando os ficheiros subxacentes du. Montar o sistema de ficheiros raíz nunha vista temporal (sudo mkdir /dev/shm/rootview && sudo mount --bind / /dev/shm/rootview), comprobar du -sh /dev/shm/rootview/mnt/*, e elimine os ficheiros ocultos.
btrfs filesystem df / df -h mostra 20 gigabytes gratis en a Btrfs volume, pero as escrituras fallan ENOSPC. Btrfs Esgotamento de fragmentos de metadatos: Btrfs asigna espazo en anacos de datos e metadatos separados; se todo o espazo en bruto non asignado está bloqueado en fragmentos de datos escasos, os anacos de metadatos alcanzan o 100 por cento. Engade temporalmente un dispositivo de bucle de ficheiros RAM de 2 gigabytes (dd if=/dev/zero of=/dev/shm/btrfs_ram bs=1M count=2048 && sudo btrfs device add -f /dev/shm/btrfs_ram /), correr sudo btrfs balance start -dusage=10 /, entón sudo btrfs device remove /dev/shm/btrfs_ram /.

Fase 2: recuperar espazo no disco de forma segura en menos de 60 segundos

Siga estes pasos exactos para recuperar entre 500 megabytes e 50 gigabytes (de 0.530 a 53.600 millóns de bytes) de espazo sen corromper os procesos activos:

Paso 1: trunque os ficheiros abertos eliminados ("pantasma") mediante /proc/<pid>/fd/

Se vostede ou un script de logrotate automatizado xa eliminou ficheiros grandes pero non se devolveu espazo no disco, comprobe a táboa de ficheiros abertos desvinculados do núcleo:

sudo lsof +L1
Mira o SIZE/OFF columna (medido en bytes). Se ves unha entrada como:
COMMAND    PID     USER   FD   TYPE DEVICE    SIZE/OFF NLINK    NODE NAME
mysqld    1942    mysql    6u   REG  259,1 34896609280     0  918273 /tmp/ibXz91aB (deleted)
rsyslogd   612   syslog    7w   REG  259,1 18253611008     0  131092 /var/log/syslog.1 (deleted)
Aquí, rsyslogd (PID 612, descritor do ficheiro 7w -> 7) mantén aberto un ficheiro de rexistro eliminado de 18,2 gigabytes. Non kill -9 procesos de bases de datos (mysqld ou postgres) para liberar /tmp ficheiros se pode liberar espazo noutro lugar primeiro. Pola contra, pon a cero o descritor do ficheiro de rexistro (PID 612, FD 7) directamente na memoria do núcleo:
sudo sh -c ': > /proc/612/fd/7'
Corre df -h inmediatamente: todos os 18,2 gigabytes son liberados no lugar sen reiniciar un só servizo.

Paso 2: Recuperar ext4 bloques reservados en liña con tune2fs

En calquera ext4 ou ext3 sistema de ficheiros, verifique o número de bloques reservados actual:

df -h /
sudo tune2fs -l /dev/nvme0n1p1 | grep -i "reserved block"
Porque PostgreSQL (postgres), MySQL (mysql), Redis (redis), e aplicacións web SQLite (www-data, node) executados como usuarios non root sen privilexios, o núcleo de Linux impide que usen o último 5 por cento do disco. Reducindo a proporción de bloques reservados de 5% a 1% (ou 0% durante unha emerxencia activa) ten efecto instantáneamente nun sistema de ficheiros montado en directo:
sudo tune2fs -m 1 /dev/nvme0n1p1
Nun volume de base de datos de 1 terabyte (1.000 gigabytes), este comando único envía inmediatamente 40 gigabytes (42.900 millóns de bytes) de espazo de escritura ao motor de base de datos para que poida rematar o seu punto de control WAL. Unha vez resolta a crise e purgando os datos antigos, restablece a reserva 2% ou 5% (sudo tune2fs -m 2 /dev/nvme0n1p1).

Paso 3: trunque os rexistros de texto activos no lugar e pase o baleiro journald

Atopar os ficheiros máis grandes no sistema de ficheiros raíz (permanecer no mesmo sistema de ficheiros con -xdev para que non perdas o tempo escaneando /proc ou montaxes externas):

sudo find / -xdev -type f -size +100M -exec ls -lh {} + 2>/dev/null | sort -k 5 -hr | head -n 25
- Para ficheiros de rexistro de texto plano grandes (/var/log/nginx/access.log, /var/log/syslog, /var/log/postgresql/*.log, Docker *-json.log): Nunca corras rm nun ficheiro de rexistro activo. Trunqueo a cero bytes no seu lugar para que o descritor de ficheiros do daemon permaneza válido e os punteiros de compensación se reinicien limpamente:
sudo truncate -s 0 /var/log/nginx/error.log
sudo truncate -s 0 /var/lib/docker/containers/*/*-json.log
- Para systemd-journald rexistros binarios (/var/log/journal/):
sudo journalctl --vacuum-size=50M


Fase 3: Recuperación de PostgreSQL despois dunha falla de disco cheo ao 100 % (pg_wal inchar)

Cando un servidor PostgreSQL queda sen espazo no disco, rexistra PANIC: could not write to file "pg_wal/xlogtemp.1234": No space left on device, aborta inmediatamente os procesos fillos do administrador de correos e négase a iniciar.

Por que pg_wal (pg_xlog en PostgreSQL 9.6 e anteriores) enche todo o disco

En funcionamento normal, PostgreSQL escribe cada cambio en ficheiros de segmento de 16 megabytes (16,7 millóns de bytes) dentro $PGDATA/pg_wal/ e recíclaos despois de cada un CHECKPOINT unha vez que se supere max_wal_size. Non obstante, PostgreSQL ** está prohibido eliminar ou reciclar vellos pg_wal ficheiros** baixo tres condicións: 1. Unha ranura de replicación física/lóxica retrasada ou orfa: un servidor de réplica (standby), conector Debezium/Kafka ou pg_receivewal cliente desconectouse hai días, pero o seu slot de replicación (pg_replication_slots) aínda está active = false no principal, instruíndo a PostgreSQL para conservar cada segmento de WAL xerado desde a desconexión. 2. Un fracaso archive_command: archive_mode = on está habilitado en postgresql.conf, e o script de copia de seguridade (pgBackRest, WAL-G, Barman, ou aws s3 cp) está devolvendo un código de saída distinto de cero (por exemplo, unha clave S3 caducada ou un host de copia de seguranza inalcanzable). PostgreSQL mantén todos os segmentos WAL sen arquivar pg_wal/ ata que archive_command volve 0. 3. Un punto morto de disco cheo: pg_wal medrou ata 0 bytes permaneceu encendido /var/lib/postgresql, e agora PostgreSQL non pode nin sequera comezar a soltar o slot de replicación ou completar un punto de verificación porque a propia recuperación do inicio precisa de varios megabytes de espazo libre en disco para escribir ficheiros de estado temporais.

Rescate de espazo cero de PostgreSQL paso a paso (perda cero de datos)

  1. Cree de 1 gigabyte a 5 gigabytes (de 1,07 a 5,36 millóns de bytes) de espazo temporal fóra pg_wal/:
  2. Primeiro uso sudo tune2fs -m 0 /dev/<partition> e truncar os rexistros de texto do sistema/PostgreSQL (sudo truncate -s 0 /var/lib/postgresql/*/main/log/*.log ou /var/log/postgresql/*.log).
  3. ** E se a base de datos ten a súa propia partición dedicada con cero rexistros de texto e XFS (así tune2fs non está dispoñible)?** Move 10 a 20 dos máis antigos .ready ou ficheiros inactivos fóra dun directorio que non sexa WAL, ou reubicar o pg_wal directorio temporalmente a outra partición con espazo libre mediante unha ligazón simbólica:
    # ONLY while PostgreSQL is completely stopped (verify with: ps aux | grep postgres)
    sudo mkdir -p /mnt/extra_space/pg_wal_rescue
    sudo chown -R postgres:postgres /mnt/extra_space/pg_wal_rescue
    sudo mv /var/lib/postgresql/16/main/pg_wal/* /mnt/extra_space/pg_wal_rescue/
    sudo rmdir /var/lib/postgresql/16/main/pg_wal
    sudo ln -s /mnt/extra_space/pg_wal_rescue /var/lib/postgresql/16/main/pg_wal
    sudo chown -h postgres:postgres /var/lib/postgresql/16/main/pg_wal
    
  4. Se archive_command está fallando e bloqueando a reciclaxe de WAL, evítalo temporalmente postgresql.conf: Se o teu obxectivo S3/backup está caído e pg_wal/archive_status/ contén miles de .ready arquivos, editar postgresql.conf (archive_command = '/bin/true') só como medida de emerxencia de último recurso para evitar que o disco morra, sabendo que debes tomar un novo pg_basebackup inmediatamente despois da recuperación porque a cadea de arquivos WAL terá un oco.
  5. Inicie PostgreSQL e inspeccione inmediatamente os slots de replicación: Iniciar PostgreSQL (sudo systemctl start postgresql) e conéctese mediante sudo -u postgres psql:
    SELECT slot_name, plugin, slot_type, active,
           pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
    FROM pg_replication_slots;
    
  6. Solta calquera ranura de replicación morta/inactiva que acumule gigabytes de WAL: Se ves un slot inactivo (active = f) con 80 gigabytes de retained_wal:
    SELECT pg_drop_replication_slot('name_of_dead_slot');
    
  7. Forzar un inmediato CHECKPOINT para reciclar o inchado pg_wal segmentos:
    CHECKPOINT;
    
    O momento CHECKPOINT; remate despois de soltar o slot morto, PostgreSQL desligará ou reciclará automaticamente gigabytes de ficheiros antigos de segmentos de 16 megabytes en pg_wal/, devolvendo o uso do disco á normalidade.
  8. Evitar a morte do disco de slot de replicación futura: Definido max_slot_wal_keep_size en postgresql.conf (dispoñible en PostgreSQL 13+) a un límite seguro (como max_slot_wal_keep_size = 20GB) polo que PostgreSQL invalida a ranura dunha réplica morta en lugar de bloquear a base de datos primaria a 0 bytes libres.

Fase 4: Recuperación de MySQL / MariaDB (InnoDB) a 0 bytes libres

Cando MySQL ou MariaDB chegan 100% utilización do disco (/var/lib/mysql), InnoDB bloquea todas as escrituras ou falla [ERROR] [MY-012640] [InnoDB] Error number 28 means 'No space left on device'.

Identificando o que encheu /var/lib/mysql

Corre sudo du -sh /var/lib/mysql/* | sort -hr | head -n 15 para ver cal destes catro culpables consumiu o disco: 1. ** Rexistros binarios ilimitados (binlog.000001, mysql-bin.000042): Por defecto en MySQL 8.0+, o rexistro binario está habilitado cunha retención de 30 días (binlog_expire_logs_seconds = 2592000), que pode xerar facilmente centos de gigabytes de eventos de fila durante as importacións masivas. 2. Unha consulta desbocada escribindo táboas temporais xigantes (#sql* ou ibtmp1): Un enorme GROUP BY ou ORDER BY consulta cuberta ibtmp1 ou /tmp/#sql_* ata que o disco toque 0 bytes. 3. Monolítico ibdata1 sistema tablespace bloat: Se innodb_file_per_table foi desactivado ou as transaccións de longa duración impediron a lista de historial de InnoDB (desfacer rexistros dentro ibdata1 ou undo_001) de purga. 4. ** Rexistro de consultas lentas ou rexistro de erros de MySQL (/var/log/mysql/mysql-slow.log).

Rescate de espazo cero de MySQL/MariaDB paso a paso

  1. ** NUNCA borres ibdata1, ib_logfile0, ib_logfile1, #innodb_redo/*, ou undo_001 con rm**: Eliminar calquera destes ficheiros fai que todos .ibd ficheiro de táboa na súa base de datos non lexible.
  2. Espazo de inicio gratuíto (de 500 megabytes a 2 gigabytes):
  3. Truncar /var/log/mysql/error.log e mysql-slow.log vía sudo truncate -s 0 /var/log/mysql/*.log.
  4. Activado ext4, corre sudo tune2fs -m 1 /dev/<partition>.
  5. Se mysqld actualmente está detido e /var/lib/mysql/ibtmp1 (o espazo de táboa temporal non comprimido) é enorme, ibtmp1 recréase automaticamente ao iniciar, ou pode mover os **dos ou tres rexistros binarios máis antigos (binlog.000001, binlog.000002 - nunca o binlog activo con maior número) a /dev/shm temporalmente así mysqld pode arrincar.
  6. Iniciar MySQL e purgar os rexistros binarios de forma segura usando SQL (PURGE BINARY LOGS): Por que debes usar SQL en lugar de rm /var/lib/mysql/binlog.*? Porque MySQL rastrexa cada nome de ficheiro de rexistro binario binlog.index. Se eliminas rexistros binarios con rm sen actualizar binlog.index, MySQL rexeitará iniciarse ou a replicación romperase. Unha vez mysqld comeza, inicia sesión (sudo mysql) e executa:
    SHOW BINARY LOGS;
    PURGE BINARY LOGS BEFORE NOW() - INTERVAL 1 DAY;
    
    (Ou purga todo ata o ficheiro de rexistro activo actual que se mostra na parte inferior de SHOW BINARY LOGS; usando PURGE BINARY LOGS TO 'binlog.000085';)
  7. Establece un tamaño de rexistro binario permanente e un límite de retención /etc/mysql/mysql.conf.d/mysqld.cnf:
    [mysqld]
    binlog_expire_logs_seconds = 259200   # Keep only 3 days (259,200 seconds)
    max_binlog_size = 256M
    innodb_temp_data_file_path = ibtmp1:12M:autoextend:max:5G
    
    Tapón ibtmp1 ás max:5G garante que un pícaro non indexado JOIN ou ORDER BY a consulta falla con a table is full erro en lugar de expandir ibtmp1 ata que todo o servidor Linux morra con 0 bytes libres.

Fase 5: Recuperación dunha base de datos SQLite3 corrupta (database or disk is full / SQLITE_FULL / malformed)

Aplicacións integradas, contedores Docker (Nextcloud, Vaultwarden, Home Assistant, Plex, Grafana, Gitea), e os servizos móbiles/de escritorio dependen de SQLite3. Cando un disco alcanza 0 bytes libres mentres SQLite está no medio dunha reversión de diario ou un rexistro de escritura anticipada (-wal), atopará unha das dúas emerxencias: 1. Masivo .db-wal arquivo inchazo (o .db-wal o ficheiro pasou a 10 gigabytes mentres que o .db o ficheiro ten só 200 megabytes, porque os lectores de longa duración impediron un punto de control WAL pasivo e agora o disco está cheo ao 100 por cento). 2. RuntimeError: database disk image is malformed (SQLITE_CORRUPT) causado por un hardware averiado fsync(), un contenedor matou a metade da recuperación a 0 bytes libres ou alguén que eliminou o -wal ou -journal arquivo a man.

Warning

Nunca mover, renomear ou copiar un .db arquivo por si mesmo mentres deixa o seu .db-wal (Registro de escritura anticipada) ou .db-journal (Rollback Journal) arquivo detrás: Se app.db-wal ou app.db-journal existe ao lado app.db, ese ficheiro acompañante contén transaccións comprometidas e páxinas orixinais de árbore B que se deben realizar app.db estruturalmente consistente. Copia sempre os tres ficheiros (app.db, app.db-wal, app.db-shm) xuntos antes de executar calquera comando.

Paso 1: encoller un inchado .db-wal ficheiro e aspirar SQLite cando o espazo no disco está preto de cero

  1. Detén o contedor da aplicación ou o servizo que mantén aberta a base de datos SQLite (sudo systemctl stop app ou docker stop container_name).
  2. Copiar app.db, app.db-wal, e app.db-shm a unha partición ou unidade externa con moito espazo libre (ou libre 2 veces o tamaño de app.db primeiro no disco local).
  3. Abre a base de datos co sqlite3 CLI e forza un punto de verificación WAL truncado, que dobra todos os fotogramas comprometidos desde app.db-wal en app.db e encolle app.db-wal ata 0 bytes:
    sqlite3 /path/to/app.db "PRAGMA wal_checkpoint(TRUNCATE);"
    
  4. Verifique a integridade estrutural da árbore B e da lista libre:
    sqlite3 /path/to/app.db "PRAGMA integrity_check;"
    
    Se imprime ok, a súa base de datos é 100 por cento saudable.
  5. Como VACUUM unha enorme base de datos SQLite cando o disco local non ten espazo libre suficiente: Estándar VACUUM; require ata 2 veces o tamaño da base de datos en espazo libre no disco na mesma partición e /var/tmp. En cambio, usa VACUUM INTO (introducido en SQLite 3.27.0) para escribir unha copia recén compactada e desfragmentada directamente nun disco montado separado ou nun recurso compartido de rede:
    sqlite3 /path/to/app.db "VACUUM INTO '/mnt/external_usb/app_compacted.db';"
    

Paso 2: salvar unha árbore B danada (database disk image is malformed) con .recover

Se PRAGMA integrity_check; informes row 412 missing from index, btreeInitPage() returns error code 11, ou database disk image is malformed:

  1. Primeiro intente reconstruír índices secundarios rotos (REINDEX): Moitas veces os datos da táboa reais (table B-trees) está 100 por cento intacta e só se corrompiu unha árbore de índice secundario B cando o disco se encheu. Executar:
    sqlite3 /mnt/external_usb/copy_of_app.db "REINDEX;"
    sqlite3 /mnt/external_usb/copy_of_app.db "PRAGMA integrity_check;"
    
    Se PRAGMA integrity_check; agora volve ok, recuperaches o 100 por cento da túa base de datos sen filas perdidas.
  2. Se REINDEX falla, executa o escáner forense B-tree (.recover): A diferenza dos maiores .dump comando (que deixa de exportar unha táboa no momento en que chega a un punteiro da árbore B danado), .recover (integrado en sqlite3 versión 3.29.0+) evita por completo os punteiros da árbore B interior corrompidos, escanea cada páxina de folla de 4 kilobytes do ficheiro de forma secuencial desde o byte 0 ata o EOF, reconstrúe todas as filas lexibles e coloca os rexistros orfos nun ficheiro. lost_and_found táboa:
    sqlite3 /mnt/external_usb/copy_of_app.db ".recover" | sqlite3 /mnt/external_usb/repaired_app.db
    
  3. Verifique a base de datos recén reconstruída:
    sqlite3 /mnt/external_usb/repaired_app.db "PRAGMA integrity_check;"
    
    Comproba se a lost_and_found creouse a táboa (sqlite3 /mnt/external_usb/repaired_app.db ".tables") para inspeccionar as filas orfas recuperadas das páxinas de follas sen ligazón. Para bases de datos SQLCipher cifradas (como copias de seguridade de Signal ou WhatsApp), consulte a nosa guía dedicada en corrupción de copia de seguridade do chat cifrado de SQLite, Signal e WhatsApp e extracción de claves locais.

Fase 6: "Arquivo de lastre de tripwire" de emerxencia e lista de verificación de prevención de seguimento

Unha vez que o servidor e a base de datos estean en liña de novo, implemente estas catro garantías de inmediato para que nunca volva quedar atrapado en 0 bytes libres:

  • Crear un gigabyte (1,073,741,824 byte) Ficheiro de lastre de emerxencia en cada partición da base de datos: Executar sudo fallocate -l 1G /var/lib/EMERGENCY_DELETE_ME.ballast. Se algunha vez chega o servidor 100% disco cheo, en execución sudo rm /var/lib/EMERGENCY_DELETE_ME.ballast libera 1 gigabyte de bloques contiguos en 1 milisegundo.
  • Cap systemd-journald e rexistros do contedor Docker de forma permanente: Establecido SystemMaxUse=200M en /etc/systemd/journald.conf e configurar /etc/docker/daemon.json con "log-opts": {"max-size": "20m", "max-file": "3"}.
  • ** Illar /var/log, /tmp, e /var/lib/postgresql en volumes LVM separados**: Conservación /var/log e /tmp separado dos volumes da base de datos garante que un rexistro web descontrolado nunca faga falla a base de datos nin bloquee os inicios de sesión SSH.
  • Alerta en AMBOS df -h (> 80%) E df -i (> 80%) máis pg_replication_slots lag: configurar a monitorización (node_filesystem_avail_bytes e node_filesystem_files_free) para alertar antes de que a utilización supere o 85 por cento.

Números de emerxencia rexionais e protocolos da axencia

Aínda que un disco de servidor completo é normalmente unha emerxencia interna das operacións de TI, unha interrupción que afecta ao rexistro sanitario electrónico (EHR) bases de datos, envío de emerxencia (CAD), a telemetría municipal de auga/electricidade ou a dispoñibilidade legal de datos persoais poden requirir unha escalada formal de emerxencia:

  • Estados Unidos e Canadá: Marque 911 se un fallo do servidor desactiva o seguimento clínico ou o envío e activa os procedementos de tempo de inactividade. Informar de esgotamento de recursos de infraestrutura crítica ou ataques de ransomware a CISA (1-844-Say-CISA / cisa.gov/report) ou o Centro Canadiense de Seguridade Cibernética (1-833-CYBER-88).
  • Reino Unido: Marque 999 para ameazas para a vida ou sistemas críticos do NHS. Segundo os regulamentos do GDPR e NIS do Reino Unido, avalía se a perda permanente de dispoñibilidade da base de datos require unha notificación ao ICO (0303 123 1113) nun prazo de 72 horas.
  • Unión Europea: Marque 112 en todos os estados membros da UE. As entidades esenciais baixo a Directiva NIS2 deben notificar ao seu CSIRT nacional nun prazo de 24 horas despois dunha interrupción importante, e a perda permanente de datos persoais sen recuperación de copia de seguranza activa os informes do artigo 33 do GDPR nun prazo de 72 horas.
  • Australia e Nova Zelanda: Marque 000 en Australia ou 111 en Nova Zelanda; póñase en contacto co ACSC (1300 CYBER1) para incidencias de infraestruturas.
  • India e Asia-Pacífico: Marque 112 para resposta de emerxencia; informar cortes inducidos por cibernética a CERT-In (incident@cert-in.org.in) dentro da xanela obrigatoria de 6 horas.

Preguntas frecuentes

Por que fixo df -h permanecer ao 100% (0 Avail) mesmo despois de eliminar un ficheiro de rexistro de 50 GB con rm?

En sistemas de ficheiros Linux, rm só chamadas desvincular(), eliminando o nome do ficheiro do directorio mentres o núcleo mantén os bloques de disco asignados ata que cada proceso que mantén ese ficheiro aberto pecha o seu descritor de ficheiro (i_count == 0). Corre sudo lsof +L1 para atopar o ID do proceso (PID) e Descriptor de ficheiro (FD) do (eliminado) ficheiro e, a continuación, execute sudo sh -c ': > /proc/PID/fd/FD' para cero os bloques no lugar inmediatamente sen reiniciar o servizo.

E se non podo nin SSH no servidor porque /tmp ou /var/run está cheo ao 100% e sshd négase a asignar unha sesión?

Primeiro intente executar un comando directo non PTY sobre SSH sen asignar un pseudoterminal interactivo: ssh -T root@server "sh -c ': > /var/log/syslog'". Se raíz o inicio de sesión está desactivado, use a consola serie fóra de banda do seu provedor de nube (AWS EC2 Serial Console, DigitalOcean Console, Linode Lish ou Proxmox/VMware VNC) para iniciar sesión directamente en ttyS0 ou arrincar en modo de recuperación de usuario único.

Alguén xa eliminou ficheiros dentro de PostgreSQL pg_wal directorio antes de ler esta guía, e agora PostgreSQL négase a comezar PANIC: could not locate a valid checkpoint record. Perdéronse todos os datos?

Non, a maioría das filas da táboa aínda están dentro $PGDATA/base/, aínda que as transaccións durante o voo dentro dos ficheiros WAL eliminados pérdense e algunhas páxinas poden romperse. Primeiro fai unha copia completa do conxunto $PGDATA directorio (cp -a /var/lib/postgresql/16/main /mnt/backup/pgdata_raw). Despois corre sudo -u postgres /usr/lib/postgresql/16/bin/pg_resetwal -f /var/lib/postgresql/16/main, inicie PostgreSQL en modo de usuario único e execute inmediatamente pg_dumpall nun recén inicializado (initdb) cluster; nunca continúe executando o tráfico de produción nun clúster despois pg_resetwal.

Como borrar millóns de ficheiros pequenos cando rm -rf colga ou falla nun inodo esgotado (df -i 100%) servidor?

Cando un directorio contén millóns de pequenos ficheiros de sesión ou caché, o seu índice de directorio (htree) crece enorme, provocando ls e rm - rf para bloquear a clasificación de nomes de ficheiros na RAM. Pola contra, corre sudo find /path/to/million_files -mindepth 1 -eliminarou crear un directorio de RAM baleiro (mkdir /dev/shm/empty) e corre sudo rsync -a --delete /dev/shm/empty/ /path/to/million_files/ para desvincular os inodos rapidamente.

Por que Docker encheu todo o meu disco do servidor cando os meus contedores son pequenos e como limpo? /var/lib/docker con seguridade?

Docker acumula espazo en disco nos rexistros estándar JSON non rotados (/var/lib/docker/containers/*/*-json.log), colgando superposición 2 capas de imaxes e caché de kit de compilación. Nunca manualmente rm - rf carpetas dentro /var/lib/docker/overlay2/. Primeiro trunque os rexistros JSON (sudo truncate -s 0 /var/lib/docker/containers/*/*-json.log) para que o demo teña espazo para respirar, entón corre sistema sudo docker prune -a -f (omitindo --volumes polo que os volumes da base de datos permanecen intactos).

Podo expandir un volume de disco persistente/EBS na nube en directo mentres o servidor está a utilizar o 100 % do disco?

Si, a expansión de volume en liña funciona sen reiniciar, cunha única captura: o script auxiliar growpart /dev/nvme0n1 1 tenta crear un ficheiro temporal en /tmp usando mktemp e falla en 0 bytes libres. Evita ese fallo executando sudo TMPDIR=/dev/shm growpart /dev/nvme0n1 1 (usando a memoria RAM /dev/shm monte) seguido de sudo resize2fs /dev/nvme0n1p1 (ext4) ou sudo xfs_growfs / (XFS).


Guías relacionadas


Fontes e orientacións oficiais

  • Grupo de desenvolvemento global de PostgreSQL: Documentación oficial de PostgreSQL 16 - Capítulo 30: Fiabilidade e rexistro de escritura anticipada (Configuración de WAL, slots de replicación e recuperación de fallos completos do disco).
  • Consorcio SQLite (sqlite.org): Como corromper un ficheiro de base de datos SQLite (bloqueo de ficheiros, ficheiros diarios/WAL sen ligar e .recover Extensión CLI).
  • Documentación de Oracle Corporation / MySQL e MariaDB Foundation: Recuperación de fallos de InnoDB, Procedementos de purga de rexistros binarios (PURGE BINARY LOGS) e espazo de táboa temporal (ibtmp1) Xestión.
  • Organización do núcleo de Linux (kernel.org): Administración do sistema de ficheiros Ext4 (tune2fs Bloques reservados, táboas de inodos e /proc/<pid>/fd/ Truncamento do descritor de ficheiros).
  • Instituto Nacional de Estándares e Tecnoloxía (NIST) (Estados Unidos): Publicación especial 800-123: Guide to General Server Security and Availability Management.