Azure Native Qumulo Maintenant disponible dans l'UE, au Royaume-Uni et au Canada - En savoir plus

Transfert de données déchargées du stockage Windows (ODX) et le cas de la prélecture manquante

Rédigé par:
Comment un client a connu des performances plus lentes que prévu en comparant READ/WRITE standard à ODX - et comment l'équipe d'ingénierie a tiré parti des métriques de Qumulo Core, du cycle de publication rapide et de l'expérience de mise à niveau transparente pour découvrir et résoudre le mystère !

Comment un client a connu des performances plus lentes que prévu en comparant READ/WRITE standard à ODX - et comment l'équipe d'ingénierie a tiré parti des métriques de Qumulo Core, du cycle de publication rapide et de l'expérience de mise à niveau transparente pour découvrir et résoudre le mystère !

Qu'est-ce qu'ODX (Windows Storage Offloaded Data Transfer) ?

Windows Storage Offloaded Data Transfer (ODX) fait partie du protocole SMB (Server Message Block) où vous pouvez dire au système de fichiers Qumulo de copier un morceau d'un fichier d'un fichier à un autre sans envoyer les données via la machine cliente. ODX améliore les performances de copie un peu comme la copie côté serveur (SSC). Il élimine la latence du réseau entre le client et le serveur et permet à Qumulo Core d'optimiser la taille et la mise en mémoire tampon des E/S. En comparant ODX contre SSC, nos résultats de tests internes montrent qu'ODX est 7 fois plus rapide et SSC 4 fois plus rapide que la séquence READ/WRITE typique qui se produit lors de la copie d'un fichier vers un autre emplacement sur le même serveur.

Lire le mystère de la latence

En 2021, nous avons fourni le support ODX pour Qumulo Core version 3.0.0 ou supérieure. Peu de temps après l'expédition, un client a signalé que les performances d'ODX étaient plus lentes que prévu.

Sachant qu'ODX lit à partir d'un fichier et écrit dans un autre, nous avons d'abord soupçonné que les performances d'écriture étaient le problème. En règle générale, les opérations de lecture prennent au maximum quelques millisecondes (merci Mise en cache et prélecture SSD!). Pourtant, lorsque nous avons regardé le latence de lecture, nous avons vu qu'il s'agissait d'une plus grande partie de la latence ODX que ce à quoi nous nous attendions - de l'ordre de 25 ms (environ), avec des pics plus élevés à 40 ou 50 ms. Qu'est-ce qui se passe avec ça? Voici une visualisation de la durée de vie de la phase de lecture d'une opération ODX :

Nous avons examiné nos données de performances de séries temporelles à faible granularité que nous collectons via notre pipeline de surveillance cloud. En moyenne, notre taux de réussite du cache RAM et nos mesures de latence semblaient bonnes. Mais alors pourquoi les lectures spécifiques à ODX étaient-elles généralement lentes ?

Le premier indice

Au fur et à mesure que nous nous rapprochions de la découverte de la cause première, nous avions besoin de mesures de granularité plus élevées spécifiques à une seule charge de travail ODX sur ce cluster, sans le bruit des autres opérations. Heureusement, nous avons un outil, appelé trigger</var/www/wordpress>, which we built internally, which collects this kind of distributed performance data when needed. We worked with our customer to profile some specific ODX sequences, and used trigger</var/www/wordpress> to collect data during those sequences. We learned a couple of things. (Refer to Figure 1, above.)

Dans chaque opération de lecture, la plupart des blocs étaient dans le cache RAM, mais chaque lecture manquait de cache pour quelques blocs. Lorsque cela se produit, la transaction du système de fichiers doit lire les données des périphériques de stockage eux-mêmes. Dans ce cas, les métriques nous ont indiqué que les données se trouvaient sur des disques en rotation.

[type de boîte = "ombre"]Remarque: Dans mon esprit, je pensais "bien sûr, ça devait être les disques qui tournaient... c'est TOUJOURS les disques qui tournent. J'aurais dû savoir que les recherches sont la seule chose qui aurait pu pousser la latence jusqu'à 50 ms. Les disques qui tournent et moi n'avons pas la meilleure relation. Ils ont l'habitude exaspérante mais utile d'exposer douloureusement les comportements involontaires dans les chemins de code sensibles aux performances.[/box]

