Cómo eliminar millones de archivos sin molestar al servidor

11

Me gustaría eliminar un directorio de caché nginx, que rápidamente eliminé:

mv cache cache.bak
mkdir cache
service nginx restart

Ahora tengo una cache.bakcarpeta que tiene 2 millones de archivos. Me gustaría eliminarlo, sin molestar al servidor.

Una simple rm -rf cache.bakbasura del servidor, incluso la respuesta HTTP más simple tarda 16 segundos mientras se está ejecutando rm, por lo que no puedo hacer eso.

Lo intenté ionice -c3 rm -rf cache.bak, pero no ayudó. El servidor tiene un HDD, no un SSD, probablemente en un SSD, esto podría no ser un problema.

Creo que la mejor solución sería algún tipo de estrangulamiento, como lo hace el administrador de caché integrado de nginx.

Como resolverias esto? ¿Hay alguna herramienta que pueda hacer exactamente esto?

ext4 en Ubuntu 16.04

hipernudo
fuente
1
¿Cómo te recuperaste de "rm -rf cache.bak"? Parece que nginx se estaba ejecutando cuando cambió el nombre, por lo que podría haber mantenido los descriptores de archivo e incluso haber cambiado al nuevo directorio. Creo que necesita cerrar nginx por completo, eliminar el caché y luego reiniciar.
Jan Steinman
66
En el futuro, pegue su caché en un sistema de archivos separado. De esa manera, simplemente puede destruir ese sistema de archivos, que es mucho más rápido que tratar de eliminar millones de archivos. Aprendí esto de la manera difícil hace unos años con un directorio de cola de hylafax que contiene millones de archivos.
Dennis Kaarsemaker
¿Has intentado correr rmusando nice ?
Vladislav Rastrusny
Intente rsync para eliminar rápidamente - respuestas a un caso similar - unix.stackexchange.com/questions/37329/…
kawu
Gracias por todos los comentarios, he resumido mis hallazgos para escribir una respuesta.
hyperknot

Respuestas:

9

Haz un script bash como este:

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

Guárdelo con nombre, deleter.shpor ejemplo. Ejecutar chmod u+x deleter.shpara hacerlo ejecutable.

Este script elimina todos los archivos que se le pasan como argumentos y luego duerme 0,5 segundos.

Entonces, puedes correr

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

Este comando recupera una lista de todos los archivos en cache.bak y pasa los cinco nombres de archivo a la vez al script de eliminación.

Por lo tanto, puede ajustar cuántos archivos se eliminan a la vez y cuánto tiempo transcurre entre cada operación de eliminación.

Tero Kilkanen
fuente
Gracias por esta solución, la he incluido en mi informe general. Sin embargo, una pregunta es: ¿cómo se manejan los ns grandes? Por lo general, tuve problemas con el carácter * en los directorios grandes que daban errores, ¿no es el caso aquí?
hyperknot
xargsentiende el tamaño máximo de una línea de comando e intenta no excederlo por defecto. Este tiene límites adicionales de no más de 5 rutas a la vez.
BowlOfRed
1
Solo tenga en cuenta que a una velocidad de 10 archivos por segundo, tomará 55 horas eliminar 2 millones de archivos.
Andrew Henle
4

Debería considerar guardar su caché en un sistema de archivos separado que puede montar / desmontar como alguien dijo en los comentarios. Hasta que lo haga, puede usar este delineador /usr/bin/find /path/to/files/ -type f -print0 -exec sleep 0.2 \; -exec echo \; -deleteasumiendo que su binario de búsqueda se encuentra debajo de / usr / bin y desea ver el progreso en la pantalla. Ajuste el sueño en consecuencia, para no estresar demasiado su HDD.

Alex
fuente
No se necesita -print0aquí, ya que no está canalizando la salida de findningún lado.
Tero Kilkanen
Quizás te interese lo que está sucediendo. Llámalo paranoia, pero siempre quiero estar seguro de que estoy borrando los archivos correctos.
Alex
Ah cierto, no estaba decodificando el comando correctamente, mi mal.
Tero Kilkanen
3

Es posible que desee probar ionice en un script que consume la salida de un comando de búsqueda. Algo como lo siguiente:

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
)

Dependiendo del sistema de archivos, cada eliminación de archivos puede resultar en reescribir todo ese directorio. Para directorios grandes que pueden ser todo un éxito. Se requieren actualizaciones adicionales para la tabla de inodo, y posiblemente una lista de espacio libre.

Si el sistema de archivos tiene un diario, los cambios se escriben en el diario; aplicado; y eliminado del diario. Esto aumenta los requisitos de E / S para la actividad intensiva de escritura.

Es posible que desee utilizar un sistema de archivos sin un diario para el caché.

En lugar de ionizar, puede usar un comando de suspensión para limitar la velocidad de las acciones. Esto funcionará incluso si ionice no funciona, pero llevará mucho tiempo eliminar todos sus archivos.

BillThor
fuente
2

Obtuve muchas respuestas / comentarios útiles aquí, que me gustaría concluir y mostrar mi solución también.

  1. Sí, la mejor manera de evitar que tal cosa suceda es mantener el directorio de caché en un sistema de archivos separado. Nuking / formateo rápido de un sistema de archivos siempre toma unos segundos (tal vez minutos) como máximo, sin relación con la cantidad de archivos / directorios que estaban presentes en él.

  2. Las soluciones ionice/ niceno hicieron nada, porque el proceso de eliminación en realidad no causó casi ninguna E / S. Lo que causó la E / S fue que creo que las colas / memorias intermedias a nivel del núcleo / sistema de archivos se llenaron cuando el proceso de eliminación eliminó los archivos demasiado rápido.

  3. La forma en que lo resolví es similar a la solución de Tero Kilkanen, pero no requirió llamar a un script de shell. Usé el --bwlimitinterruptor incorporado de rsync para limitar la velocidad de eliminación.

El comando completo fue:

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

Ahora bwlimit especifica el ancho de banda en kilobytes, que en este caso se aplica al nombre de archivo o la ruta de los archivos. Al configurarlo a 1 KBps, estaba eliminando alrededor de 100,000 archivos por hora, o 27 archivos por segundo. Los archivos tenían rutas relativas como cache.bak/e/c1/db98339573acc5c76bdac4a601f9ec1e, que tiene 47 caracteres de longitud, por lo que daría 1000/47 ~ = 21 archivos por segundo, de manera similar a mi suposición de 100,000 archivos por hora.

Ahora ¿por qué --bwlimit=1? Probé varios valores:

  • 10000, 1000, 100 -> el sistema se desacelera como antes
  • 10 -> el sistema funciona bastante bien durante un tiempo, pero produce ralentizaciones parciales una vez por minuto más o menos. Los tiempos de respuesta HTTP siguen siendo <1 seg.
  • 1 -> sin desaceleración del sistema en absoluto. No tengo prisa y de esta manera se pueden eliminar 2 millones de archivos en <1 día, así que lo elijo.

Me gusta la simplicidad del método integrado de rsync, pero esta solución depende de la longitud de la ruta relativa. No es un gran problema ya que la mayoría de las personas encontrarían el valor correcto a través de prueba y error.

hipernudo
fuente
Y ahora tengo curiosidad sobre cuál sería el efecto del disco si hicieras algo como "mv cache.dir-old / dev / null"
ivanivan