Begrenzen Sie das Leeren des Linux-Hintergrunds (schmutzige Seiten)

26

Background Flushing unter Linux tritt auf, wenn entweder zu viele geschriebene Daten anstehen (einstellbar über / proc / sys / vm / dirty_background_ratio) oder ein Timeout für anstehende Schreibvorgänge erreicht ist (/ proc / sys / vm / dirty_expire_centisecs). Sofern kein anderes Limit erreicht wird (/ proc / sys / vm / dirty_ratio), werden möglicherweise mehr geschriebene Daten zwischengespeichert. Weitere Schreibvorgänge werden blockiert.

Theoretisch sollte dies einen Hintergrundprozess erzeugen, der schmutzige Seiten ausschreibt, ohne andere Prozesse zu stören. In der Praxis stört es jeden Prozess, der nicht zwischengespeichertes Lesen oder synchrones Schreiben ausführt. Schlecht. Dies liegt daran, dass die Hintergrundbereinigung tatsächlich mit 100% Gerätegeschwindigkeit schreibt und alle anderen Geräteanforderungen zu diesem Zeitpunkt verzögert werden (da alle Warteschlangen und Schreibcaches auf der Straße gefüllt sind).

Gibt es eine Möglichkeit, die Anzahl der Anforderungen pro Sekunde zu begrenzen, die der Spülvorgang ausführt, oder andere Geräte-E / A auf andere Weise effektiv zu priorisieren?

Korkman
quelle
Vielleicht ist dies eine gute Frage, die Sie um 21:56
Welchen IO-Scheduler verwenden Sie?
3dinfluence
Versuchte verschiedene (CFQ, Deadline), aber ich denke, diese funktionieren nur zuverlässig, wenn kein batteriegepufferter Schreib-Cache enthalten ist. Wie ein Disk-Array habe ich 1 GB Daten mit PCIe-Bus-Geschwindigkeit (RAM) und stoße dann auf die Reality-Wall. Mehrere Sekunden Null-E / A für alle LUNs. Eine Drosselung der Flushs (zumindest im Hintergrund) auf eine grobe Schätzung der tatsächlichen Gerätegeschwindigkeit würde dieses Überlastungsproblem lösen.
Korkman
1
Vor kurzem wurde mir bewusst, dass / sys / block / sdX / queue / nr_requests ein wichtiges Tunable ist. Wenn Sie den Wert auf Minimum (= 4 in meinem Fall) reduzieren, wird die Latenz beim gleichzeitigen Laden erheblich verbessert: Die Anzahl der fsync-Zufallsschreibvorgänge in Sysbench pro Sekunde stieg von 4 (!) Auf 80-90, während mit dd mit Busgeschwindigkeit geschrieben wurde. Die nicht geladene Leistung scheint davon nicht betroffen zu sein. Scheduler sind alle gleich, Noop oder Deadline scheinen optimal. Dies kann für die meisten BBWC-Konfigurationen zutreffen.
Korkman

Antworten:

20

Nach vielem Benchmarking mit sysbench komme ich zu folgendem Schluss:

Eine Situation zu überleben, in der

  • Ein böser Kopiervorgang überflutet schmutzige Seiten
  • und Hardware Write-Cache ist vorhanden (evtl. auch ohne das)
  • und synchrone Lese- oder Schreibvorgänge pro Sekunde (IOPS) sind kritisch

Entleere einfach alle Aufzüge, Warteschlangen und schmutzigen Seiten-Caches. Der richtige Ort für fehlerhafte Seiten befindet sich im RAM dieses Hardware-Schreibcaches.

Passen Sie dirty_ratio (oder neue dirty_bytes) so niedrig wie möglich an, achten Sie jedoch auf den sequentiellen Durchsatz. In meinem speziellen Fall waren 15 MB optimal ( echo 15000000 > dirty_bytes).

Dies ist eher ein Hack als eine Lösung, da Gigabyte RAM jetzt nur für das Lese-Caching anstelle von Dirty-Cache verwendet werden. Damit ein fehlerhafter Cache in dieser Situation gut funktioniert, muss der Linux-Kernel-Hintergrund-Flusher die durchschnittliche Geschwindigkeit ermitteln, mit der das zugrunde liegende Gerät Anforderungen akzeptiert, und das Hintergrund-Flushing entsprechend anpassen. Nicht einfach.


Spezifikationen und Benchmarks zum Vergleich:

Getestet, während ddNullen auf die Festplatte geschrieben wurden, zeigte sysbench einen enormen Erfolg : 10 Threads wurden mit 16 kB von 33 auf 700 IOPS (Leerlaufbegrenzung: 1500 IOPS) und ein einzelner Thread von 8 auf 400 IOPS erhöht.

Ohne Last waren IOPS nicht betroffen (~ 1500) und der Durchsatz leicht reduziert (von 251 MB / s auf 216 MB / s).

dd Anruf:

dd if=/dev/zero of=dumpfile bs=1024 count=20485672

für sysbench wurde die test_datei.0 vorbereitet, um unsparse zu sein mit:

dd if=/dev/zero of=test_file.0 bs=1024 count=10485672

Sysbench-Aufruf für 10 Threads:

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-Aufruf für einen 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

Kleinere Blockgrößen zeigten noch drastischere Zahlen.

--file-block-size = 4096 mit 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 mit 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 mit 15 MB dirty_bytes im Leerlauf:

sysbench 0.4.12: Multithread-Systembewertungsbenchmark

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

Testsystem:

  • Adaptec 5405Z (das sind 512 MB Schreib-Cache mit Schutz)
  • Intel Xeon L5520
  • 6 GiB RAM bei 1066 MHz
  • Hauptplatine Supermicro X8DTN (5520 Chipsatz)
  • 12 Seagate Barracuda 1 TB-Festplatten
    • 10 in Linux-Software-RAID 10
  • Kernel 2.6.32
  • Dateisystem xfs
  • Debian instabil

Zusammenfassend bin ich jetzt sicher, dass diese Konfiguration im Leerlauf, bei hoher Auslastung und sogar bei voller Auslastung für Datenbankverkehr, der ansonsten durch sequentiellen Verkehr ausgehungert worden wäre, eine gute Leistung erbringt. Der sequenzielle Durchsatz ist höher als zwei Gigabit-Verbindungen ohnehin liefern können, daher ist es kein Problem, ihn ein wenig zu reduzieren.

Korkman
quelle
Was ist Ihre Methode, um den Teil "15 MB für Dirty_Buffer ist optimal" zu erreichen?
Marcin
1
Versuch und Irrtum. Ändern Sie beim nächsten Mal etwa die Hälfte des Betrags, bis ich nur noch 15 MB und OK IOPS habe. Der aktuelle Kernel 3.2 kann sich ganz anders verhalten, übrigens.
Korkman
2
Ich wollte mich nur bedanken, dass du mich auf den richtigen Weg gebracht hast. Hatte einige ähnliche Probleme mit einem XenServer-Knoten. Es stellte sich heraus, dass PHP-FPM / APC-Cache schmutzige Seiten verursachte. Das Anpassen des APC-Cache-Speichermodells löste das Problem für uns. DiskIO wurde von 20% auf 0
ausgelastet
Logischerweise dirty_bytessollte es kaum hoch genug sein, um die CPUs nicht zu blockieren, während Prozesse schreiben, wenn der Prozess im Durchschnitt mit dem Durchsatz des Geräts schreibt . Wenn Ihr Anwendungscode Zyklen großer Berechnungen durchführt, gefolgt vom Schreiben großer Datenmengen, ist die Optimierung sehr schwierig, da sich die Durchschnittswerte für kurze Zeit stark von denen für lange Zeit unterscheiden. Die richtige Lösung wäre, die prozessspezifischen dirty_bytesEinstellungen anzupassen , aber Linux unterstützt so etwas meines Wissens nicht.
Mikko Rantalainen
3

Obwohl die Optimierung der Kernel-Parameter das Problem gestoppt hat, ist es tatsächlich möglich, dass Ihre Leistungsprobleme auf einen Fehler auf dem Adaptec 5405Z-Controller zurückzuführen sind, der in einem Firmware-Update vom 1. Februar 2012 behoben wurde. In den Versionshinweisen heißt es: "Es wurde ein Problem behoben, bei dem die Firmware bei hoher E / A-Belastung hängen blieb." Vielleicht hat es genügt, die E / A so zu verteilen, dass dieser Fehler nicht ausgelöst wird, aber das ist nur eine Vermutung.

Hier sind die Versionshinweise: http://download.adaptec.com/pdfs/readme/relnotes_arc_fw-b18937_asm-18837.pdf

