Limiter le vidage d'arrière-plan Linux (pages sales)

26

Le vidage en arrière-plan sur Linux se produit lorsque trop de données écrites sont en attente (réglables via / proc / sys / vm / dirty_background_ratio) ou qu'un délai d'attente pour les écritures en attente est atteint (/ proc / sys / vm / dirty_expire_centisecs). À moins qu'une autre limite ne soit atteinte (/ proc / sys / vm / dirty_ratio), davantage de données écrites peuvent être mises en cache. D'autres écritures se bloqueront.

En théorie, cela devrait créer un processus d'arrière-plan pour écrire des pages sales sans perturber les autres processus. En pratique, cela perturbe tout processus effectuant une lecture non mise en cache ou une écriture synchrone. Mal. Cela est dû au fait que le vidage d'arrière-plan écrit en fait à 100% de la vitesse du périphérique et que toute autre demande de périphérique à ce moment sera retardée (car toutes les files d'attente et les caches d'écriture sur la route sont remplis).

Existe-t-il un moyen de limiter le nombre de demandes par seconde effectuées par le processus de vidage, ou de hiérarchiser efficacement les autres E / S de périphérique?

korkman
la source
Ce serait peut-être une bonne question à envoyer à la liste de diffusion du noyau linux vger.kernel.org/vger-lists.html#linux-kernel
Quel planificateur IO utilisez-vous?
3dinfluence
J'ai essayé plusieurs (cfq, délai), mais je suppose que cela ne fonctionne de manière fiable que si aucun cache d'écriture sauvegardé par batterie n'est inclus. Comme une baie de disques, je mange 1 Gio de données à la vitesse du bus PCIe (RAM), puis frappe le mur de la réalité. Plusieurs secondes zéro E / S pour tous les LUN. Limiter les débits (au moins ceux de fond) à une estimation approximative de la vitesse réelle de l'appareil résoudrait ce problème de congestion.
korkman
1
J'ai récemment pris conscience que / sys / block / sdX / queue / nr_requests était un accordable majeur. Le baisser au minimum (= 4 dans mon cas) améliore beaucoup la latence de la charge simultanée: les écritures aléatoires Sysbench fsync par seconde sont passées de 4 (!) À 80-90 tout en écrivant à la vitesse du bus avec dd. Les performances non chargées ne semblent pas affectées. Les programmateurs sont tous les mêmes, noop ou délai semble optimal. Cela peut être vrai pour la plupart des configurations BBWC.
korkman

Réponses:

20

Après de nombreuses analyses comparatives avec sysbench, j'arrive à cette conclusion:

Pour survivre (en termes de performances) à une situation où

  • un mauvais processus de copie inonde les pages sales
  • et le cache d'écriture matériel est présent (peut-être aussi sans cela)
  • et les lectures ou écritures synchrones par seconde (IOPS) sont essentielles

il suffit de vider tous les ascenseurs, les files d'attente et les caches de pages sales. L'endroit correct pour les pages sales est dans la RAM de ce cache d'écriture matériel.

Ajustez dirty_ratio (ou les nouveaux dirty_bytes) aussi bas que possible, mais gardez un œil sur le débit séquentiel. Dans mon cas particulier, 15 Mo étaient optimaux ( echo 15000000 > dirty_bytes).

Il s'agit plus d'un hack que d'une solution car des gigaoctets de RAM sont désormais utilisés uniquement pour la mise en cache de lecture au lieu de cache sale. Pour que le cache sale fonctionne bien dans cette situation, le nettoyeur d'arrière-plan du noyau Linux devrait faire la moyenne de la vitesse à laquelle le périphérique sous-jacent accepte les demandes et ajuster le vidage d'arrière-plan en conséquence. Pas facile.


Spécifications et repères de comparaison:

Testé lors de l'utilisation ddde zéros sur le disque, sysbench a connu un énorme succès , augmentant 10 threads d'écriture fsync à 16 Ko de 33 à 700 IOPS (limite d'inactivité: 1500 IOPS) et un thread unique de 8 à 400 IOPS.

Sans charge, les IOPS n'étaient pas affectés (~ 1500) et le débit était légèrement réduit (de 251 Mo / s à 216 Mo / s).

dd appel:

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

pour sysbench, le test_file.0 a été préparé pour ne pas être analysé avec:

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

appel sysbench pour 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

appel sysbench pour 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

De plus petites tailles de blocs ont montré des nombres encore plus drastiques.

--file-block-size = 4096 avec 1 Go 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 avec 15 Mo 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 avec 15 Mo dirty_bytes sur le système inactif:

sysbench 0.4.12: benchmark d'évaluation de système 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

Système de test:

  • Adaptec 5405Z (soit 512 Mo de cache en écriture avec protection)
  • Intel Xeon L5520
  • 6 Go de RAM à 1066 MHz
  • Carte mère Supermicro X8DTN (chipset 5520)
  • 12 disques Seagate Barracuda 1 To
    • 10 dans le logiciel Linux RAID 10
  • Noyau 2.6.32
  • Système de fichiers xfs
  • Debian instable

En résumé, je suis maintenant sûr que cette configuration fonctionnera bien dans des situations d'inactivité, de charge élevée et même de pleine charge pour le trafic de base de données qui autrement aurait été affamé par le trafic séquentiel. Le débit séquentiel est supérieur à ce que deux liaisons gigabits peuvent fournir de toute façon, donc pas de problème à le réduire un peu.

korkman
la source
Quelle est votre méthodologie pour arriver à la partie '15MB pour dirty_buffers is optimal'?
Marcin
1
Essai et erreur. Comme, changez la moitié du montant la prochaine fois, etc., jusqu'à ce que je me retrouve avec seulement 15 Mo et des IOPS OK. Le noyau 3.2 actuel peut se comporter très différemment, BTW.
korkman
2
Je voulais juste vous remercier de m'avoir mis sur la bonne voie. Eu des problèmes similaires avec un nœud XenServer. Il s'est avéré que le cache PHP-FPM / APC provoquait des pages sales. L'ajustement du modèle de mémoire cache APC a résolu le problème pour nous. DiskIO est passé de 20% d'utilisation à 0.
jeffatrackaid
Logiquement, il dirty_bytesdevrait être à peine suffisamment élevé pour ne pas bloquer les processeurs pendant l'écriture des processus si le processus écrit en moyenne avec le débit du périphérique. Si votre code d'application effectue des cycles de calcul énorme suivis par l'écriture d'une énorme quantité de données, il sera très difficile à optimiser car les moyennes à court terme diffèrent considérablement des moyennes à long terme. La bonne solution serait d'ajuster le dirty_bytesparamètre spécifique au processus , mais Linux ne prend pas en charge une telle chose pour autant que je sache.
Mikko Rantalainen
3

Même si le réglage des paramètres du noyau a arrêté le problème, il est possible que vos problèmes de performances soient le résultat d'un bogue sur le contrôleur Adaptec 5405Z qui a été corrigé dans une mise à jour du micrologiciel du 1er février 2012. Les notes de version indiquent "Correction d'un problème où le micrologiciel pouvait se bloquer lors d'une forte contrainte d'E / S." Peut-être que répartir les E / S comme vous l'avez fait était suffisant pour empêcher ce bug de se déclencher, mais ce n'est qu'une supposition.

Voici les notes de version: http://download.adaptec.com/pdfs/readme/relnotes_arc_fw-b18937_asm-18837.pdf

Même si ce n'était pas le cas pour votre situation particulière, j'ai pensé que cela pourrait bénéficier aux utilisateurs qui rencontreront ce message à l'avenir. Nous avons vu des messages comme les suivants dans notre sortie dmesg qui nous ont finalement conduit à la mise à jour du 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

Voici les numéros de modèle des contrôleurs RAID Adaptec répertoriés dans les notes de mise à jour du micrologiciel doté du correctif de blocage d'E / S élevé: 2045, 2405, 2405Q, 2805, 5085, 5405, 5405Z, 5445, 5445Z, 5805, 5805Q, 5805Z, 5805ZQ, 51245, 51645, 52445.

sa289
la source
1
Wow, merci pour votre contribution. Bien que ce ne soit pas le cas pour moi, vous me donnez une autre raison d'éviter complètement le HW RAID et de passer aux configurations HBA uniquement. HW RAID a toujours l'avantage BBWC, mais avec des choses comme bcache se déplaçant dans le noyau, même cela disparaît. L'inconvénient de HW RAID est exactement le genre de bogues de firmware que vous décrivez. J'avais un autre système avec une configuration DRBD et une charge d'E / S élevée provoquant des réinitialisations du micrologiciel, donc ce n'est pas rare de rencontrer (cela pourrait être exactement ce bug).
korkman
1

Un noyau qui inclut "WBT":

Améliorations de la couche de blocs , LWN.net

Avec la limitation d'écriture différée, [la couche de blocs] tente d'obtenir des performances maximales sans latence d'E / S excessive en utilisant une stratégie empruntée au planificateur de réseau CoDel. CoDel suit la latence minimale observée des paquets réseau et, si celle-ci dépasse une valeur seuil, il commence à supprimer les paquets. La suppression d'écritures est désapprouvée dans le sous-système d'E / S, mais une stratégie similaire est suivie en ce que le noyau surveille la latence minimale des lectures et des écritures et, si cela dépasse une valeur de seuil, il commence à réduire la quantité d'écriture différée en arrière-plan cela se fait. Ce comportement a été ajouté en 4.10; Axboe a déclaré que de très bons résultats ont été observés.

WBT ne nécessite pas de basculer vers la nouvelle couche de blocs blk-mq. Cela dit, cela ne fonctionne pas avec les planificateurs d'E / S CFQ ou BFQ. Vous pouvez utiliser WBT avec les programmateurs de délai / mq-date limite / noop / aucun. Je crois que cela fonctionne également avec le nouveau planificateur d'E / S "kyber".

Outre la mise à l'échelle de la taille de la file d'attente pour contrôler la latence, le code WBT limite le nombre de demandes de réécriture en arrière-plan en proportion de la limite de file d'attente calculée.

La configuration d'exécution est en cours /sys/class/block/*/queue/wbt_lat_usec.

Les options de configuration de construction à rechercher sont

/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

Votre énoncé de problème est confirmé à 100% par l'auteur de WBT - bravo :-).

Bloc [PATCHSET]: limitation de l'écriture différée en mémoire tampon

Depuis la nuit des temps, notre écriture différée tamponnée en arrière-plan est nulle. Lorsque nous effectuons une réécriture tamponnée en arrière-plan, cela devrait avoir peu d'impact sur l'activité de premier plan. C'est la définition de l'activité d'arrière-plan ... Mais aussi loin que je me souvienne, les écrivains tamponnés lourds ne se sont pas comportés comme ça. Par exemple, si je fais quelque chose comme ça:

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

sur mon ordinateur portable, puis essayez de démarrer Chrome, il ne démarrera pas avant que la réécriture en mémoire tampon ne soit terminée. Ou, pour les charges de travail orientées serveur, où l'installation d'un gros RPM (ou similaire) a un impact négatif sur les lectures ou les écritures de synchronisation de la base de données. Lorsque cela se produit, des gens me crient dessus.

Les résultats de certains tests récents peuvent être trouvés ici:

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

Voir les articles précédents pour une plus grande description du jeu de patchs.

sourcejedi
la source
Je suis heureux de voir que le problème est reconnu et traité à l'intérieur du noyau maintenant. Gardez à l'esprit que blk-mq est assez récent et peut - être pas encore mature .
korkman
@korkman soupire, je suppose que je vais modifier la citation pour éviter la fausse implication. Je suis d'accord que ce sont des choses ajoutées au cours des deux dernières années, il peut toujours y avoir des régressions de performances ou pire. AFAIR le mainteneur rejette le correctif de corruption de données dans le sens où c'est un coup de chance. Si vous utilisez les versions du noyau où blk-mq a été développé, on peut se demander dans quelle mesure l'utilisation de la couche de blocs "héritée" évitera les bogues. Le bug de suspension que j'ai corrigé était un bug qui provenait de blk-mq, puis il a été refactorisé ou quelque chose et a affecté les deux. github.com/torvalds/linux/commit/1dc3039bc87a
sourcejedi
0

Quelle est votre moyenne pour Dirty in / proc / meminfo? Cela ne devrait normalement pas dépasser votre / proc / sys / vm / dirty_ratio. Sur un serveur de fichiers dédié, j'ai dirty_ratio réglé sur un pourcentage de mémoire très élevé (90), car je ne le dépasserai jamais. Votre dirty_ration est trop bas, quand vous le frappez, tout craque, élevez-le.

Luc
la source
Le problème n'est pas que les processus soient bloqués lors de la frappe de dirty_ratio. Je suis d'accord avec ça. Mais le processus "d'arrière-plan" écrit des données sales sur les disques remplit les files d'attente sans pitié et tue les performances IOPS. Cela s'appelle la famine IO je pense. En fait, la définition de dirty_ratio_bytes extrêmement bas (comme 1 Mo) aide beaucoup, car le vidage se produira presque immédiatement et les files d'attente resteront vides. L'inconvénient est peut-être un débit inférieur pour le séquentiel, mais ce n'est pas grave.
korkman
Vous avez éteint tous les ascenseurs? Qu'avez-vous modifié d'autre d'un système vanille?
Luke
1
Voir ma réponse personnelle. La fin de l'histoire était de supprimer la mise en cache sale et de laisser cette partie au contrôleur HW. Les ascenseurs sont un peu hors de propos avec le cache d'écriture HW en place. Le contrôleur possède ses propres algorithmes d'ascenseur, donc avoir n'importe quel ascenseur dans le logiciel ne fait qu'ajouter des frais généraux.
korkman
Elevevator dans le logiciel est un compromis: sacrifiez la latence pour améliorer la bande passante. Par exemple, imaginez 100 000 opérations d'écriture dans la file d'attente logicielle soumise dans un ordre aléatoire; si l'ascenseur logiciel peut commander ces opérations à l'aide d'un énorme tampon, il peut finir par n'envoyer que 5 000 demandes beaucoup plus importantes à l'appareil. Cependant, en conséquence, la latence doit être augmentée de 100 000 opérations, car il se peut que les premières 2 000 opérations et les dernières 1 000 opérations soient en fait proches l'une de l'autre sur le périphérique. Sans latence supplémentaire, il sera impossible de les fusionner.
Mikko Rantalainen