Soluzione 1:
Dopo molti benchmark con sysbench, sono giunto a questa conclusione:
Per sopravvivere (dal punto di vista delle prestazioni) a una situazione in cui
- un processo di copia malvagio inonda le pagine sporche
- ed è presente la cache di scrittura hardware (possibilmente anche senza)
- e le letture o scritture sincrone al secondo (IOPS) sono fondamentali
basta scaricare tutti gli ascensori, le code e le cache delle pagine sporche. Il posto corretto per le pagine sporche è nella RAM di quella cache di scrittura hardware.
Regola dirty_ratio (o nuovi dirty_bytes) il più basso possibile, ma tieni d'occhio il throughput sequenziale. Nel mio caso particolare, 15 MB erano ottimali (echo 15000000 > dirty_bytes
).
Questo è più un trucco che una soluzione perché ora vengono utilizzati gigabyte di RAM solo per la cache di lettura anziché per la cache sporca. Affinché la cache sporca funzioni bene in questa situazione, lo scaricatore in background del kernel di Linux dovrebbe calcolare la media della velocità con cui il dispositivo sottostante accetta le richieste e regolare di conseguenza lo svuotamento in background. Non facile.
Specifiche e benchmark per il confronto:
Testato a dd
azzerando il disco, sysbench ha mostrato un enorme successo , aumentando le scritture fsync di 10 thread a 16 kB da 33 a 700 IOPS (limite di inattività:1500 IOPS) e thread singolo da 8 a 400 IOPS.
Senza carico, gli IOPS non sono stati influenzati (~1500) e il throughput è stato leggermente ridotto (da 251 MB/s a 216 MB/s).
dd
chiama:
dd if=/dev/zero of=dumpfile bs=1024 count=20485672
per sysbench, test_file.0 è stato preparato per essere unsparse con:
dd if=/dev/zero of=test_file.0 bs=1024 count=10485672
chiamata sysbench per 10 thread:
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
chiamata sysbench per un thread:
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
Le dimensioni dei blocchi più piccole hanno mostrato numeri ancora più drastici.
--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 su sistema inattivo:
sysbench 0.4.12:benchmark di valutazione del sistema multi-thread
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 di test:
- Adaptec 5405Z (ovvero 512 MB di cache in scrittura con protezione)
- Intel Xeon L5520
- 6 GiB di RAM a 1066 MHz
- Scheda madre Supermicro X8DTN (chipset 5520)
- 12 dischi Seagate Barracuda da 1 TB
- 10 nel software RAID 10 di Linux
- Kernel 2.6.32
- Filesystem xfs
- Debian instabile
In sintesi, ora sono sicuro che questa configurazione funzionerà bene in situazioni di inattività, carico elevato e persino a pieno carico per il traffico del database che altrimenti sarebbe stato affamato dal traffico sequenziale. Il throughput sequenziale è comunque superiore a quello che possono fornire due collegamenti gigabit, quindi nessun problema a ridurlo un po'.
Soluzione 2:
Anche se l'ottimizzazione dei parametri del kernel ha risolto il problema, in realtà è possibile che i problemi di prestazioni siano il risultato di un bug sul controller Adaptec 5405Z che è stato corretto in un aggiornamento del firmware del 1° febbraio 2012. Le note di rilascio dicono "Risolto un problema per cui il firmware poteva bloccarsi durante un elevato stress I/O". Forse distribuire l'I/O come hai fatto è stato sufficiente per impedire l'attivazione di questo bug, ma è solo un'ipotesi.
Ecco le note di rilascio:http://download.adaptec.com/pdfs/readme/relnotes_arc_fw-b18937_asm-18837.pdf
Anche se questo non fosse il caso della tua situazione particolare, ho pensato che ciò potesse essere di beneficio agli utenti che si imbattessero in questo post in futuro. Abbiamo visto alcuni messaggi come il seguente nel nostro output dmesg che alla fine ci ha portato all'aggiornamento del firmware:
aacraid: Host adapter abort request (0,0,0,0)
[above was repeated many times]
AAC: Host adapter BLINK LED 0x62
AAC0: adapter kernel panic'd 62.
sd 0:0:0:0: timing out command, waited 360s
sd 0:0:0:0: Unhandled error code
sd 0:0:0:0: SCSI error: return code = 0x06000000
Result: hostbyte=DID_OK driverbyte=DRIVER_TIMEOUT,SUGGEST_OK
sd 0:0:0:0: timing out command, waited 360s
sd 0:0:0:0: Unhandled error code
sd 0:0:0:0: SCSI error: return code = 0x06000028
Result: hostbyte=DID_OK driverbyte=DRIVER_TIMEOUT,SUGGEST_OK
sd 0:0:0:0: timing out command, waited 360s
sd 0:0:0:0: Unhandled error code
sd 0:0:0:0: SCSI error: return code = 0x06000028
Di seguito sono riportati i numeri di modello dei controller RAID Adaptec elencati nelle note di rilascio per il firmware con correzione del blocco I/O elevato:2045, 2405, 2405Q, 2805, 5085, 5405, 5405Z, 5445, 5445Z, 5805, 5805Q, 5805Z, 5805ZQ, 51245, 51645, 52445.