Le cache de réécriture (Writeback Cache) du noyau Linux contrôle le moment où les données modifiées sont enregistrées en tant que Pages sales restent en mémoire vive (RAM) et à quel moment le noyau les écrit par lots sur le support de stockage. Je vais vous expliquer comment ce processus Performance, les latences et la sécurité des données, et quels sont les paramètres qui comptent vraiment au quotidien.
Points centraux
- Pages sales marquent les pages modifiées en mémoire vive (RAM) qui ne sont pas encore enregistrées sur le support de données.
- Writeback regroupe les modifications et les enregistre efficacement par blocs plus importants.
- Valeurs seuils Tout comme vm.dirty_ratio, ces paramètres régulent la vitesse et la limitation.
- Synchronisation L'utilisation de fsync/Flush permet d'éviter toute perte de données.
- Suivi La section /proc et les outils affichent la charge et les temps de latence.
Fonctionnement du cache de pages
Je lis un fichier, le noyau place les données dans le cache de pages, et les accès ultérieurs s'effectuent à partir du Mémoire plutôt que depuis le disque. Lors de l'écriture, le système marque les pages modifiées comme Sale et acquitte souvent immédiatement l'appel afin que l'application continue de fonctionner. Ce découplage réduit les temps d'attente, car les accès E/S lents ne ralentissent pas directement chaque application. Le cache met également à disposition les blocs fréquemment utilisés et augmente le taux de réussite lors d'accès ultérieurs. Si vous souhaitez approfondir le sujet, vous trouverez des informations complémentaires dans mon aperçu sur Mise en cache du système de fichiers, qui met en évidence le rôle des chemins de lecture et d'écriture dans la vie quotidienne.
« Dirty Pages » : signification et conséquences
Les « Dirty Pages » sont des pages mémoire modifiées qui n'ont pas encore été sauvegardées de manière permanente et qui ne sont donc disponibles que dans le RAM existent. Tant qu'ils sont sales, je porte une certaine Risque: Une coupure de courant pourrait annuler ces modifications. Néanmoins, cela permet d'obtenir un taux d'écriture plus élevé, car le noyau regroupe de nombreuses petites mises à jour. Si la proportion de pages sales augmente, la pression sur les modules de réécriture s'accroît. Le système peut alors libérer de la mémoire en écrivant les pages concernées sur le disque en leur accordant la priorité.
Réintégration : déclencheurs et déroulement
La réinitialisation s'effectue de manière programmée, en fonction d'un événement ou sur demande Apps. Le noyau regroupe les pages sales, forme des séquences d'E/S appropriées et les transmet via la couche de blocs vers le périphérique de stockage. En cours de route, les systèmes de fichiers, les mécanismes de récupération d'espace et les planificateurs d'E/S interviennent pour contrôler l'ordre et la taille des opérations. Les appels de synchronisation tels que fsync garantissent que certaines données soient correctement enregistrées sur le support avant de poursuivre l'opération. Pendant les phases d'activité intense, j'observe dans les statistiques une part croissante de réécriture différée, qui redescend après le vidage.
Mécanismes internes : balance_dirty_pages, BDI et Writeback-Worker
En coulisses, plusieurs composants s'imbriquent les uns dans les autres. Les threads d'écriture parcourent balance_dirty_pages(), qui tient compte de la charge « dirty » actuelle, de la vitesse du périphérique et des limites définies. Il régule le débit d'écriture des processus (throttling) afin que la réécriture en arrière-plan puisse suivre. Chaque Dispositif de soutien-Contexte (bdi) – généralement un périphérique bloc ou un backend de système de fichiers – dispose de ses propres files d'attente de travail avec Fils de discussion « Flusher », qui transforment les « Dirty Pages » en requêtes d'E/S ordonnées. Cette répartition empêche un périphérique lent de ralentir tous les autres et améliore l'équité entre les charges de travail.
La limitation est adaptative : lorsque je détecte des opérations d'écriture plus rapides ou des blocs contigus plus volumineux, les quantités de données « sales » autorisées augmentent temporairement. En cas d'engorgements, de latences élevées ou de files d'attente saturées, le noyau freine plus agressivement et impose des pauses aux écrivains jusqu'à ce que le tampon soit à nouveau dégagé. C'est précisément cette interaction qui explique pourquoi de légères modifications des paramètres peuvent entraîner des profils de latence sensiblement différents.
Seuils : vm.dirty_background_ratio et vm.dirty_ratio
Je contrôle ce comportement à l'aide de deux limites importantes qui régulent la proportion de pages polluées par rapport au RAM définir. Si je dépasse la valeur de fond, le noyau commence à Contexte d'écriture. Si j'atteins la limite stricte, le système ralentit les processus d'écriture jusqu'à ce qu'une quantité suffisante de données ait été renvoyée. Ainsi, la mémoire reste utilisable, même si certains programmes génèrent de grandes quantités de modifications. Si vous travaillez avec des limites en octets, utilisez les paramètres *_bytes correspondants à la place des valeurs de ratio.
Tableau : paramètres du noyau et indicateurs pertinents
J'utilise quelques commutateurs centraux pour contrôler de manière ciblée et rendre visibles le writeback, la latence et le débit ; l'aperçu suivant aide à Classement et rapides Examen.
| Paramètre/indicateur | Effet | Valeurs par défaut / Remarque |
|---|---|---|
| vm.dirty_background_ratio / vm.dirty_background_bytes | Lance la réécriture en arrière-plan lorsque la proportion de pages corrompues dépasse ce seuil. | Pour les serveurs, optez pour un réglage plutôt prudent afin que le flush se déclenche plus tôt. |
| vm.dirty_ratio / vm.dirty_bytes | Limite maximale pour les « dirty pages » ; à partir de ce seuil, les écritures sont limitées. | Si elle est trop élevée, elle augmente les risques liés à la latence ; si elle est trop faible, elle réduit le débit. |
| vm.dirty_writeback_centisec | Intervalle pendant lequel le noyau vérifie les pages sales en vue d'un vidage en arrière-plan. | Des intervalles plus courts atténuent les pics de charge, mais génèrent davantage de réveils. |
| vm.dirty_expire_centisecs | Âge à partir duquel les „ Dirty Pages “ sont considérées comme « mûres » et font l'objet d'une attention particulière lors de la rédaction. | Des valeurs plus élevées renforcent l'agrégation, mais réduisent les garanties de cohérence en cas d'erreur. |
| /proc/meminfo : Dirty, Writeback | Nombre actuel de pages souillées ou activement réécrites. | Utile pour l'observation en temps réel lors des tests de charge. |
| Options de montage/FS (par exemple, barrières, mode journal) | Influencent l'ordre, la persistance et le coût des différentes opérations de vidage. | Faites votre choix en fonction du système de fichiers et du périphérique. |
Je relève régulièrement ces valeurs et je les mets en corrélation avec les temps d'attente d'E/S dans Top, iostat ou d'autres outils similaires. Outils. Cela permet de déterminer clairement si c'est Writeback lui-même qui est à l'origine de la limitation ou si c'est le Stockage est à la limite.
Suivi et diagnostic : ce que je mesure
Je commence par consulter le fichier /proc/meminfo et j'observe les champs « Dirty » et « Writeback » tout en effectuant de manière ciblée Dernier génère. Lorsque les « dirty » montent fortement et restent élevés, il manque souvent des « flushes » opportuns ou le Moyen est saturé. Si le « writeback » augmente mais que le « dirty » ne diminue que lentement, cela ralentit le périphérique cible ou le chemin d'E/S. Si les pics de latence coïncident avec les pics de « writeback », je lisse l'intervalle ou je réduis les valeurs de ratio. Pour me familiariser avec les schémas typiques, un bref Optimiseur de cache de page, qui répertorie les vis de réglage et les points de mesure.
Points de mesure avancés, vmstat et traçage
Outre /proc/meminfo, j'utilise des compteurs très précis pour distinguer la cause de l'effet. Dans /proc/vmstat Des champs tels que nr_dirty, nr_writeback, nr_dirtied et nr_written fournissent des indications sur la dynamique : à quelle vitesse les données sont-elles « salies », à quelle vitesse sont-elles « nettoyées » ? En complément, j'observe la longueur des files d'attente d'E/S et les taux d'échec des opérations de fusion dans la couche de blocs.
- vmstat 1 : affiche par seconde la dérive des opérations « dirty/writeback » et le temps d'attente d'E/S (wa),
- /proc/pressure/memory : indique la pression mémoire qui déclenche indirectement le « writeback »,
- Points de trace (writeback:*) et événements de bloc : révèlent l'ordre et la taille des vidages,
- perf/ftrace : identifie les points chauds dans balance_dirty_pages et les files d'attente de travail de Flusher.
Si je constate que la valeur « nr_dirtied » reste systématiquement supérieure à « nr_written », c'est un signe clair d'un risque imminent de limitation de débit ou de vidages en arrière-plan effectués trop tardivement. Si les pics observés au niveau des points de trace de réécriture coïncident avec des pics de latence, j'optimise l'intervalle et la taille des lots.
Disque dur (HDD) vs SSD : implications pour la conception du « writeback »
Sur les rouleaux, les grandes séries consécutives sont particulièrement rentables, car elles évitent les recherches coûteuses éviter. Les SSD en bénéficient également, mais ce qui compte ici, c'est la répartition des écritures et l'interaction avec le Contrôleur. J'évite les synchronisations trop fréquentes afin que le micrologiciel puisse fonctionner efficacement. Parallèlement, je porte davantage attention aux barrières de cohérence et à la sémantique de vidage sur les SSD afin de tirer pleinement parti des garanties offertes par le périphérique. Les charges de travail mixtes, comprenant des lectures et des écritures aléatoires, réagissent de manière perceptible aux petits ajustements des seuils de données sales et du timing de vidage.
Cache de l'appareil, sémantique de vidage et protection contre les coupures de courant (PLP)
La persistance effective d'un flush dépend également de Cache de l'appareil . De nombreux disques durs mettent les données en mémoire tampon dans leur propre DRAM. Sans Protection contre les pertes de puissance (PLP) Je risque une perte de données si le cache n'est pas vidé à temps. Le « writeback » tire certes parti du cache du périphérique, mais je m'assure que les barrières et les commandes de vidage soient respectées. Sur les systèmes équipés de contrôleurs RAID, je vérifie s’il existe un cache alimenté par batterie ou par mémoire flash ; dans ce cas, les écritures synchronisées sont souvent plus avantageuses, sans compromettre la sécurité.
Je fais également la distinction suivante : le FUA (Force Unit Access) impose la persistance à chaque opération d'E/S, mais cela a un coût en termes d'IOPS. Les barrières de vidage peuvent sécuriser plusieurs écritures simultanément. Pour les chemins particulièrement critiques (comme les journaux), j'accepte la surcharge liée au FUA et au flush, tandis que je laisse les données en masse dans le flux de réécriture différée. Quiconque modifie les options de montage ou les paramètres du contrôleur doit ensuite vérifier, à l'aide de tests de charge, que la sémantique de vidage prévue fonctionne correctement.
Cohérence des données : utiliser correctement fsync, Flush et FUA
J'utilise fsync de manière ciblée pour les données présentant un volume élevé Valeur, qui ont besoin d'une garantie claire de durabilité. Le noyau peut propager les opérations de vidage jusqu'au support et, grâce à la FUA, s'assurer qu'une écriture est bel et bien persiste, avant que la confirmation ne revienne. Cette approche prend du temps et consomme des IOPS, mais elle évite la perte de données en cas de plantage. Sans ces barrières, le système signale les opérations comme réussies alors que les octets se trouvent encore dans le cache du SSD ou dans la mémoire vive. J'adapte ces choix en fonction de l'application : sauvegarde « dure » pour les journaux de transactions, « souple » pour les mises à jour en masse.
Exemples d'optimisation pour les charges de travail liées à l'hébergement et aux bases de données
Pour les serveurs Web et les serveurs de bases de données, je définis souvent une valeur modérée pour `dirty_background_ratio` et je maintiens `dirty_ratio` nettement au-dessus afin d'assurer un vidage en arrière-plan en temps voulu. démarrer, sans que Schreiber ne soit trop tôt à freins. Lors de pics d'écriture, je réduis l'intervalle de réécriture afin que les mécanismes de réécriture se déclenchent plus tôt. Sur les systèmes dotés d'une grande quantité de RAM, je privilégie les valeurs *_bytes afin d'utiliser des quantités réelles plutôt que des pourcentages. Je teste chaque modification à l’aide de benchmarks reproductibles et je mesure la latence, le débit ainsi que les 95e et 99e centiles. Cet aperçu pratique me fournit un guide concis sur l’impact du cache de page : Optimisation des performances du cache de pages sous Linux.
Direct I/O et mmap : lorsque le cache de pages est contourné
Toutes les applications n'utilisent pas le cache de page de la même manière. Avec O_DIRECT elle peut contourner délibérément le cache et écrire ou lire directement dans le périphérique. Cela soulage la mémoire vive et raccourcit les chemins d'accès, mais me prive des avantages du traitement par lots et de la lecture anticipée. Cela peut s'avérer utile pour les transferts volumineux et ponctuels ; en revanche, pour de nombreuses petites écritures, je perds les avantages du « writeback ».
Avec mmap et avec le « Copy-on-Write », je marque les pages comme « sales » lorsqu'elles sont modifiées ; la mise à jour s'effectue via le chemin de réécriture normal ou par msync. J'en tiens compte lorsque les applications s'appuient fortement sur les E/S en mémoire : des pics de données non validées peuvent survenir de manière inattendue, même si l'application „ ne fait que “ modifier la mémoire. Là encore, la définition de limites de ratio ou d'octets permet de contrôler le moment de la réécriture.
Environnements de conteneurs et « writeback » des cgroups
Dans les configurations multi-locataires, j'évite les „ voisins bruyants “ grâce à cgroups. Le noyau attribue les pages sales au groupe à l'origine de leur modification (cgroup-Writeback), ce qui permet une répartition plus équitable du vidage en arrière-plan et de la limitation du débit. Grâce à des limites de mémoire (memory.high, memory.max), je limite les pics de mémoire « sale » par conteneur. De plus, je définis des quotas d'E/S via le contrôleur d'E/S afin d'empêcher que certaines charges de travail ne saturent la file d'attente du périphérique.
Dans la pratique, je définis des limites maximales réalistes pour chaque classe de service : les tâches batch gourmandes en écriture se voient attribuer des « dirty budgets » généreux, tandis que les frontends sensibles à la latence en ont des plus restreints. La latence globale reste ainsi plus stable, car le « writeback » ne limite pas brusquement le débit pour tous les conteneurs dès qu’un seul d’entre eux déraille.
Systèmes de fichiers réseau (NFS, SMB, systèmes de fichiers distribués)
Dans le cas des systèmes de fichiers en réseau, un niveau de mise en mémoire tampon supplémentaire intervient. Les pages modifiées locales indiquent simplement que des données sont en cours de transfert ; quant à savoir si elles à distance C'est le protocole (sémantique de validation) et le serveur qui décident si les données ont été validées. Je ne me fie pas aux vidages implicites : je synchronise explicitement les données critiques. Dans le même temps, je tiens compte des coûts liés aux allers-retours : des synchronisations trop fréquentes sur le réseau aggravent sensiblement les latences.
Dans les charges de travail mixtes, je sépare les chemins d'accès : les fichiers locaux et temporaires tirent pleinement parti du cache de pages ; les montages réseau bénéficient de points de synchronisation plus stricts. J'évite ainsi que la réécriture via le réseau ne devienne un goulot d'étranglement, alors que les tâches locales disposeraient encore de réserves.
Planificateur d'E/S, blk-mq et profondeur de file d'attente
L'efficacité avec laquelle les lots de réécriture sont transférés vers l'appareil dépend également de Blocklayer à partir de. Avec blk-mq Les E/S sont réparties sur plusieurs files d'attente ; des planificateurs tels que mq-deadline ou kyber établissent des priorités et organisent les opérations. Je choisis le planificateur en fonction du support : sur NVMe, „ none “ est souvent judicieux, tandis que sur SATA ou SAS, Deadline facilite l'organisation des écritures.
Le Profondeur de la file d'attente Je le définis de manière à ce que l'appareil soit sollicité à pleine capacité, mais sans être surchargé. Une profondeur trop faible réduit le débit, tandis qu'une profondeur trop importante augmente la dispersion de la latence et rend la limitation de débit plus difficile. Le „ writeback “ tire profit de profondeurs modérées et de requêtes volumineuses et contiguës. Je surveille les taux de fusion et les compteurs « inflight » ; une baisse des taux de fusion indique que les lots sont trop petits ou qu’il y a des charges de travail aléatoires concurrentes.
Tests reproductibles et restauration en toute sécurité
Avant de régler les commandes, je note l'état actuel, je vérifie reproductible et je prévois des retours en arrière. J'utilise des charges de travail identiques, des volumes de données identiques, et je préchauffe le cache de manière ciblée ou je le vide délibérément afin de garantir la comparabilité des tests. Je définis d'abord les modifications de paramètres de manière temporaire, j'observe les métriques, puis je ne les enregistre de manière définitive qu'ensuite.
# Exemple : réglages temporaires (Root)
sysctl -w vm.dirty_background_bytes=$((512*1024*1024))
sysctl -w vm.dirty_bytes=$((2*1024*1024*1024))
sysctl -w vm.dirty_writeback_centisecs=100
sysctl -w vm.dirty_expire_centisecs=3000
# Test de charge court (exemple, en fonction de la charge de travail)
# fio --name=wbtest --filename=/data/testfile --size=8G --ioengine=libaio \
# --rw=randwrite --bs=128k --iodepth=32 --direct=0 --numjobs=4 --runtime=60 --time_based
Pendant ce temps, je lis en parallèle les fichiers /proc/meminfo, vmstat et iostat et je mets en corrélation les pics. Une fois le test terminé, je réinitialise les valeurs ou je les intègre de manière contrôlée dans la configuration du système. Pour cela, je documente Date, Noyau- la version, les informations relatives à l'appareil et au système de fichiers, afin que les comparaisons ultérieures restent fiables.
Problèmes courants et solutions
Si le système semble fonctionner de manière fluide, mais que les opérations d'écriture sont ralenties, je vérifie s'il y a un ralentissement dû à une valeur trop faible de dirty_ratio. Si le niveau de « dirty » reste élevé, cela signifie qu'il y a un manque de bande passante ou que le Intervalle Le délai jusqu'au flush est trop long. Lorsque les latences explosent lors de brèves rafales de synchronisation, je répartis la charge en lots plus petits et j'optimise la planification des E/S. Si le cache peine à se mettre en route, une limite *_bytes trop faible empêche peut-être un regroupement en lots efficace. Un examen plus approfondi de Éviction du cache lors de l'impression cela aide lorsque le manque d'espace de stockage vient s'ajouter aux difficultés.
Bonnes pratiques et petite liste de contrôle
Je fais une distinction stricte entre les données qui doivent être enregistrées immédiatement et celles dont la persistance peut être différée, afin de Performance à gagner. Pour les journaux et les journaux de transactions, j'impose des synchronisations ; pour les artefacts temporaires, je laisse le « writeback » fonctionner librement et je ne surveille que la limite de régulation. Avant chaque ajustement, je mesure l’état actuel et je compare les résultats A/B à l’aide de scénarios définis. Je limite le nombre d’écrivains simultanés, car des flux non coordonnés réduisent l’intérêt du traitement par lots. Et je documente immédiatement les modifications afin que les analyses futures puissent s’appuyer sur des données claires Données basée.
Résumé pratique pour une réussite rapide
Le cache de réécriture regroupe les modifications apportées au Page Le cache réduit les coûts d'E/S et allège la charge des applications. Les pages sales ne constituent pas une erreur, mais un moyen ciblé de gagner en vitesse, à condition de connaître les limites et les exigences de cohérence. Grâce aux paramètres vm.dirty_background_ratio et vm.dirty_ratio, je peux contrôler quand le noyau travaille discrètement en arrière-plan et quand il freine les opérations d'écriture. Les outils et le répertoire /proc me fournissent la visibilité nécessaire sur les pages sales et les réécritures, afin que je ne sois pas dans le flou. Lorsque je maîtrise ces leviers, le Web, les bases de données et les tâches par lots fonctionnent nettement plus rapidement, sans que cela n’affecte la Intégrité de compromettre la sécurité de mes données.