Les disques rotatifs peuvent diffuser efficacement des données lorsque les requêtes sont mises en file d'attente dans un ordre contigu ; commençant au début d'un fichier et lisant jusqu'à la fin. Cependant, dans ce cas, il ne nous manquait que quelques blocs du cache par opération de lecture ODX, ce qui se traduit par un disque en rotation avec de nombreuses lectures non contiguës. C'est une mauvaise nouvelle pour la latence du disque en rotation.

Normalement, les opérations de lecture du système de fichiers ne subissent pas ce type de latence de disque en rotation, car nous disposons d'un prefetcher efficace. Le prefetcher devine ce qui va être lu ensuite et le charge dans le cache à l'avance. Le prefetcher a un modèle d'E/S optimisé pour lire à partir de disques en rotation.

Alors, pourquoi le prefetcher ne fonctionnait-il pas ?

Notre prefetcher a des métriques qui décrivent son succès en moyenne. Ces métriques nous ont indiqué que tout ce qui était prérécupéré était lu, mais certaines données lues par le système de fichiers n'étaient pas prérécupérées… c'est vraiment bizarre ! Peut-être que les opérations ODX lisent dans le désordre ou sautent au hasard ? Le prefetcher ne fonctionne pas bien avec les IO aléatoires.

Nous avons vérifié les journaux d'opérations pour voir le modèle d'E/S. Les journaux d'opérations sont un outil de fichier journal texte qui nous fournit des informations sur chaque opération, telles que le décalage, la taille et le succès ou l'échec du cache. Cependant, nous n'avions pas prévu que nous aurions besoin des tailles et des décalages de lecture ODX dans nos journaux d'opérations, et par conséquent, ce code n'avait pas été connecté ! Nous avons donc dû écrire du code supplémentaire et attendre une mise à jour…

Trouver le coupable

En quelques semaines, nous avions expédié un nouveau code et, grâce à nos mises à niveau super impressionnantes, le client a pu mettre à niveau son système de stockage Qumulo vers la dernière version peu de temps après. Ils ont relancé la charge de travail de test pour nous. En utilisant la journalisation des opérations améliorée, nous avons trouvé un autre casse-tête ! En lisant les journaux d'opérations (j'avais l'impression d'être dans la matrice en train de lire les chiffres verts), nous avons constaté que notre code de protocole ODX envoyait au système de fichiers des demandes de lecture contiguës de 8650752 octets chacune. Lorsque nous avons fait le calcul, cela donne 8 mébioctets + 256 Kio. Mais! Le journal des opérations a montré que chaque requête ODX n'obtenait en réalité que 8388608 octets du cache (exactement 8 mégaoctets).

Je me souviens qu'au début j'avais les yeux vitreux… est-ce que j'avais mal lu les chiffres ? Comment chaque requête manque-t-elle de cache pour seulement 256 Kio sur les 8 Mio demandés ? Comment le prefetcher ne récupère-t-il qu'un sous-ensemble de chaque requête ? C'est impossible!

[type de boîte = "ombre"]Remarque: La première étape de chaque bogue est le déni - croire que les données sont fausses. Heureusement, ce n'était pas mon premier rodéo. J'ai rapidement étouffé mon déni, et j'ai commencé à me demander « comment est-ce possible » ?[/box]

