linux: evita que la escritura de archivos grandes congele el sistema

Entonces, en mi escritorio de Linux, estoy escribiendo un archivo grande en un disco local o en un soporte NFS.

Hay algún tipo de búfer del sistema en el que los datos que se escribirán se almacenan en caché. (Creo que hay algo en el rango de 0.5-2GB en mi sistema).

Si el búfer está lleno, todos los archivos de acceso se bloquean, congelando efectivamente el sistema hasta que finalice la escritura. (Estoy bastante seguro de que incluso el acceso de lectura está bloqueado).

¿Qué necesito configurar para asegurarme de que eso nunca suceda?

Lo que quiero es:

Si un proceso no puede escribir datos en el disco (o montaje en red, etc.) lo suficientemente rápido, ese proceso puede bloquearse hasta que el disco se ponga al día, pero otros procesos aún pueden leer / escribir datos a una velocidad y latencia razonables sin ninguna interrupción.

Idealmente, podría establecer cuánto de la velocidad de lectura / escritura total del dsik está disponible para un cierto tipo de programa (cp, git, mplayer, firefox, etc.), como “todos los procesos de mplayer juntos obtienen al menos 10 MB / s, no importa lo que haga el resto del sistema “. Pero “todas las instancias de mplayer juntas obtienen al menos el 50% de la tasa total, no importa qué” también está bien. (es decir, no me importa mucho si puedo establecer tasas absolutas o proporciones de la tasa total).

Más importante (porque las lecturas / escrituras más importantes son pequeñas), quiero una configuración similar para la latencia. Una vez más, tendría una garantía de que la lectura / escritura de un solo proceso no puede bloquear el resto del sistema durante más de 10 ms (o lo que sea), pase lo que pase. Idealmente, tendría una garantía como “mplayer nunca tiene que esperar más de 10 ms para que se maneje una lectura / escritura, sin importar lo que esté haciendo el sistema”.

Esto debe funcionar sin importar cómo comenzó el proceso ofensivo (incluido el usuario con el que se está ejecutando, etc.), por lo que “envolver un gran cp en ionice” o lo que sea que apenas sea útil. Solo evitaría que algunas tareas congelen previsiblemente todo si recuerdo ionizarlas, pero ¿qué pasa con un trabajo cron, una llamada ejecutiva de algún demonio en ejecución, etc.?

(Supongo que podría envolver a los peores delincuentes con un script de shell que siempre los ioniza, pero incluso así, al mirar la página de manual de ionice, parece ser un tanto vago sobre las garantías exactas que me da, por lo que preferiría un sistema más sistemático y alternativa mantenible.)

