Linux: ajuste del controlador RAID de hardware del mundo real (scsi y cciss)

29

La mayoría de los sistemas Linux que administro tienen controladores RAID de hardware de características (principalmente HP Smart Array ). Todos están ejecutando RHEL o CentOS.

Estoy buscando ajustables del mundo real para ayudar a optimizar el rendimiento de las configuraciones que incorporan controladores RAID de hardware con discos SAS (Smart Array, Perc, LSI, etc.) y caché con respaldo de batería o flash. Suponga RAID 1 + 0 y múltiples ejes (4+ discos).

Paso una cantidad considerable de tiempo ajustando la configuración de red de Linux para aplicaciones de comercio financiero y de baja latencia. Pero muchas de esas opciones están bien documentadas (cambiar las memorias intermedias de envío / recepción, modificar la configuración de la ventana TCP, etc.). ¿Qué están haciendo los ingenieros en el lado del almacenamiento?

Históricamente, he realizado cambios en el elevador de programación de E / S , y recientemente he optado por deadliney los noopprogramadores para mejorar el rendimiento dentro de mis aplicaciones. A medida que las versiones de RHEL han progresado, también he notado que los valores predeterminados compilados para los dispositivos de bloque SCSI y CCISS también han cambiado. Esto ha tenido un impacto en la configuración recomendada del subsistema de almacenamiento a lo largo del tiempo. Sin embargo, ha pasado un tiempo desde que vi recomendaciones claras. Y sé que los valores predeterminados del sistema operativo no son óptimos. Por ejemplo, parece que el búfer de lectura anticipada predeterminado de 128 kb es extremadamente pequeño para una implementación en hardware de clase de servidor.

Los siguientes artículos exploran el impacto en el rendimiento de cambiar la memoria caché de lectura anticipada y los valores nr_requests en las colas de bloque.

http://zackreed.me/articles/54-hp-smart-array-p410-controller-tuning
http://www.overclock.net/t/515068/tuning-a-hp-smart-array-p400-with -linux-why-tuning-really-matters
http://yoshinorimatsunobu.blogspot.com/2009/04/linux-io-scheduler-queue-size-and.html

Por ejemplo, estos son cambios sugeridos para un controlador HP Smart Array RAID:

echo "noop" > /sys/block/cciss\!c0d0/queue/scheduler 
blockdev --setra 65536 /dev/cciss/c0d0
echo 512 > /sys/block/cciss\!c0d0/queue/nr_requests
echo 2048 > /sys/block/cciss\!c0d0/queue/read_ahead_kb

¿Qué más se puede ajustar de manera confiable para mejorar el rendimiento del almacenamiento?
Estoy buscando específicamente las opciones sysctl y sysfs en escenarios de producción.

ewwhite
fuente

Respuestas:

38

Descubrí que cuando tuve que ajustar para una latencia más baja en comparación con el rendimiento, reduje nr_requests desde su valor predeterminado (hasta 32). La idea de lotes más pequeños equivale a una latencia más baja.

También para read_ahead_kb descubrí que para lecturas / escrituras secuenciales, aumentar este valor ofrece un mejor rendimiento, pero descubrí que esta opción realmente depende de su carga de trabajo y patrón de E / S. Por ejemplo, en un sistema de base de datos que he sintonizado recientemente, cambié este valor para que coincida con un solo tamaño de página de base de datos que ayudó a reducir la latencia de lectura. Aumentar o disminuir más allá de este valor resultó perjudicar el rendimiento en mi caso.

En cuanto a otras opciones o configuraciones para bloquear colas de dispositivos:

max_sectors_kb = He configurado este valor para que coincida con lo que el hardware permite para una sola transferencia (verifique el valor del archivo max_hw_sectors_kb (RO) en sysfs para ver qué está permitido)

nomerges = esto le permite deshabilitar o ajustar la lógica de búsqueda para fusionar solicitudes io. (desactivar esto puede ahorrarle algunos ciclos de CPU, pero no he visto ningún beneficio al cambiar esto para mis sistemas, así que lo dejé por defecto)

rq_affinity = No he probado esto todavía, pero aquí está la explicación detrás de los documentos del kernel