Auch wenn dies in Ihrer speziellen Situation nicht der Fall war, war ich der Meinung, dass dies Nutzern zugute kommen könnte, die in Zukunft auf diesen Beitrag stoßen. In unserer dmesg-Ausgabe sahen wir einige Meldungen wie die folgende, die uns schließlich zum Firmware-Update führten:

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

Hier sind die Modellnummern der Adaptec RAID-Controller aufgeführt, die in den Versionshinweisen für die Firmware mit dem Fix für hohe E / A-Probleme aufgeführt sind: 2045, 2405, 2405Q, 2805, 5085, 5405, 5405Z, 5445, 5445Z, 5805, 5805Q, 5805Z, 5805ZQ, 51245, 51645, 52445.

sa289
quelle
1
Wow, danke für deinen Input. Obwohl dies bei mir nicht der Fall war, geben Sie mir noch einen weiteren Grund, HW-RAID vollständig zu vermeiden und mit nur HBA-Setups fortzufahren. HW RAID hat immer noch den BBWC-Vorteil, aber mit Dingen wie bcache, die in den Kernel gelangen, verschwindet auch dieser. Der Nachteil von HW-RAID ist genau die Art von Firmware-Fehlern, die Sie beschreiben. Ich hatte ein anderes System mit DRBD-Setup und hoher E / A-Last, die Firmware-Resets verursachte. Dies ist also nicht selten anzutreffen (könnte genau dieser Fehler gewesen sein).
Korkman
1

Ein Kernel, der "WBT" enthält:

Verbesserungen in der Blockebene , LWN.net

Beim Writeback-Throttling versucht [die Blockschicht], mithilfe einer Strategie, die vom CoDel-Netzwerkplaner entlehnt wurde, die maximale Leistung ohne übermäßige E / A-Latenz zu erzielen. CoDel verfolgt die beobachtete minimale Latenzzeit von Netzwerkpaketen und fängt an, Pakete zu verwerfen, wenn diese einen Schwellenwert überschreiten. Das Löschen von Schreibvorgängen ist im E / A-Subsystem verpönt, aber eine ähnliche Strategie wird verfolgt, indem der Kernel die minimale Latenz von Lese- und Schreibvorgängen überwacht und, wenn diese einen Schwellenwert überschreiten, den Umfang des Hintergrund-Rückschreibens verringert das wird gemacht. Dieses Verhalten wurde in 4.10 hinzugefügt; Axboe sagte, dass ziemlich gute Ergebnisse gesehen wurden.

WBT erfordert kein Umschalten auf die neue Blockebene "blk-mq". Das heißt, es funktioniert nicht mit den E / A-Schedulern CFQ oder BFQ. Sie können WBT mit den Schedulern deadline / mq-deadline / noop / none verwenden. Ich glaube, es funktioniert auch mit dem neuen "Kyber" I / O-Scheduler.

Der WBT-Code skaliert nicht nur die Warteschlangengröße, um die Latenz zu steuern, sondern begrenzt auch die Anzahl der Rückschreibanforderungen im Hintergrund als Anteil des berechneten Warteschlangenlimits.