Mejor respuesta
Normalmente, Linux usa un caché para escribir asincrónicamente los datos en el disco. Sin embargo, puede suceder que el lapso de tiempo entre la solicitud de escritura y la escritura real o la cantidad de datos no escritos (sucios) sea muy grande. En esta situación, un bloqueo provocaría una gran pérdida de datos y, por esta razón, Linux cambia a escrituras sincrónicas si el caché sucio se vuelve demasiado grande o viejo. Como también se debe respetar el orden de escritura, no se puede pasar por alto un pequeño IO sin garantizar que el pequeño IO es completamente independiente de todas las escrituras en cola anteriores. Por lo tanto, las escrituras dependientes pueden causar un gran retraso. (Este tipo de dependencias también puede ser causado en el nivel del sistema de archivos: ver https://ext4.wiki.kernel.org/index.php/Ext3_Data%3DOrdered_vs_Data%3DWriteback_mode).

Supongo que está experimentando algún tipo de hinchazón del búfer en combinación con escrituras dependientes. Si escribe un archivo grande y tiene una memoria caché de disco grande, termina en situaciones en las que se debe escribir una gran cantidad de datos antes de poder realizar una escritura sincrónica. Hay un buen artículo sobre LWN, que describe el problema: https://lwn.net/Articles/682582/

Todavía se está trabajando en los planificadores y la situación puede mejorar con las nuevas versiones del kernel. Sin embargo, hasta entonces:
Hay algunos modificadores que pueden influir en el comportamiento de almacenamiento en caché en Linux (hay más, ver: https://www.kernel.org/doc/Documentation/sysctl/vm.txt):

> dirty_ratio: contiene, como porcentaje de la memoria total disponible que contiene páginas libres y páginas recuperables, el número de páginas en las que un proceso que genera escrituras en disco comenzará a escribir datos sucios. La memoria total disponible no es igual a la memoria total del sistema.
> dirty_background_ratio: contiene, como porcentaje de la memoria total disponible que contiene páginas libres y páginas recuperables, el número de páginas en las que los subprocesos del enjuague del núcleo de fondo comenzarán a escribir datos sucios.
> dirty_writeback_centisecs: los subprocesos del enjuague del núcleo se activarán periódicamente y escribirán los datos ‘antiguos’ en el disco. Este sintonizable expresa el intervalo entre esos despertares, en centésimas de segundo. Establecer esto en cero desactiva la reescritura periódica por completo.
> dirty_expire_centisecs: este sintonizador se utiliza para definir cuándo los datos sucios son lo suficientemente antiguos como para ser elegibles para ser escritos por los subprocesos de descarga del kernel. Se expresa en centésimas de segundo. Los datos que han estado sucios en la memoria durante más tiempo que este intervalo se escribirán la próxima vez que se active un hilo de descarga.

La solución más fácil para reducir la latencia máxima en tales situaciones es reducir la cantidad máxima de caché de disco sucio y hacer que el trabajo en segundo plano realice las primeras escrituras. Por supuesto, esto puede provocar una degradación del rendimiento en situaciones en las que una memoria caché de otro modo grande impediría las escrituras síncronas. Por ejemplo, puede configurar lo siguiente en /etc/sysctl.conf:

vm.dirty_background_ratio = 1
vm.dirty_ratio = 5

Tenga en cuenta que los valores adecuados para su sistema dependen de la cantidad de RAM disponible y la velocidad del disco. En condiciones extremas, la ración sucia anterior podría ser demasiado grande. Por ejemplo, si tiene 100GiB de RAM disponible y su disco escribe a una velocidad de aproximadamente 100MiB, la configuración anterior daría como resultado una cantidad máxima de caché sucia de 5GiB y eso puede tomar alrededor de 50 segundos para escribir. Con dirty_bytes y dirty_background_bytes también puede establecer los valores para el caché de manera absoluta.

Otra cosa que puede probar es cambiar el planificador io. En las versiones actuales del kernel, hay noop, deadline y cfq. Si está utilizando un núcleo antiguo, puede experimentar un mejor tiempo de reacción con el planificador de fecha límite en comparación con cfq. Sin embargo, tienes que probarlo. Noop debe evitarse en su situación. También existe el planificador BFQ no principal que afirma reducir la latencia en comparación con CFQ (http://algo.ing.unimo.it/people/paolo/disk_sched/). Sin embargo, no está incluido en todas las distribuciones. Puede verificar y cambiar el planificador en tiempo de ejecución con:

cat /sys/block/sdX/queue/scheduler 
echo <SCHEDULER_NAME> > /sys/block/sdX/queue/scheduler

El primer comando también le dará un resumen de los programadores disponibles y sus nombres exactos. Nota: la configuración se pierde después del reinicio. Para elegir el planificador de forma permanente, puede agregar un parámetro de kernel:

elevator=<SCHEDULER_NAME>

La situación para NFS es similar, pero incluye otros problemas. Los siguientes dos informes de errores pueden brindar información sobre el manejo de estadísticas en NFS y por qué una escritura de archivos grandes puede hacer que las estadísticas sean muy lentas:

https://bugzilla.redhat.com/show_bug.cgi?id=688232
https://bugzilla.redhat.com/show_bug.cgi?id=469848

Actualización: (14.08.2017)
Con el kernel 4.10, se han introducido las nuevas opciones de kernel CONFIG_BLK_WBT y sus subopciones BLK_WBT_SQ y CONFIG_BLK_WBT_MQ. Están evitando la acumulación de búferes causada por los búferes de hardware, cuyo tamaño y priorización no pueden ser controlados por el núcleo:

Enabling this option enables the block layer to throttle buffered
background writeback from the VM, making it more smooth and having
less impact on foreground operations. The throttling is done
dynamically on an algorithm loosely based on CoDel, factoring in
the realtime performance of the disk

Además, BFQ-Scheduler está integrado en el núcleo 4.12.

Por favor indique la dirección original:linux: evita que la escritura de archivos grandes congele el sistema - Código de registro