J'ai commencé à expliquer le fonctionnement du prefetcher à mon collègue qui travaillait avec moi sur l'enquête. Le prefetcher doit devancer la charge de travail de lecture, de sorte que la taille des E/S de la charge de travail de lecture n'a pas d'importance. Le prefetcher récupère toujours les données en gros morceaux et de telle sorte que la file d'attente sur les disques en rotation soit bien ordonnée pour éviter les recherches. Et ensuite ça m'a frappé…gros morceaux… Quelle est la taille des morceaux de prélecture ? OH… ils font 8 MiB… attendez, c'est effrayant. Et comment devance-t-il la charge de travail de lecture ? OH, nous lançons une prélecture par requête de lecture… attendez… en assemblant ces deux choses… si nous ne lançons qu'une seule prélecture par requête de lecture, et que la taille du bloc de prélecture est d'au plus 8 MiB, et que le lecteur lit des blocs de 8 MiB + 256KiB… alors oui, évidemment, le prefetcher n'avancera jamais… il prélèvera toujours les 8MiB suivants, laissant une queue de 256KiB non mise en cache. WOW . (Poing en l'air). D'accord. Nous avons trouvé le pistolet fumant.

Exemples d'illustrations du problème de prélecture

Mystère expliqué

Comprendre le bogue n'est que le début. Trois questions me sont immédiatement venues à l'esprit :

  1. Pourquoi ce même problème ne se produit-il pas dans nos tests de lecture de système de fichiers standard ?
  2. Pourquoi ODX utilise-t-il une taille d'E/S de 8 Mio + 256 Kio, supérieure à la taille d'E/S maximale du préchargeur, et
  3. Pourquoi nos tests de performances spécifiques à ODX n'ont-ils pas détecté cela ?
1. Pourquoi ce problème ne se produit-il pas dans nos tests de performances de lecture de système de fichiers standard ?

Notre planificateur de protocole de système de fichiers traite toutes les demandes de protocole. La taille typique de la demande de protocole est de 1 Mo. Lorsque nous recevons des demandes de lecture de protocole, nous les traitons et combinons éventuellement les demandes pour optimiser les performances de lecture. Nous avons naturellement une taille d'E/S combinée maximale pour ces demandes de système de fichiers. Si vous laissez la taille d'E/S devenir trop grande, la demande peut être bloquée sur une grande chose à un seul thread qu'elle faisait (par exemple, CPU, allocation de mémoire). Ainsi, notre planificateur de système de fichiers rend la demande de lecture combinée maximale de 8 Mo, identique à la taille d'E/S maximale de notre préchargeur. C'était voulu. Ainsi, dans ces charges de travail, le préchargeur précharge tout, bien qu'il n'obtienne jamais plus de 8 Mo d'avance si la taille d'E/S combinée est également de 8 Mo…(se gratte la tête...ce n'était pas non plus un comportement intentionnel...).

2. Pourquoi ODX utilise-t-il une taille d'E/S de 8 Mio + 256 Kio ?

L'opération ODX elle-même passe par le planificateur, mais ne fait pas passer sa demande de lecture interne par le planificateur. ODX définissait alors la taille de lecture d'E/S maximale qu'il demanderait, indépendamment du planificateur.

Nous avons constaté que la taille maximale des E/S du planificateur et la taille maximale des E/S ODX utilisaient des fonctions différentes :

fs_target_transaction_size()
fs_max_transaction_size()</var/www/wordpress>

Le planificateur utilisait fs_target_transaction_size</var/www/wordpress>, which is a minimum of fs_max_transaction_size</var/www/wordpress> and 8MiB! Whereas the ODX code was intuitively using fs_max_transaction_size</var/www/wordpress> - which is computed, and turned out to be 8MiB + 256KiB.

Il y avait donc notre cause première. Nous avons corrigé le code du protocole ODX à utiliser fs_target_transaction_size</var/www/wordpress>, and voilà, no more uncached tails to the read requests.

3. Pourquoi nos tests de performance d'ODX n'ont-ils pas détecté cela ?

Nos tests de performances ODX fait, en fait, présentent le comportement des queues non mises en cache. Mais, la performance n'était pas si mauvaise; car, dans ce test de performances, les données étaient suffisamment petites pour tenir dans le cache SSD !

En regardant en arrière Figure 1 (ci-dessus), vous pouvez voir que la latence des lectures à partir du SSD est bien inférieure à celle du disque en rotation. Il n'était donc pas aussi évident d'après les résultats des tests de performance que le prefetcher faisait la mauvaise chose. Le test ne vérifiait pas explicitement les métriques du prefetcher.

Une fois que nous avons modifié le test de performances pour effectuer une deuxième étape consistant à expulser les données du SSD, puis à les relire à partir du disque en rotation, les performances de la ligne de base étaient bien pires qu'elles n'auraient dû l'être, révélant le bogue. Nous avons corrigé le bogue, constaté l'amélioration de ce test de performance automatisé et expédié l'amélioration en 2 semaines. Tirant à nouveau parti de Qumulo mises à niveau faciles, nos clients ont pu effectuer la mise à niveau peu de temps après le correctif et bénéficier des performances ODX améliorées.

Apprendre encore plus

Articles Similaires

Remonter en haut