Si esta opción es '1', la capa de bloque migrará las finalizaciones de la solicitud al "grupo" de la CPU que originalmente envió la solicitud. Para algunas cargas de trabajo, esto proporciona una reducción significativa en los ciclos de CPU debido a los efectos de almacenamiento en caché.
Para las configuraciones de almacenamiento que necesitan maximizar la distribución del procesamiento de finalización, establecer esta opción en '2' obliga a la finalización a ejecutarse en la CPU solicitante (omitiendo la lógica de agregación del "grupo")

planificador = dijiste que intentaste el plazo y noop. He probado tanto el noop como la fecha límite, pero he encontrado que la fecha límite no es válida para las pruebas que hice más recientemente para un servidor de base de datos.

NOOP funcionó bien, pero para nuestro servidor de bases de datos todavía pude lograr un mejor rendimiento ajustando el programador de la fecha límite.

Opciones para el planificador de fecha límite ubicado en / sys / block / {sd, cciss, dm -} * / queue / iosched /:

fifo_batch = algo así como nr_requests, pero específico para el planificador. La regla general es ajustar esto hacia abajo para una latencia más baja o hacia arriba para el rendimiento. Controla el tamaño del lote de las solicitudes de lectura y escritura.

write_expire = establece el tiempo de caducidad para los lotes de escritura por defecto es 5000ms. Una vez más, disminuir este valor disminuye su latencia de escritura, mientras que aumentar el valor aumenta el rendimiento.

read_expire = establece el tiempo de caducidad para los lotes de lectura por defecto es de 500 ms. Las mismas reglas se aplican aquí.

front_merges = Tiendo a desactivar esto, y está activado por defecto. No veo la necesidad de que el planificador desperdicie los ciclos de CPU tratando de fusionar por adelantado las solicitudes de IO.

writes_starved = dado que la fecha límite está orientada hacia las lecturas, el valor predeterminado aquí es procesar 2 lotes de lectura antes de que se procese un lote de escritura. Encontré que el valor predeterminado de 2 es bueno para mi carga de trabajo.

rtorti19
fuente
77
... y así es como publicas tu primera respuesta en un sitio. ¡Bien hecho!
Jeff Ferland
1
Este es un buen comienzo y ejecutar pruebas repetidas en condiciones controladas me ha ayudado a ajustar un poco el rendimiento de la aplicación. También es útil ver cómo puedo ajustar el almacenamiento para las tendencias generales de carga de trabajo.
ewwhite
4

Más que nada, todo depende de su carga de trabajo.

read_ahead_kbpuede ayudarlo si es realmente útil leer una gran cantidad de datos de algún archivo con anticipación, como cuando transmite video. A veces puede lastimarte mucho. Sí, los 128 KB predeterminados pueden sonar pequeños, pero con suficiente concurrencia, ¡comienzan a sonar como grandes! Por otro lado, con un servidor como un servidor de codificación de video que solo convierte los videos de un formato a otro, sería una buena idea sintonizar.

nr_requests, cuando se sintoniza demasiado, puede inundar fácilmente su controlador RAID, lo que nuevamente perjudica el rendimiento.

En el mundo real, necesitas mirar las latencias . Si está conectado a SAN, echar un vistazo a iostat, saro lo que le gusta usar, y ver si los tiempos de solicitud de E / S de servicios están por las nubes. Por supuesto, esto también ayuda con los discos locales: si las latencias son muy grandes, considere reducir la configuración de su elevador de E / S bajando max_requests y otras configuraciones.

Janne Pikkarainen
fuente
¿Qué otras configuraciones?
ewwhite
4

Para su información read_ahead_kby blockdev --setrason solo diferentes maneras de establecer la misma configuración utilizando diferentes unidades (kB vs sectores):

foo:~# blockdev --setra 65536 /dev/cciss/c0d0
foo:~# blockdev --getra /dev/cciss/c0d0
65536
foo:~# cat /sys/block/cciss\!c0d0/queue/read_ahead_kb
32768
foo:~# echo 2048 > /sys/block/cciss\!c0d0/queue/read_ahead_kb
foo:~# cat /sys/block/cciss\!c0d0/queue/read_ahead_kb
2048
foo:~# blockdev --getra /dev/cciss/c0d0
4096

Entonces el

blockdev --setra 65536 /dev/cciss/c0d0

en tu ejemplo no tiene efecto.

en cambio
fuente