Limiter la bande passante d'une VM pour tester des commandes BPF

En lisant le livre BPF Performance Tools de Brendan Gregg, j’ai eu envie de tester les nouveaux outils disponibles.

En particulier, j’ai voulu voir si des problèmes de saturation disque pouvaient être détectés avec biosnoop, biotop, biolatency et/ou bitesize. Dans cet article, on verra comment configurer une VM VirtualBox pour essayer ces outils.

Le protocole de test

Le protocole de test sera très simple. Il s’agira du lancement d’une application web Java tout ce qu’il y a de plus standard (Spring PetClinic). Avant le lancement de l’application, une commande bio* sera exécutée pour le surveiller.

Le protocole de test sera joué deux fois. Une fois sur une machine non bridée. Une fois sur une machine pour laquelle la bande passante du disque est limitée à 1 Mo/s.

Le setup

En utilisant l’outil VBoxManage de VirtualBox, il est possible d’accéder à beaucoup plus de paramètres que ceux disponibles dans l’interface graphique.

Ici, on va s’intéresser plus particulièrement aux commandes VBoxManage storageattach et VBoxManage bandwidthctl. Avec bandwidthctl, on va créer une limite à la bande passante disque utilisable par une VM. Avec storageattach, on va associer le disque dur d’une VM à la limite précédemment créée.

Les deux commandes listées ci-dessous doivent être exécutées quand la VM est éteinte.

Je dispose d’une VM nommée Archlinux. Elle a un unique disque dur sur lequel tous les fichiers sont stockés (OS, /home et /boot, restons simples). Tout d’abord, il faut créer une limite. On la dimensionnera très largement pour être sur qu’elle ne ralentit pas le démarrage de la VM. Car oui, j’ai essayé avec une valeur de base à 1 Ko/s, Grub a mis plusieurs minutes pour pouvoir charger ses propres fichiers.

VBoxManage bandwidthctl Archlinux add "Disk bandwidth limit" --type disk --limit 1000M

Ensuite, il faut associer le disque dur de la VM à cette limite.

VBoxManage storageattach Archlinux --storagectl "SATA" --port 0 --bandwidthgroup "Disk bandwidth limit"

