No me preocupa el uso de RAM (ya que tengo suficiente) ni la pérdida de datos en caso de un apagado accidental (ya que mi energía está respaldada, el sistema es confiable y los datos no son críticos). Pero hago mucho procesamiento de archivos y podría mejorar el rendimiento.
Es por eso que me gustaría configurar el sistema para usar más RAM para el almacenamiento en caché de lectura y escritura del sistema de archivos, para obtener archivos de forma agresiva (por ejemplo, leer con anticipación todo el archivo al que accede una aplicación en caso de que el archivo sea del mismo tamaño o al menos de lo contrario, leer una gran parte) y vaciar los búferes de escritura con menos frecuencia. ¿Cómo lograr esto (que sea posible)?
Uso sistemas de archivos ext3 y ntfs (¡uso mucho ntfs!) con XUbuntu 11.10 x86.
Respuesta aceptada:
Mejorar el rendimiento de la memoria caché del disco en general es más que simplemente aumentar el tamaño de la memoria caché del sistema de archivos, a menos que su totalidad el sistema cabe en la RAM, en cuyo caso debe usar la unidad RAM (tmpfs
es bueno porque permite volver al disco si necesita la RAM en algún caso) para el almacenamiento en tiempo de ejecución (y tal vez un script initrd para copiar el sistema del almacenamiento a la unidad RAM al inicio).
No dijiste si tu dispositivo de almacenamiento es SSD o HDD. Esto es lo que he encontrado que funciona para mí (en mi caso, sda
es un HDD montado en /home
y sdb
está montado SSD en /
).
Primero optimice la parte de carga del almacenamiento a la caché:
Aquí está mi configuración para HDD (asegúrese de que AHCI+NCQ esté habilitado en BIOS si tiene alternadores):
echo cfq > /sys/block/sda/queue/scheduler
echo 10000 > /sys/block/sda/queue/iosched/fifo_expire_async
echo 250 > /sys/block/sda/queue/iosched/fifo_expire_sync
echo 80 > /sys/block/sda/queue/iosched/slice_async
echo 1 > /sys/block/sda/queue/iosched/low_latency
echo 6 > /sys/block/sda/queue/iosched/quantum
echo 5 > /sys/block/sda/queue/iosched/slice_async_rq
echo 3 > /sys/block/sda/queue/iosched/slice_idle
echo 100 > /sys/block/sda/queue/iosched/slice_sync
hdparm -q -M 254 /dev/sda
Vale la pena señalar que el caso de HDD es alto fifo_expire_async
(generalmente escribir) y largo slice_sync
para permitir que un solo proceso obtenga un alto rendimiento (establezca slice_sync
a un número más bajo si se encuentra con situaciones en las que múltiples procesos están esperando algunos datos del disco en paralelo). El slice_idle
siempre es un compromiso para los discos duros, pero configurarlo en algún lugar en el rango 3-20 debería estar bien dependiendo del uso del disco y el firmware del disco. Prefiero apuntar a valores bajos, pero configurarlo demasiado bajo destruirá su rendimiento. El quantum
La configuración parece afectar mucho el rendimiento, pero trate de mantenerlo lo más bajo posible para mantener la latencia en un nivel razonable. Configuración de quantum
demasiado bajo destruirá el rendimiento. Los valores en el rango 3-8 parecen funcionar bien con HDD. La latencia en el peor de los casos para una lectura es (quantum
* slice_sync
) + (slice_async_rq
* slice_async
) ms si entendí correctamente el comportamiento del kernel. El async se usa principalmente para escrituras y, dado que está dispuesto a retrasar la escritura en el disco, configure ambos slice_async_rq
y slice_async
a números muy bajos. Sin embargo, configurar slice_async_rq
un valor demasiado bajo puede detener las lecturas porque las escrituras ya no se pueden retrasar después de las lecturas. Mi configuración intentará escribir datos en el disco como máximo después de 10 segundos después de que los datos se hayan pasado al kernel, pero dado que puede tolerar la pérdida de datos en caso de pérdida de energía, también configure fifo_expire_async
a 3600000
decir que 1 hora está bien para el retraso en el disco. Solo mantén el slice_async
bajo, sin embargo, porque de lo contrario puede obtener una latencia de lectura alta.
El hdparm
Se requiere un comando para evitar que AAM elimine gran parte del rendimiento que permite AHCI+NCQ. Si su disco hace demasiado ruido, omita esto.
Esta es mi configuración para SSD (serie Intel 320):
echo cfq > /sys/block/sdb/queue/scheduler
echo 1 > /sys/block/sdb/queue/iosched/back_seek_penalty
echo 10000 > /sys/block/sdb/queue/iosched/fifo_expire_async
echo 20 > /sys/block/sdb/queue/iosched/fifo_expire_sync
echo 1 > /sys/block/sdb/queue/iosched/low_latency
echo 6 > /sys/block/sdb/queue/iosched/quantum
echo 2 > /sys/block/sdb/queue/iosched/slice_async
echo 10 > /sys/block/sdb/queue/iosched/slice_async_rq
echo 1 > /sys/block/sdb/queue/iosched/slice_idle
echo 20 > /sys/block/sdb/queue/iosched/slice_sync
Aquí vale la pena señalar los valores bajos para diferentes configuraciones de corte. La configuración más importante para un SSD es slice_idle
que debe establecerse en 0-1. Establecerlo en cero mueve todas las decisiones de pedido al NCQ nativo, mientras que establecerlo en 1 permite que el kernel ordene las solicitudes (pero si el NCQ está activo, el hardware puede anular parcialmente el pedido del kernel). Pruebe ambos valores para ver si puede ver la diferencia. Para la serie Intel 320, parece que configurar slide_idle
a da el mejor rendimiento pero configurándolo en
1
ofrece la mejor (la más baja) latencia general.
Para obtener más información sobre estos parámetros ajustables, consulte https://www.kernel.org/doc/Documentation/block/cfq-iosched.txt.
Actualización en el año 2020 y versión de kernel 5.3 (cfq está muerto):
modprobe bfq
for d in /sys/block/sd?
do
# HDD (tuned for Seagate SMR drive)
echo bfq > "$d/queue/scheduler"
echo 4 > "$d/queue/nr_requests"
echo 32000 > "$d/queue/iosched/back_seek_max"
echo 3 > "$d/queue/iosched/back_seek_penalty"
echo 80 > "$d/queue/iosched/fifo_expire_sync"
echo 1000 > "$d/queue/iosched/fifo_expire_async"
echo 5300 > "$d/queue/iosched/slice_idle_us"
echo 1 > "$d/queue/iosched/low_latency"
echo 200 > "$d/queue/iosched/timeout_sync"
echo 0 > "$d/queue/iosched/max_budget"
echo 1 > "$d/queue/iosched/strict_guarantees"
# additional tweaks for SSD (tuned for Samsung EVO 850):
if test $(cat "$d/queue/rotational") = "0"
then
echo 36 > "$d/queue/nr_requests"
echo 1 > "$d/queue/iosched/back_seek_penalty"
# slice_idle_us should be ~ 0.7/IOPS in µs
echo 16 > "$d/queue/iosched/slice_idle_us"
echo 10 > "$d/queue/iosched/fifo_expire_sync"
echo 250 > "$d/queue/iosched/fifo_expire_async"
echo 10 > "$d/queue/iosched/timeout_sync"
echo 0 > "$d/queue/iosched/strict_guarantees"
fi
done
La configuración es bastante similar pero ahora uso bfq
en lugar de cfq
porque este último no está disponible con los núcleos modernos. Trato de mantener nr_requests
lo más bajo posible para permitir bfq
para controlar la programación con mayor precisión. Al menos, las unidades SSD de Samsung parecen requerir una cola bastante profunda para poder ejecutarse con un alto IOPS.
Estoy usando Ubuntu 18.04 con el paquete kernel linux-lowlatency-hwe-18.04-edge
que tiene bfq
solo como módulo, así que necesito cargarlo antes de poder cambiarlo.
También hoy en día también uso zram
pero solo uso el 5% de RAM para zram. Esto permite que el kernel de Linux use la lógica relacionada con el intercambio sin tocar los discos. Sin embargo, si decide optar por un intercambio de disco cero, asegúrese de que sus aplicaciones no pierdan RAM o estará desperdiciando dinero.
Ahora que hemos configurado el kernel para cargar cosas del disco a la memoria caché con un rendimiento razonable, es hora de ajustar el comportamiento de la memoria caché:
De acuerdo con los puntos de referencia que he hecho, no me molestaría en configurar la lectura anticipada a través de blockdev
en absoluto. La configuración predeterminada del kernel está bien.
Configure el sistema para que prefiera intercambiar datos de archivos sobre el código de la aplicación (esto no importa si tiene suficiente RAM para mantener completo sistema de archivos y todo el código de la aplicación y toda la memoria virtual asignada por las aplicaciones en RAM). Esto reduce la latencia para cambiar entre diferentes aplicaciones frente a la latencia para acceder a archivos grandes desde una sola aplicación:
echo 15 > /proc/sys/vm/swappiness
Si prefiere mantener las aplicaciones casi siempre en la RAM, puede configurarlo en 1. Si lo configura en cero, el kernel no se intercambiará en absoluto a menos que sea absolutamente necesario para evitar OOM. Si tuviera limitaciones de memoria y trabajara con archivos grandes (por ejemplo, edición de video HD), entonces podría tener sentido configurar esto cerca de 100.
Hoy en día (2017) prefiero no tener ningún intercambio si tienes suficiente RAM. Al no tener intercambio, generalmente se perderán 200-1000 MB de RAM en una máquina de escritorio de larga duración. Estoy dispuesto a sacrificar tanto para evitar la latencia en el peor de los casos (cambiar el código de la aplicación cuando la memoria RAM está llena). En la práctica, esto significa que prefiero OOM Killer al intercambio. Si permite/necesita el intercambio, es posible que desee aumentar /proc/sys/vm/watermark_scale_factor
, también, para evitar cierta latencia. Sugeriría valores entre 100 y 500. Puede considerar esta configuración como intercambiar el uso de la CPU por una menor latencia de intercambio. El valor predeterminado es 10 y el máximo posible es 1000. Un valor más alto debería (de acuerdo con la documentación del kernel) dar como resultado un mayor uso de la CPU para kswapd
procesos y menor latencia de intercambio general.
A continuación, dígale al núcleo que prefiera mantener la jerarquía de directorios en la memoria sobre el contenido de los archivos en caso de que sea necesario liberar algo de RAM (nuevamente, si todo cabe en la RAM, esta configuración no hace nada):
echo 10 > /proc/sys/vm/vfs_cache_pressure
Configuración de vfs_cache_pressure
a un valor bajo tiene sentido porque en la mayoría de los casos, el kernel necesita conocer la estructura del directorio antes de que pueda usar el contenido del archivo del caché y vaciar el caché del directorio demasiado pronto hará que el caché del archivo sea casi inútil. Considere bajar hasta 1 con esta configuración si tiene muchos archivos pequeños (mi sistema tiene alrededor de 150 000 fotos de 10 megapíxeles y cuenta como un sistema de "muchos archivos pequeños"). Nunca lo establezca en cero o la estructura del directorio siempre se mantiene en la memoria, incluso si el sistema se está quedando sin memoria. Establecer esto en un valor grande es sensato solo si tiene solo unos pocos archivos grandes que se vuelven a leer constantemente (nuevamente, la edición de video HD sin suficiente RAM sería un caso de ejemplo). La documentación oficial del kernel dice que "aumentar la presión de vfs_cache_pression significativamente más allá de 100 puede tener un impacto negativo en el rendimiento".
Excepción: si tiene una cantidad realmente enorme de archivos y directorios y rara vez toca/lee/lista todos los archivos configurando vfs_cache_pressure
superior a 100 puede ser inteligente. Esto solo se aplica si no tiene suficiente RAM y no puede mantener toda la estructura de directorios en RAM y todavía tiene suficiente RAM para el caché y los procesos de archivos normales (por ejemplo, un servidor de archivos de toda la empresa con mucho contenido de archivo). Si cree que necesita aumentar vfs_cache_pressure
por encima de 100 estás corriendo sin suficiente RAM. Aumento de vfs_cache_pressure
puede ayudar, pero la única solución real es obtener más RAM. Tener vfs_cache_pressure
establecer un número alto sacrifica el rendimiento promedio para tener un rendimiento general más estable (es decir, puede evitar el peor de los casos realmente malos, pero tiene que lidiar con un peor rendimiento general).
Finalmente, dígale al kernel que use hasta el 99% de la RAM como caché para escrituras e indíquele al kernel que use hasta el 50% de la RAM antes de ralentizar el proceso de escritura (predeterminado para dirty_background_ratio
es 10
). Advertencia:personalmente no haría esto, pero afirmaste tener suficiente RAM y estás dispuesto a perder los datos.
echo 99 > /proc/sys/vm/dirty_ratio
echo 50 > /proc/sys/vm/dirty_background_ratio
Y decir que 1 h de retraso de escritura está bien incluso para comenzar escribir cosas en el disco (de nuevo, yo no haría esto):
echo 360000 > /proc/sys/vm/dirty_expire_centisecs
echo 360000 > /proc/sys/vm/dirty_writeback_centisecs
Para obtener más información sobre estos parámetros ajustables, consulte https://www.kernel.org/doc/Documentation/sysctl/vm.txt
Si coloca todos esos en /etc/rc.local
e incluya lo siguiente al final, todo estará en caché tan pronto como sea posible después del arranque (solo haga esto si su sistema de archivos realmente cabe en la RAM):
(nice find / -type f -and -not -path '/sys/*' -and -not -path '/proc/*' -print0 2>/dev/null | nice ionice -c 3 wc -l --files0-from - > /dev/null)&
O una alternativa un poco más simple que podría funcionar mejor (solo caché /home
y /usr
, solo haz esto si tu /home
y /usr
realmente caben en RAM):
(nice find /home /usr -type f -print0 | nice ionice -c 3 wc -l --files0-from - > /dev/null)&