Después de mucho benchmarking con sysbench, llego a esta conclusión:
Para sobrevivir (en cuanto al rendimiento) una situación donde
- un malvado proceso de copia inunda páginas sucias
- y la caché de escritura de hardware está presente (posiblemente también sin eso)
- y las lecturas o escrituras sincrónicas por segundo (IOPS) son críticas
simplemente volcar todos los ascensores, colas y cachés de páginas sucias. El lugar correcto para las páginas sucias es en la RAM de ese caché de escritura de hardware.
Ajuste dirty_ratio (o new dirty_bytes) lo más bajo posible, pero vigile el rendimiento secuencial. En mi caso particular, 15 MB fueron óptimos ( echo 15000000 > dirty_bytes
).
Esto es más un truco que una solución porque los gigabytes de RAM ahora se usan solo para el almacenamiento en caché de lectura en lugar de la caché sucia. Para que el caché sucio funcione bien en esta situación, el enjuague de fondo del kernel de Linux necesitaría promediar a qué velocidad el dispositivo subyacente acepta solicitudes y ajustar el enjuague de fondo en consecuencia. No es fácil.
Especificaciones y puntos de referencia para la comparación:
Probado mientras dd
usaba ceros en el disco, sysbench mostró un gran éxito , al aumentar 10 escrituras de fsync a 16 kB de 33 a 700 IOPS (límite de inactividad: 1500 IOPS) y un solo hilo de 8 a 400 IOPS.
Sin carga, los IOPS no se vieron afectados (~ 1500) y el rendimiento se redujo ligeramente (de 251 MB / sa 216 MB / s).
dd
llamada:
dd if=/dev/zero of=dumpfile bs=1024 count=20485672
para sysbench, el test_file.0 se preparó para no analizarse con:
dd if=/dev/zero of=test_file.0 bs=1024 count=10485672
sysbench llama para 10 hilos:
sysbench --test=fileio --file-num=1 --num-threads=10 --file-total-size=10G --file-fsync-all=on --file-test-mode=rndwr --max-time=30 --file-block-size=16384 --max-requests=0 run
sysbench llama para un hilo:
sysbench --test=fileio --file-num=1 --num-threads=1 --file-total-size=10G --file-fsync-all=on --file-test-mode=rndwr --max-time=30 --file-block-size=16384 --max-requests=0 run
Los tamaños de bloque más pequeños mostraron números aún más drásticos.
--file-block-size = 4096 con 1 GB dirty_bytes:
sysbench 0.4.12: multi-threaded system evaluation benchmark
Running the test with following options:
Number of threads: 1
Extra file open flags: 0
1 files, 10Gb each
10Gb total file size
Block size 4Kb
Number of random requests for random IO: 0
Read/Write ratio for combined random IO test: 1.50
Calling fsync() after each write operation.
Using synchronous I/O mode
Doing random write test
Threads started!
Time limit exceeded, exiting...
Done.
Operations performed: 0 Read, 30 Write, 30 Other = 60 Total
Read 0b Written 120Kb Total transferred 120Kb (3.939Kb/sec)
0.98 Requests/sec executed
Test execution summary:
total time: 30.4642s
total number of events: 30
total time taken by event execution: 30.4639
per-request statistics:
min: 94.36ms
avg: 1015.46ms
max: 1591.95ms
approx. 95 percentile: 1591.30ms
Threads fairness:
events (avg/stddev): 30.0000/0.00
execution time (avg/stddev): 30.4639/0.00
--file-block-size = 4096 con 15 MB dirty_bytes:
sysbench 0.4.12: multi-threaded system evaluation benchmark
Running the test with following options:
Number of threads: 1
Extra file open flags: 0
1 files, 10Gb each
10Gb total file size
Block size 4Kb
Number of random requests for random IO: 0
Read/Write ratio for combined random IO test: 1.50
Calling fsync() after each write operation.
Using synchronous I/O mode
Doing random write test
Threads started!
Time limit exceeded, exiting...
Done.
Operations performed: 0 Read, 13524 Write, 13524 Other = 27048 Total
Read 0b Written 52.828Mb Total transferred 52.828Mb (1.7608Mb/sec)
450.75 Requests/sec executed
Test execution summary:
total time: 30.0032s
total number of events: 13524
total time taken by event execution: 29.9921
per-request statistics:
min: 0.10ms
avg: 2.22ms
max: 145.75ms
approx. 95 percentile: 12.35ms
Threads fairness:
events (avg/stddev): 13524.0000/0.00
execution time (avg/stddev): 29.9921/0.00
--file-block-size = 4096 con 15 MB dirty_bytes en el sistema inactivo:
sysbench 0.4.12: punto de referencia de evaluación del sistema de subprocesos múltiples
Running the test with following options:
Number of threads: 1
Extra file open flags: 0
1 files, 10Gb each
10Gb total file size
Block size 4Kb
Number of random requests for random IO: 0
Read/Write ratio for combined random IO test: 1.50
Calling fsync() after each write operation.
Using synchronous I/O mode
Doing random write test
Threads started!
Time limit exceeded, exiting...
Done.
Operations performed: 0 Read, 43801 Write, 43801 Other = 87602 Total
Read 0b Written 171.1Mb Total transferred 171.1Mb (5.7032Mb/sec)
1460.02 Requests/sec executed
Test execution summary:
total time: 30.0004s
total number of events: 43801
total time taken by event execution: 29.9662
per-request statistics:
min: 0.10ms
avg: 0.68ms
max: 275.50ms
approx. 95 percentile: 3.28ms
Threads fairness:
events (avg/stddev): 43801.0000/0.00
execution time (avg/stddev): 29.9662/0.00
Sistema de prueba:
- Adaptec 5405Z (eso es 512 MB de caché de escritura con protección)
- Intel Xeon L5520
- 6 GiB RAM @ 1066 MHz
- Placa base Supermicro X8DTN (chipset 5520)
- 12 discos Seagate Barracuda de 1 TB
- 10 en el software de Linux RAID 10
- Kernel 2.6.32
- Sistema de archivos xfs
- Debian inestable
En resumen, ahora estoy seguro de que esta configuración funcionará bien en situaciones inactivas, de alta carga e incluso de carga completa para el tráfico de la base de datos que de lo contrario se habría visto afectado por el tráfico secuencial. El rendimiento secuencial es superior al que dos enlaces de gigabit pueden entregar de todos modos, por lo que no hay problema en reducirlo un poco.