Pour démarrer l’application, un simple java -jar target/*.jar suffira. Entre deux redémarrages, il sera nécessaire de vider le cache Linux avec echo 3 | sudo tee /proc/sys/vm/drop_caches. On pourra également vérifier que le jar principal n’est pas en cache avec la commande vmtouch.

Test sans limitation

Avant de lancer l’application, on vérifie que le jar de petclinic n’est pas en cache.

[alarm@archlinux ~]$ vmtouch -v ./spring-petclinic/target/*.jar
./spring-petclinic/target/spring-petclinic-2.2.0.BUILD-SNAPSHOT.jar
[                                                            ] 0/11643

           Files: 1
     Directories: 0
  Resident Pages: 0/11643  0/45M  0%
         Elapsed: 0.000353 seconds

Lorsque l’application est lancée, on peut voir que le processus java charge plusieurs dizaines de Mo depuis le disque. Cela correspond non seulement à l’uberjar mais également à tous les fichiers dont la JVM a besoin, y compris le fichier rt.jar. Ces I/O sont réalisées avec une latence excellente (<1 ms en moyenne).

[alarm@archlinux ~]$ sudo biotop -C -r 10
Tracing... Output every 1 secs. Hit Ctrl-C to end

[...]
22:44:29 loadavg: 0.22 0.35 0.35 4/159 4093

PID    COMM             D MAJ MIN DISK       I/O  Kbytes  AVGms
4076   java             R 8   0   sda        497 31376.0   0.49
4076   C2 CompilerThre  R 8   0   sda         22  1632.0   0.59
4076   bash             R 8   0   sda         14   696.0   0.39
4076   C1 CompilerThre  R 8   0   sda          6   348.0   0.44
509    bash             R 8   0   sda          3   140.0   2.28

22:44:30 loadavg: 0.37 0.38 0.36 4/163 4097

PID    COMM             D MAJ MIN DISK       I/O  Kbytes  AVGms
4076   java             R 8   0   sda        640  8792.0   0.48
4076   background-prei  R 8   0   sda        165  2044.0   0.51
4076   C2 CompilerThre  R 8   0   sda          1   124.0   0.57

22:44:31 loadavg: 0.37 0.38 0.36 4/162 4098

PID    COMM             D MAJ MIN DISK       I/O  Kbytes  AVGms
4076   java             R 8   0   sda        391  4100.0   0.52
4076   background-prei  R 8   0   sda        254  3908.0   0.49
4076   Thread-0         R 8   0   sda         37   316.0   0.45

22:44:32 loadavg: 0.37 0.38 0.36 4/162 4098

PID    COMM             D MAJ MIN DISK       I/O  Kbytes  AVGms
4076   java             R 8   0   sda        313  3480.0   0.59

Une fois l’application stoppée, on peut constater que le jar est bien dans le FS cache. On peut donc au choix utiliser vmtouch -e ou bien echo 3 | sudo tee /proc/sys/vm/drop_caches pour l’en supprimer. Puisqu’on veut avoir le plus d’I/O possible, je choisis de vider entièrement le cache.

[alarm@archlinux ~]$ vmtouch -v ./spring-petclinic/target/*.jar
./spring-petclinic/target/spring-petclinic-2.2.0.BUILD-SNAPSHOT.jar
[ooooOooOooooOoOoOOOOOOooooOooOOooooooooOooooooooooOooooooOoO] 8777/11643

           Files: 1
     Directories: 0
  Resident Pages: 8777/11643  34M/45M  75.4%
         Elapsed: 0.000901 seconds

Test avec limitation

Cette fois, je choisis de limiter la bande passante disque à 1 Mo/s. J’ai essayé avec des valeurs plus faibles mais cela figeait parfois la VM. Il semble que le bruit de fond soit suffisant pour parfois atteindre cette limite. Quoi qu’il en soit, 1 Mo/s est une bonne limite sachant que le jar de PetClinic fait 45 Mo.

J’exécute donc la commande ci-dessous.

VBoxManage bandwidthctl Archlinux set "Disk bandwidth limit" --limit 1M

Cette fois, le résultat est bien différent. Je constate déjà un temps de chargement beaucoup plus long de l’application. Sans l’avoir formellement mesuré, je peux déjà affirmer que la limitation de bande passante fonctionne bien.

Mais c’est surtout la sortie de biotop qui est révélatrice. On voit bien que le processus java ne peut pas lire les données plus rapidement que 1 Mo/s. Mais en plus, on constate que pour lire ce Mo, la latence moyenne est située entre 50 et 100ms. Soit entre 50x et 100x plus que comparé au premier run.

On voit donc comment détecter une saturation disque avec biotop.

[alarm@archlinux ~]$ sudo biotop -C -r 10
Tracing... Output every 1 secs. Hit Ctrl-C to end

[...]
22:32:14 loadavg: 0.49 0.43 0.27 2/138 3933

PID    COMM             D MAJ MIN DISK       I/O  Kbytes  AVGms
3932   java             R 8   0   sda          9  1060.0 110.47

22:32:15 loadavg: 0.49 0.43 0.27 2/138 3933

PID    COMM             D MAJ MIN DISK       I/O  Kbytes  AVGms
3932   java             R 8   0   sda         17  1020.0  59.48

22:32:16 loadavg: 0.49 0.43 0.27 7/138 3933

PID    COMM             D MAJ MIN DISK       I/O  Kbytes  AVGms
3932   java             R 8   0   sda         11   996.0  90.63

22:32:17 loadavg: 0.49 0.43 0.27 6/143 3938

PID    COMM             D MAJ MIN DISK       I/O  Kbytes  AVGms
3932   java             R 8   0   sda         16   980.0  62.48

Quelques surprises

J’avais initialement prévu de tester trois autres commandes. Mais cela n’a pas été possible.

La commande biosnoop liste chaque ouverture de fichier. Au chargement d’une JVM, cela représente bien trop de bruit pour être utilisable.

La commande bitesize indique la taille des I/O demandées par l’application. Elle ne prend pas en compte la bande passante effectivement disponible pour ces I/O. Elle s’adresse dont à une autre problématique.

Pour finir, la commande biolatency était intéressante mais elle met l’accent sur la latence disque, comme son nom l’indique. Dans le listing précédent, on voit que la latence est plus élevée. Mais s’agissant d’un problème de bande passante avant tout, je pense que biotop est plus adapté.

Pour aller plus loin

La commande VBoxManage bandwidthctl peut également être appliquée sur une carte réseau. Ce sera l’occasion de tester d’autres nouveaux outils comme soconnect et détecter des congestions.

Le livre BPF Performance Tools regorge de nouveaux outils. Je suis curieux de voir comment des cas d’étude peuvent être créés en totale isolation pour expérimenter chacun de ces outils.


Si vous avez des questions ou voulez me faire part de vos commentaires, envoyez moi un tweet (@pingtimeout). Et si vous avez apprécié cet article et voulez soutenir mon travail, vous pouvez toujours m’offrir un café sur BuyMeACoffee ☕️.