Come eliminare milioni di file senza disturbare il server


11

Vorrei eliminare una directory della cache nginx, che ho eliminato rapidamente da:

mv cache cache.bak
mkdir cache
service nginx restart

Ora ho una cache.bakcartella che contiene 2 milioni di file. Vorrei eliminarlo, senza disturbare il server.

Un semplice rm -rf cache.bakelimina il server, anche la risposta HTTP più semplice richiede 16 secondi mentre rm è in esecuzione, quindi non posso farlo.

Ci ho provato ionice -c3 rm -rf cache.bak, ma non ha aiutato. Il server ha un HDD, non un SSD, probabilmente su un SSD questi potrebbero non essere un problema.

Credo che la soluzione migliore sarebbe una sorta di limitazione, come fa il gestore cache incorporato di nginx.

Come lo risolveresti? C'è qualche strumento che può fare esattamente questo?

ext4 su Ubuntu 16.04


1
Come hai recuperato da "rm -rf cache.bak"? Sembra che nginx fosse in esecuzione quando hai fatto la ridenominazione, quindi potrebbe aver mantenuto i descrittori di file e persino passato alla nuova directory. Penso che sia necessario chiudere completamente nginx, eliminare la cache, quindi riavviare.
Jan Steinman,

6
In futuro, attacca la cache su un filesystem separato. In questo modo puoi semplicemente annotare quel file system, che è molto più veloce del tentativo di eliminare milioni di file. L'ho imparato nel modo più duro alcuni anni fa con una directory di spool hylafax contenente miliardi di file.
Dennis Kaarsemaker,

Hai provato a correre rmusando Nice ?
Vladislav Rastrusny il

Prova rsync per eliminare rapidamente - risposte a un caso simile - unix.stackexchange.com/questions/37329/…
kawu

Grazie per tutti i commenti, ho riassunto i miei risultati per scrivere la risposta.
hyperknot il

Risposte:


9

Crea uno script bash come questo:

#!/bin/bash
rm -- "$*"
sleep 0.5

Salvalo con il nome deleter.shper esempio. Esegui chmod u+x deleter.shper renderlo eseguibile.

Questo script elimina tutti i file che gli sono stati passati come argomenti e quindi viene messo in pausa 0,5 secondi.

Quindi, puoi correre

find cache.bak -print0 | xargs -0 -n 5 deleter.sh

Questo comando recupera un elenco di tutti i file in cache.bak e passa i cinque nomi di file alla volta allo script di eliminazione.

Pertanto, è possibile regolare il numero di file eliminati alla volta e il tempo che intercorre tra ciascuna operazione di eliminazione.


Grazie per questa soluzione, l'ho incluso nel mio commento generale. Una domanda però, come sta gestendo ns grandi? Di solito ho avuto problemi con il carattere * in grandi directory che davano errori, non è il caso qui?
hyperknot,

xargscomprende la dimensione massima di una riga di comando e cerca di non superarla per impostazione predefinita. Questo ha limiti aggiuntivi di non più di 5 percorsi alla volta.
BowlOfRed

1
Basta essere consapevoli del fatto che alla velocità di 10 file al secondo, occorreranno 55 ore per eliminare 2 milioni di file.
Andrew Henle,

4

Dovresti considerare di salvare la cache su un filesystem separato che puoi montare / smontare come qualcuno ha affermato nei commenti. Fino a quando non lo fai, puoi usare questo liner /usr/bin/find /path/to/files/ -type f -print0 -exec sleep 0.2 \; -exec echo \; -deleteassumendo che il tuo binario di ricerca si trovi sotto / usr / bin e desideri vedere i progressi sullo schermo. Regola il sonno di conseguenza, in modo da non stressare eccessivamente l'HDD.


Non è necessario -print0qui, poiché non si sta eseguendo il piping dell'output da findnessuna parte.
Tero Kilkanen,

Potresti essere interessato a ciò che è rm-ing. Chiamalo paranoia, ma voglio sempre essere sicuro di eliminare i file giusti.
Alex,

Ah vero, non stavo decodificando correttamente il comando, mia cattiva.
Tero Kilkanen,

3

Puoi provare ionice su uno script che utilizza l'output di un comando find. Qualcosa di simile al seguente:

ionice -c3 $(
for file in find cache.bak -type f; do
    rm $file
done
for dir in find cache.bak -depthe -type d -empty; do
    rmdir $dir
done
)

A seconda del filesystem, ogni cancellazione di file può comportare la riscrittura dell'intera directory. Per le grandi directory che possono essere un successo. Sono necessari ulteriori aggiornamenti per la tabella degli inode e, possibilmente, un elenco di spazi liberi.

Se il file system ha un journal, le modifiche vengono scritte nel journal; applicato; e rimosso dal diario. Ciò aumenta i requisiti I / O per l'attività intensiva di scrittura.

Potresti voler usare un filesystem senza un journal per la cache.

Invece di ionice, puoi usare un comando sleep per limitare le azioni. Funzionerà anche se ionice no, ma ci vorrà molto tempo per eliminare tutti i tuoi file.


2

Ho ricevuto molte risposte / commenti utili qui, che vorrei concludere e mostrare anche la mia soluzione.

  1. Sì, il modo migliore per evitare che ciò accada è mantenere la directory cache su un filesystem separato. Il cloud / formattazione rapida di un file system richiede sempre pochi secondi (forse minuti), non correlato al numero di file / directory presenti su di esso.

  2. Le soluzioni ionice/ nicenon hanno fatto nulla, perché il processo di eliminazione in realtà non ha causato quasi nessun I / O. Ciò che ha causato l'I / O è stato credo che code / buffer a livello di kernel / filesystem si riempissero quando i file venivano eliminati troppo rapidamente dal processo di eliminazione.

  3. Il modo in cui l'ho risolto è simile alla soluzione di Tero Kilkanen, ma non è stato necessario chiamare uno script di shell. Ho usato lo --bwlimitswitch integrato di rsync per limitare la velocità di eliminazione.

Il comando completo era:

mkdir empty_dir
rsync -v -a --delete --bwlimit=1 empty_dir/ cache.bak/

Ora bwlimit specifica la larghezza di banda in kilobyes, che in questo caso si applicava al nome file o al percorso dei file. Impostandolo su 1 KBps, stava eliminando circa 100.000 file all'ora o 27 file al secondo. I file avevano percorsi relativi come cache.bak/e/c1/db98339573acc5c76bdac4a601f9ec1e, che sono lunghi 47 caratteri, quindi darebbero 1000/47 ~ = 21 file al secondo, quindi un po 'simile alla mia ipotesi di 100.000 file all'ora.

Adesso perchè --bwlimit=1? Ho provato vari valori:

  • 10000, 1000, 100 -> rallentamento del sistema come prima
  • 10 -> il sistema funziona abbastanza bene per un po ', ma produce rallentamenti parziali una volta al minuto. I tempi di risposta HTTP sono ancora <1 sec.
  • 1 -> nessun rallentamento del sistema. Non ho fretta e 2 milioni di file possono essere eliminati in <1 giorno in questo modo, quindi lo scelgo.

Mi piace la semplicità del metodo integrato di rsync, ma questa soluzione dipende dalla lunghezza del percorso relativo. Non è un grosso problema in quanto la maggior parte delle persone troverebbe il giusto valore tramite tentativi ed errori.


E ora sono curioso di sapere quale sarebbe l'effetto del disco se facessi qualcosa del tipo "mv cache.dir-old / dev / null"
ivanivan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.