Die Laufzeitkonfiguration ist in /sys/class/block/*/queue/wbt_lat_usec.

Die zu suchenden Build-Konfigurationsoptionen sind

/boot/config-4.20.8-200.fc29.x86_64:CONFIG_BLK_WBT=y
/boot/config-4.20.8-200.fc29.x86_64:# CONFIG_BLK_WBT_SQ is not set
/boot/config-4.20.8-200.fc29.x86_64:CONFIG_BLK_WBT_MQ=y

Ihre Problemstellung wird zu 100% vom Autor von WBT bestätigt - gut gemacht :-).

[PATCHSET] -Block: Gedrosseltes Zurückschreiben

Seit Anbeginn der Zeit ist unser im Hintergrund gepuffertes Rückschreiben zum Erliegen gekommen. Wenn wir ein gepuffertes Rückschreiben im Hintergrund durchführen, sollte dies nur geringe Auswirkungen auf die Vordergrundaktivität haben. Das ist die Definition von Hintergrundaktivität ... Aber so lange ich mich erinnern kann, haben sich stark gepufferte Autoren nicht so verhalten. Zum Beispiel, wenn ich so etwas mache:

$ dd if=/dev/zero of=foo bs=1M count=10k

Auf meinem Laptop und wenn Sie dann versuchen, Chrome zu starten, wird es im Grunde nicht gestartet, bevor das gepufferte Rückschreiben abgeschlossen ist. Oder für serverorientierte Workloads, bei denen die Installation einer großen RPM (oder ähnliches) die Datenbanklesevorgänge oder -synchronisationsschreibvorgänge beeinträchtigt. Wenn das passiert, brüllen mich die Leute an.

Ergebnisse einiger kürzlich durchgeführter Tests finden Sie hier:

https://www.facebook.com/axboe/posts/10154074651342933

Weitere Informationen zum Patchset finden Sie in den vorherigen Beiträgen.

sourcejedi
quelle
Ich bin froh zu sehen, dass das Problem jetzt im Kernel erkannt und behoben wird. Denken Sie daran, blk-mq ist ziemlich neu und vielleicht noch nicht so ausgereift .
Korkman
@ Korkman Seufzer, ich denke, ich werde das Zitat entstellen, um die falsche Implikation zu vermeiden. Ich bin damit einverstanden, dass dies Dinge sind, die in den letzten Jahren hinzugefügt wurden. Möglicherweise gibt es immer noch Leistungsrückgänge oder Schlimmeres. AFAIR, der Betreuer, weist die Datenkorruptionsbehebung in dem Sinne zurück, dass dies ein Zufall ist. Wenn Sie die Kernel-Versionen verwenden, in denen blk-mq entwickelt wurde, ist es fraglich, inwieweit die Verwendung der "Legacy" -Block-Ebene Fehler vermeidet. Der Suspend-Fehler, den ich behoben habe, war ein Fehler, der in blk-mq entstanden ist, dann wurde er überarbeitet oder etwas anderes und betraf beide. github.com/torvalds/linux/commit/1dc3039bc87a
sourcejedi
0

Was ist dein Durchschnitt für Dirty in / proc / meminfo? Dies sollte normalerweise Ihr / proc / sys / vm / dirty_ratio nicht überschreiten. Auf einem dedizierten Dateiserver habe ich dirty_ratio auf einen sehr hohen Prozentsatz des Speichers (90) eingestellt, da ich ihn nie überschreiten werde. Deine Dirty_Ration ist zu niedrig, wenn du sie triffst, bricht alles zusammen, erhöhe sie.

Luke
quelle
Das Problem ist nicht, dass Prozesse blockiert werden, wenn dirty_ratio getroffen wird. Ich bin damit einverstanden. Aber der "Hintergrund" -Prozess, der schmutzige Daten auf die Festplatten schreibt, füllt Warteschlangen ohne Gnade und beeinträchtigt die IOPS-Leistung. Ich denke, es heißt IO-Hunger. In der Tat hilft es, dirty_ratio_bytes extrem niedrig einzustellen (wie 1 MB), da das Leeren fast sofort erfolgt und die Warteschlangen leer bleiben. Nachteil ist möglicherweise geringerer Durchsatz für sequentielle, aber das ist in Ordnung.
Korkman
Sie haben alle Aufzüge ausgeschaltet? Was haben Sie noch an einem Vanille-System geändert?
Luke
1
Siehe meine Selbstantwort. Das Ende der Geschichte bestand darin, das schmutzige Caching zu entfernen und diesen Teil dem HW-Controller zu überlassen. Aufzüge sind irgendwie irrelevant, wenn ein HW-Schreibcache vorhanden ist. Die Steuerung verfügt über eigene Aufzugsalgorithmen, sodass jeder Aufzug in der Software nur zusätzlichen Aufwand verursacht.
Korkman
Aufzug in der Software ist ein Kompromiss: Latenz opfern, um Bandbreite zu verbessern. Stellen Sie sich beispielsweise 100.000 Schreibvorgänge in der Software-Warteschlange vor, die in zufälliger Reihenfolge gesendet werden. Wenn der Software-Aufzug diese Operationen unter Verwendung eines großen Puffers bestellen kann, sendet er möglicherweise nur 5 KB große Anforderungen an das Gerät. Dies hat jedoch zur Folge, dass die Latenz um 100K-Operationen erhöht werden muss, da sich die ersten 2K-Operationen und die letzten 1K-Operationen auf dem Gerät möglicherweise tatsächlich in der Nähe befinden. Ohne zusätzliche Latenz ist es unmöglich, diese zusammenzuführen.
Mikko Rantalainen