Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Performance et diagnostic - Méthodologie et outils

Performance et diagnostic - Méthodologie et outils

Notions & méthodologie
Etat des lieux rapide sur une machine Linux
Outils et diagnostic plus avancés
Zoom sur une JVM
Spécificités avec Docker

Vladislav Pernin

November 12, 2023
Tweet

More Decks by Vladislav Pernin

Other Decks in Technology

Transcript

  1. •Allo Houston : ça marche pas - c’est lent …

    •Comment faire et ne pas faire
  2. Qui suis-je ? • Vladislav Pernin • 17 ans d’expérience

    • CTO du pôle Nex’us de la DSI d’Enedis
  3. Allo Houston : ça marche pas - c’est lent …

    • Comment procéder ? • Notions & méthodologie • Etat des lieux rapide • Outils et diagnostic plus avancés • Zoom sur une JVM • Spécificités avec Docker • Scénarios • Surtout en ligne de commande • Sur Linux • Aperçu avancé … de surface • Pas un guide exhaustif • Pas un expert système • Pas de GIF
  4. Notions de monitoring • Boîte noire : • Visible depuis

    l’extérieur, typiquement un user • Orienté symptôme • Montre des problèmes en cours • Base de l’alerting (peut faire débat, selon l’actionabilité des remontées internes) • Boîte blanche : • Métriques exposées par l’intérieur du système • Orienté cause • Permet aussi de détecter des problèmes à venir, « signaux faibles » • Prérequis : système observable
  5. Notions de monitoring • Symptômes ou causes, qu’est ce qui

    est cassé et pourquoi, ex : • Erreurs sur page web utilisateur : job batch sur même machine qui sature le CPU • Latence webservice : fibre optique à nettoyer • En chaîne, une cause contribuant un souci sur la brique suivante … • Sur incident important • Rarement une seule root cause • Plutôt un ensemble d’éléments contributeurs
  6. Anti méthodologies • Taper des commandes au hasard ou sauter

    sur le premier graphe bizarre • Regarder les logs applicatifs et sauter sur le premier souci • Googler et appliquer le premier Stack Overflow • Blame someone else : pas ma faute, c’est le composant ... ou l’équipe … • Drunk man anti pattern • Streetlight anti pattern • Changer des settings au hasard et regarder
  7. Méthodologie • Enfonçage de porte ouverte mais … • Qu’est

    ce qui vous fait dire qu’il y a un problème ? • Est-ce que le système a déjà bien fonctionné ? • Qu’est ce qui a changé récemment ? • Qui est concerné, vous ou tout le monde? • Quel environnement : logiciels, matériels, versions, configuration, … ?
  8. Méthodologie • Avoir une image mentale : • De l’architecture

    de l’application/SI • Du chemin des flux, leurs dépendances entre briques • Des chemins en lecture et en écriture dans les briques • De l’infrastructure sous jacente • Indispensable • Mais contradictoire à l’heure du cloud • Abstraction, « make it someone else problem »
  9. Méthodologie • Deux approches complémentaires • Analyse des ressources :

    • IOPS, throughput, utilization, saturation • Pour les ressources système (cpu, mémoire, disque, réseau, …) • Analyse de la charge : • Requests • Completion/errors • Latency • Bon vernis sur toutes les couches préférable : du système à l’applicatif • « Measure, don’t guess »
  10. USE method : Utilization, Saturation, Errors • Pour chaque ressource

    physique : CPUs, mémoire, disque, réseau, … • Et aussi logicielles : lock, thread pool, file descriptor, … • Vérifier : • Utilization : sur un intervalle de temps, le % de temps occupé à travailler • Saturation : > 100 %, même occupé, encore possible d’accepter du travail, la saturation définit à quel point cela n’est plus possible • Errors : nombre d’erreurs • Ne fournit que des pistes mais ferment pleins de mauvaises portes
  11. USE method : Utilization, Saturation, Errors • Certaines métriques sont

    difficiles à mesurer (erreurs CPU), difficile sur VM, mais plutôt rare. • Exemple avec le CPU
  12. USE method : Utilization, Saturation, Errors • Attention, une faible

    utilisation peut masquer des pics de charge ou des saturations • Périmètre : • Qu’une sous partie des ressources matérielles ou virtuelles • On ne regarde par exemple pas souvent l’interconnect CPU • Connaissance : known unkowns, unknow unknows • Liste de ressources à vérifier et commandes associées : http://www.brendangregg.com/USEmethod/use-rosetta.html
  13. RED method : Rate, Errors, Duration • Pour les services

    • Pas pour les ressources système • Mode boîte noire (vue de l’extérieur) : • Rate : requêtes/s, séparer celles en succès et celles en erreur • Errors : … • Duration (latency) : temps de réponse, temps d’attente/queue inclus
  14. On retient : 5 golden signals • Google SRE’s 4

    golden signals : Latency, Traffic, Errors, and Saturation • « Intersection » de USE & RED • USERED : Utilisation, Saturation, Erreurs, Rate, Duration (Latency) • Comprendre les deux aspects : • Sollicitation utilisateur, service • Ressources et leurs comportements sur la charge • A adapter selon ce que l’on observe U R E D S
  15. • Nécessite la plupart du temps de l’outillage, ex avec

    un serveur web : • Utilisation : selon le modèle (cnx/process, multi threadé, …), % de workers occupés • Saturation : MaxClients, erreurs 503 • Nb erreurs/s : parsing access logs, server-status, nb de 4XX, 5XX • Nb requêtes/s : idem depuis les logs, à affiner par contexte /uri/site/… • Latence : …, percentile, max
  16. Complément : thread et off CPU analysis • Majeure partie

    des profilers et méthodes d’analyse : surtout le temps on CPU • Pleins de raisons de ne pas être on CPU • Off CPU : perspective intéressante mais difficile à interpréter • On peut aussi travailler sur le wakeup • Pour bien faire, kernel récent > 4.0, voir > 4.8 pas des 2.6 ou 3.10, RHEL 7.6 en beta
  17. Pour faire tout cela correctement • 4 piliers du monitoring

    : • Logs • Métriques • Traces • Health check • Plus : • Profiling • Scripts adhoc • Mais quand on est sur un serveur sans rien … et car on ne peut pas centraliser, historiser tout dans le détail => alerting
  18. • w • uptime • Idée de la charge du

    serveur, sur 1, 5 et 15 minutes • Qui est loggué (peut être aussi en train de faire des actions) • uname -srm • version du kernel • cat /etc/redhat-release ou /etc/lsb-release • version de l’OS • date • Vérifier qu’il n’y a pas un écart trop important avec la vraie date ou entre machines • Peut être très pénalisant sur des systèmes distribués • timedatectl • Sur systemd
  19. • dmesg • -T sur RHEL > 7 pour avoir

    la date • oom-killer, trace kernel, panne matérielle, … • journalctl -r
  20. • free -m|g • RAM totale • Vraiment libre (free),

    cached … mais pas forcément mobilisable instantanément • Disponible -/+ buffers/cache avant RHEL 7 • Available depuis RHEL 7, ajouter -w pour avoir le détail buffer/cache • “Estimation of how much memory is available for starting new applications, without swapping. Unlike the data provided by the cache or free fields, this field takes into account page cache and also that not all reclaimable memory slabs will be reclaimed due to items being in use” • Swap : ca n’est pas parce used != 0 que cela swap, ca peut avoir swappé pour un vrai souci, ou juste le swappiness > 1
  21. • nproc • Nombre de core visible • Important pour

    interpréter la charge • lscpu • Plus de détail sur la topologie processeur • Nombre de socket, core, hyperthreading • Fréquence • Nombre de nœuds NUMA dédier « partie de RAM » par socket • Attention sur VM : la description est …
  22. • vmstat -w -Sm 2 • Outil magique pour avoir

    un vue globale rapide de l’activité d’un serveur : cpu, charge, mémoire, swap, io • Ignorer la 1ère ligne • Souci si r très supérieur au nombre de core • Souci si ou so (swap in/out) différent de 0 • cs : souci si > 50 000 par core (voir pidstat …) • Colonnes cpu : • Activité CPU séparée en user, system, idle et iowait (stolen jamais valorisée) • Si wa important, attente sur disques (SAN compris), mais interprétation délicate (préférer PSI) • Si sy > 10-20%, possible souci, dépend aussi de l’activité user • -a : affichage partie active et inactive
  23. • mpstat -P ALL 2 ou sar -P ALL 2

    • Usage détaillé par CPU • sar -q 2 • Run queue
  24. • top -c • Vue globale triable cpu P, mémoire

    M • Load average : indice sur la charge du serveur, dépend du nb de core (interprétation subjective) • %CPU process : 100% == 1 core • Switch H pour afficher les threads • Switch 1 pour le détail par core • Peut manquer des short-lived process • VIRT : mem virtuelle, non allouée physiquement ; souvent écart énorme avec RES (malloc per thread arena)
  25. • ps faux • Vue complète de tout ce qui

    tourne sur cette machine • User, pid, commande • ww pour avoir la ligne de commande complète
  26. • pidstat -u -I -r -d -w -h (-p <pid>)

    2 • Vue par process (filtre possible), par type de cpu, mémoire, IO, context switch (volontaire ou pas) • Pratique pour identifier qui est responsable de la consommation de CPU system • -t vue par thread • Context switch • 𝑐𝑠𝑤𝑐ℎ/𝑠 × 80 000 𝑛𝑏 𝑐𝑜𝑟𝑒 ∗𝑓𝑟é𝑞𝑢𝑒𝑛𝑐𝑒 𝐶𝑃𝑈 > 5% => possible lock contention (plus de 5% des cycles d’horloges passés sur du ctx switch) • nvcswch/s : indice de surcharge • Ex plusieurs pid : $(pidof postgres | sed -e 's/ /,/g') • %cpu exactement à 100% erroné parfois observé sur VM
  27. • iostat -xmzty 2 • Vue détaillée du profil d’IO,

    écriture et lecture en Mo/s • Souci si await > 1000 ms • Souci « potentiel » si %util 100% (100% du temps à écrire) • « Indication » de random si : • nombre élevé de rrqm/s ou wrqm/s • beaucoup de r/s et/w/s pour peu de rMB/s ou wMB/s • petite taille de requests (avgrq-sz) • Sur VM, correspondance fs • ls -l /dev/disk/by-id
  28. • sar -n DEV 2 • Débit réseau entrée et

    sortie • Aussi nicstat et bwm-ng (taper +) • ethtool <interface> • Vitesse de la « carte » /sbin • ip -s l • mtu : vérification jumbo frame à 9000 pour gros débit, 1500 sinon /sbin
  29. • sar -n EDEV 2 • Erreurs réseau en temps

    réel • netstat -s | egrep -i "drop|error|loss|low|over" • Erreurs réseau depuis le boot • Dépréciée • nstat • Remplaçant de netstat • Diff depuis dernière exécution par défaut • Nom de métriques « moins friendly » /usr/sbin
  30. • sar -n TCP,ETCP 2 • Nouvelles connexion entrantes et

    sortantes • Retransmit TCP • sar -n DEV,EDEV,TCP,ETCP 2 • Cumulable
  31. • ss -tuna[ropi] • Connexions • Etat des connexions :

    LISTEN, ESTABLISHED … SYN_SENT, … • Arguments • -l : state LISTEN • -r : résolution DNS • -o : info timer • -p : info process (mais lent et coûteux sur RHEL6 par rapport à netstat -antup) • -i : interne TCP • Filtre possible, ex : • ss -utan state connected src :5432 • ss -o state fin-wait-1 '( sport = :http or sport = :https )' dst 193.233.7/24 /usr/sbin #root
  32. • ss -s • Nombre de connexions • netstat -nat

    | awk '{print $6}' | sort | uniq -c | sort -r • Par état • Avec ss : ss -tuna | awk '{print $2}' | sort | uniq -c | sort -r • netstat -apn | grep <state> | awk '{ print $7 }' | sort | uniq -c | sort -nr | head -n 10 • Top 10 des process par état /usr/sbin
  33. • Tester ouverture d’un port • nc -vz <host> <port>

    • traceroute -4 -T -O info -p <port> -q 1 <host> • Alernative si -z impossible • <syn,ack> : OK • <rst,ack> : KO • En bash (echo >/dev/tcp/<host>/<port>) &>/dev/null ; if [ $? -eq 0 ]; then echo OK; else echo KO; fi • Call HTTP en l’absence d’outil exec 9<>/dev/tcp/<host>/<port> echo -e "GET /<uri> HTTP/1.1\r\nHost: <host>\r\n\r\n" >&9 cat <&9 #root
  34. • mtr -rw -c 3 <host> • Ping évolué •

    hping3 <ip> -S -p <port> -i u10000 • « Ping » avec des SYN • Filtre sur rtt à 3 digits : | egrep --line-buffered 'rtt=[0-9]{3}\.‘ #root #root
  35. • Evaluation latence appel HTTP(s) : curl_format='{ "time_namelookup": %{time_namelookup}, "time_connect":

    %{time_connect}, "time_appconnect": %{time_appconnect}, "time_pretransfer": %{time_pretransfer}, "time_redirect": %{time_redirect}, "time_starttransfer": %{time_starttransfer}, "time_total": %{time_total} }‘ curl -w "$curl_format" …
  36. • Le grep tail du réseau • ngrep -d <interface

    reseau> -W byline -t -i '<match>' 'dst port <port>' #root
  37. • df -hTP • df -iTP pour les inodes •

    vgs • Volume group LVM, pour espace disponible #root
  38. • du -sh • Taille d’un répertoire et de la

    sous arborescence • locate <un_fichier> • Localise un fichier/pattern • S’appuie sur une DB locale mlocate.db • Mise à jour via updatedb souvent croné • Attention à l’impact au passage de updatedb • Possible de pruner des arborescences dans /etc/updatedb.conf
  39. • Points de montage namespacés (ex : /tmp parfois) •

    Exemple avec /tmp : /etc/security/namespace.d/namespace_XXX.conf • Depuis un user confiné, on conserve l’isolation avec sudo su - • Visibilité d’un user confiné
  40. • Visibilité d’un user non confiné (avec droits sudo) •

    Pour voir les entrées namespacées : nsenter -m -t 1
  41. • Montages namespacés pas visibles avec df ou mount •

    findmnt • SELinux • Quel mode : getenforce • Contexte de sécurité des fichiers : • ls -Z • Champs : utilisateur:rôle:type:niveau • Contexte de sécurité des processus : ps -Z • Outil setroubleshoot-server peut aider à diagnostiquer les erreurs SELinux (mais bcq de dépendances) : sealert -a /var/log/audit/audit.log
  42. • lsof -P [-p <pid>] • Fichiers ouverts [par process]

    : fichiers, sockets, ... • Attention au fichier supprimé mais non libéré : file descriptor “deleted” lsof +L1 : identification rapide des coupables • lsof sans argument : aussi les threads enfants, pas le cas avec -p <pid> • [-i :<port>] : qui écoute sur tel port • sar -v • inode, file … • Ports locaux déjà utilisés et bloquent le start de process, utiliser le setting restreignant la page : • Setting sysctl : net.ipv4.ip_local_port_range = <debut> <fin> /usr/sbin #root
  43. • atop -r <un_fichier_historise_par_jour> • Vision détaillée par process •

    A faire tourner en daemon et avec historisation (légère empreinte CPU au moment de la collecte) • Indispensable pour le post mortem • Ne pas oublier le module kernel pour avoir le réseau par process • Attention, atop est responsable du flush et rotation d’un fichier alloué par un module kernel. Si atop est tué, ce fichier va grossir dans /tmp … #root
  44. • bandwhich • Utilisation courante réseau par process, connexion et

    remote host • https://github.com/imsnif/bandwhich #root
  45. • nmon • En intéractif : c m n d

    k V • Offline : • nmon -fT -s 2 -c 20 • Snapshot toutes les 2 s sur 20s • Analyse du fichier avec par exemple nmon analyser sur Excel
  46. Où suis-je : VM ou physique ? • lspci |

    grep -i vmw • dmidecode -t 1
  47. Où suis-je : stockage ? • lshw -class disk •

    lspci -Dm | grep -i fibre • lsscsi • multipath -l
  48. perf-tools • Utilisation des frameworks de tracing de Linux (ftrace

    et perf) et de scripts • https://github.com/brendangregg/perf-tools • Designé pour Linux 3.2+, peut fonctionner sur 2.6.x … ou pas
  49. Idem mais avec bcc/eBPF • Sur des kernels récents •

    https://github.com/iovisor/bcc • dnf|yum install bcc
  50. Etat des lieux rapide : avec bcc/eBPF… • Injection d’erreurs

    • Possibilité de tracer des fonctions kernel dans le détail en filtrant sur les arguments, la durée, …
  51. • /usr/share/bcc/tools/bpflist • Display processes currently using BPF programs and

    maps, pinned BPF programs and maps, and enabled probes #root
  52. • numactl -H • Architecture NUMA du CPU • Selon

    la charge, cela a son importance • numastat • Ratio hit/miss • Répartition mémoire par node numastat -cm | egrep 'Node|^Huge|Mem'
  53. • CPU scaling • cat /sys/devices/system/cpu/cpu*/cpu freq/scaling_governor ondemand|performance • Différence

    fréquence • cat /proc/cpuinfo model name : Intel(R) Xeon(R) CPU E5-2440 0 @ 2.40GHz cpu MHz : 1200.000 • Nombre de threads d’un process • cat /proc/<pid>/status | grep Thread • Scheduler d’IO par disque • cat /sys/block/sdc/queue/scheduler • Indice de contention mémoire • cat /proc/vmstat | grep nr_vmscan_write • Page dirty du cache OS à écrire • cat /proc/meminfo | grep Dirty • Ou via le plugin vmem de collectd
  54. • Interruption • Se méfier si la colonne %irq d’un

    mpstat est à 0 • Le time accounting dans le kernel (option à la compilation) n’est peut être pas activé • Les temps %usr %sys %idle peuvent donc être erronés • Vérifiable avec : grep IRQ_TIME_ACCOUNTING /boot/config-* • Le grep peut être vide et pourtant, c’est bien compté • Vérifier avec /proc/stat
  55. • Contribution à la load • load : nombre de

    threads dans l’état R (Runnable) ou D (Uninterruptible sleep) • git clone https://github.com/tanelpoder/0xtools • make && make install (pour psn, script et repertoire lib suffisent) • psn -G syscall,wchan,filenamesum -d 10 -r • -kstat pour ajouter la stack kernel
  56. • tuned • Différents profils possible • Profil courant :

    tuned-adm active • Contenu des profils dans /etc/tuned-profiles/… • Peut surcharger des sysctl, scheduler, …
  57. • Bencher rapidement les IO • fio -name fio_data --direct=1

    --rw=randwrite --bs=4k --size=1G --numjobs=4 -- time_based --runtime=90 --group_reporting --norandommap -- directory=<test_folder> • Nécessiterait de creuser plus les options
  58. • ioping • Latence disques « tout comme le ping

    sur le réseau » • ioping -R -c 10 . : disk seek rate • ioping -A -D -s16k -c 10 . : lecture random asynchrone direct I/O de 16k
  59. • nfsstat -c • Statistiques NFS client • Surveiller la

    proportion de retrans • nfsiostat 2 <mount_point>
  60. • sar -B 2 • pgscand/s : nombre de page

    scannées par s, indice de contention • %vmeff mesure intéressante de l’efficacité de la recuperation de page mémoire • Higher is better, “volé” avec succès depuis les inactive • Bas <30% : système en difficulté
  61. • Quels process swappent ? • cat /proc/<pid>/status | grep

    VmSwap • Ou petit script : for file in /proc/[0-9]*/status ; do awk '/Tgid|VmSwap|Name/{printf $2 " " $3} END { print ""}' $file; done | grep kB | sort -k 3 -n -r | head -15
  62. • pmap -x <pid> • Détail des allocations mémoire d’un

    process et mode (s : shared) • Tri par taille : -n -k3 #root
  63. • pmap -X <pid> • Donne encore plus d’informations •

    Selon la version kernel, en plus : LazyFree ShmemPmdMapped Shared_Hugetlb Private_Hugetlb SwapPss THPeligible • Sur une JVM RSS=Size si -XX:+AlwaysPreTouch • Valeur > 0 sur Inode, address range avec un fichier derrière, si 0 allocation mémoire requise par l’application • [heap] : c’est la native Java heap d’une JVM • 16 KiB sans permission (---p) suivi de 1012 KiB (peut être 1028) avec rw-p : c’est un thread Java • Pour aider à identifier les files mappings : pmap -X <pid> | head -n -2 | awk '{ if ($5 >0 ) printf "%12s %8s %8s %4s %s\n", $1, $6, $7, $2, $13 }‘ • Cet outil peut aider https://github.com/bric3/java-pmap-inspector #root
  64. • /proc/<pid>/statm • Valeurs mémoires en page (taille standard 4

    KiB) • Virtuelle, résident, pages backed by file + shared memory, … • On retrouve bien : 1007776 * 4 = 4031104 • Nombre de pages backed by files ou shared memory : 1540 * 4 = 6160 • Resident set size des memory mapped files in KiB, sans inclure les shared pages qui ne sont pas file backed.
  65. • Examen du contenu de la mémoire • pmap -x

    <pid> • Isoler une <adress> renvoyée par pmap et sa <size> • gdb -pid <pid> • dump memory mem.bin 0x<address> 0x<address>+<size> • detach • quit • strings mem.bin • Batché sur tout le contenu : • grep rw-p /proc/<pid>/maps | sed -n 's/^\([0-9a-f]*\)-\([0-9a-f]*\) .*$/\1 \2/p' | while read start stop; do gdb --batch --pid <pid> -ex "dump memory <pid>-$start- $stop.dump 0x$start 0x$stop"; done
  66. • pcstat • Fichier en cache ou pas ? •

    curl -L -o pcstat https://github.com/tobert/pcstat/raw/2014-05-02- 01/pcstat.x86_64
  67. • /proc/locks • Détails sur les locks posés sur des

    fichiers • Classe du lock : FLOCK ou POSIX (system call fcntl, lockf) • Type de lock : ADVISORY possible d’accéder au fichier mais pas d’autres locks ; MANDATORY pas d’autres accès • READ ou WRITE • PID du process qui tient le lock • Identifiant du fichier locké MAJOR-DEVICE:MINOR-DEVICE:INODE-NUMBER • Début et fin du fichier locké
  68. • Entropy - génération de nombres aléatoires • cat /proc/sys/kernel/random/entropy_avail

    • Souci si < 300 bytes • Selon la source /dev/random (kernel < 4.8) ou /dev/urandom, comportement bloquant pour l’appelant • Parfois nécessaire d’installer un générateur tiers, type haveged • Le daemon rngd peut aider sur des processeurs avec l’instruction rdrand
  69. • ulimit -a • Limite système sur le nombres de

    process, la mémoire, … • "too many open files", "unable to create new native thread", … • Utilisateur courant • sudo -u <user> sh -c "ulimit -a" • Attention, avec systemd, les /etc/security/*** ne sont pas pris en compte Configuration par service à faire (LimitNOFILE, LimitNPROC, …)
  70. • vmware-toolbox-cmd stat balloon Y a-t-il un ballon dans ma

    VM ? • Manière de gérer la sur-allocation de mémoire dans un ESX • Mémoire totale allouée à une VM en réalité non disponible totalement • Souci si différent de 0 Mb • Catastrophique sur une JVM
  71. • PSI : Pressure Stall Information • Baromètre de «

    pression » sur mémoire, CPU et IO • Plus fin et simple que la load average Ne dépend pas du nombre de core et c’est real time • Meilleur sur l’iowait • Kernel > 4.20 (plus tôt si backport) • Parfois (RHEL 8) à activer en ajoutant psi=1 à GRUB_CMDLINE_LINUX dans /etc/default/grub, puis grub2- mkconfig -o /boot/grub2/grub.cfg • cat /proc/pressure/cpu|memory|io • En watch : watch -n .1 grep . /proc/pressure/* • some : % de temps, un ou plusieurs tasks ayant subi une latence durant les 10, 60, 300 dernières secondes ; c’est du wallclock time • full : idem mais pour toutes les tasks • total : temps total en microsecondes
  72. DNS • Souvent une source de problème ("Everything is a

    Freaking DNS problem") • dig +search <hostname> (query time intéressant) • reverse DNS : dig -x <ip> • A vérifier : • primaire en premier sur le même site • sinon latence inter-site et retry • Alignement DNS et reverse DNS : cause souvent des problèmes sur les systèmes distribués • Si dig n’est pas installé : nslookup <host|ip>
  73. • Inspecter le trafic réseau via tcpdump • Attention, énorme

    overhead • tcpdump -w <trace.pcap> <filtres> • [-i <une_interface>] • Si beaucoup de « packets dropped by kernel », les options suivantes peuvent aider : • [-nn] : pas de résolution de nom, de protocole • [-B 4096] : taille du buffer • [-s 68] : ne capture pas le paquet entier • Filtres : • Port(s) : port <un_port> • Envoyé ou reçu par une IP : host XXX.XXX.XXX.XXX • Envoyé par une IP : src host XXX.XXX.XXX.XXX • A destination d’une IP : dst host XXX.XXX.XXX.XXX • Combinaison : 'src XXX.XXX.XXX.XXX and|or|not dst XXX.XXX.XXX.XXX' #root
  74. • Analyse ensuite avec Wireshark • Layout de colonnes (seq,

    next, ack) intéressant • Les interprétations données peuvent être erronées
  75. • ip route • iptables -S|-L • Copie d’écran :

    configuration vide ou iptables désactivé • -n -v -x : statistiques détaillées avec nombre de paquets et bytes /sbin #root
  76. • Vérifier la bande passante réseau entre deux machines :

    • Sur la cible : iperf3 -s • Sur le client : iperf3 -c <hostname_cible> -t 60 -O 2 -Z -P 8 -w 2M -l 512K • La fenêtre w peut nécessiter quelques sysctl comme sysctl net.core.rmem_max et net.core.wmem_max • Tester les jumbo frame (MTU 9000) : ping -M do -s 8972 <host>
  77. • Tester l’établissement d’une connexion TLS • openssl s_client -connect

    <host>:<port> • peut nécessiter -CAfile avec la chaîne à truster • se méfier également par rapport à un browser du SNI, donc ajouter éventuellement -servername <host> • Vérifier SAN (Subject Alt Name) • | openssl x509 -noout -text | grep DNS: • testssl.sh • https://codeload.github.com/drwetter/testssl.sh/zip/3.0.4 • ./testssl.sh <host>:<port> docker run --rm -ti drwetter/testssl.sh <host>:<port> • Sortie claire et lisible • Test des versions de SSL, TLS et cipher suite • Test session resumption • … • Test de certaines vulnérabilités • Quels ports ouverts ? • nmap -sS -sV -T2 <host>
  78. • Tracer tous les appels systèmes d’un programme : strace

    • Overhead très important • strace -s 64000000 -T -v -ttt -o strace.log -fp <pid> • strace -fc -p <pid> • Statistiques sur les syscall • Possible bug sur les durées en seconds • perf trace -p <pid> • Trace aussi les pages fault • Appels aux librairies : ltrace
  79. • RedHat Transparent Huge Pages (THP) • Fréquente source de

    « hiccup » • A désactiver • Swap • Un système peut swapper même si il y a de l’espace libre • Mauvais pour une JVM • Paramètre swappiness à 1 /sbin
  80. • Batterie carte RAID HP • hpssacli controller slot=0 show

    status • Logs IML HP • hplog -v • Linux hardware error daemon : • mcelog
  81. • Lecture des compteurs CPU • https://software.intel.com/en-us/articles/intel-architecture-and-processor- identification-with-cpuid-model-and-family-numbers • https://download.01.org/perfmon/index/

    • https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64- ia-32-architectures-software-developer-vol-3b-part-2-manual.pdf
  82. • Context switch • perf record -g [-p <pid> |

    -a] -e context- switches sleep 10 • perf report --stdio #root
  83. • perf stat -ad -- sleep 10 • [-A] detail

    par cpu • Analyse IPC : sur du physique ou virtuel si exposé (vPMC sur ESX) • If your IPC is < 1.0, you are likely memory stalled, and software tuning strategies include reducing memory I/O, and improving CPU caching and memory locality, especially on NUMA systems. Hardware tuning includes using processors with larger CPU caches, and faster memory, busses, and interconnects. • If your IPC is > 1.0, you are likely instruction bound. Look for ways to reduce code execution: eliminate unnecessary work, cache operations, etc. CPU flame graphs are a great tool for this investigation. For hardware tuning, try a faster clock rate, and more cores/hyperthreads. • Plus de core ou plus rapide pas forcément utile #root
  84. • syscount -cp <pid> • Fait partie de outils perf-tools

    de Brendan Gregg • Nombre de sys call • Overhead léger avec cp #root
  85. FlameGraph via perf • Sur une charge fortement dominée par

    du CPU • Visualiser rapidement le comportement d’une application (on-cpu) • Axe Y : stack d’appel, feuille en haut et on-cpu, thread en bas • Axe X : tri alphabétique, la largeur dépend du temps passé (nb de samples) • Couleur random (ou pas) • Linux 2.6.x • perf record -F 99 -a --call-graph dwarf -- sleep 10 • git --depth 1 clone https://github.com/brendangregg/FlameGraph • perf script [-i perf.data]| ./FlameGraph/stackcollapse-perf.pl | ./FlameGraph/flamegraph.pl > perf.svg • Linux 4.9+ • git clone --depth 1 https://github.com/brendangregg/FlameGraph • git clone --depth 1 https://github.com/iovisor/bcc • ./bcc/tools/profile.py -df -F 99 10 | ./FlameGraph/flamegraph.pl > perf.svg #root
  86. • Comment est ce mesuré, échantillonné, avec quel overhead ?

    • Stats : attention, une moyenne cache les outliers, moyenne de moyenne, de percentiles, … • CPU : • Bon ou mauvais : si beaucoup d’IO wait, plus de CPU ne sert à rien • % CPU IO wait : comparaison délicate, élevé peut être car disques très lents ; charge consommant énormément de CPU user, masquant les IO wait • Si CPU en attente de mémoire, plus de CPU ne sert à rien • Compréhension délicate, parfois pas de doc outre les sources du kernel • Outillage à installer partout, par défaut (qq exceptions sécurité)
  87. • Une perspective • Performance is a field where "the

    more you know, the more you don’t know". It’s the same principle: the more you learn about systems, the more unknown unknowns you become aware of, which are then known-unknowns that you can check on.
  88. Méthodologie sur une JVM • Qualifier le profil de charge

    : • RED • Niveau système : • USE method sur CPU, RAM, IO … • Qu’est ce qui « domine » : CPU user, system, iowait, idle ? • Oriente très vite les analyses • Niveau JVM : • GC, thread, JIT … • Niveau applicatif : • Algo en premier, thread/pooling, lock • Bas niveau • Cache CPU, alignement, miss, … • Processus d’analyse complet (conférence d’Aleksey Shipilev et Kirk Pepperdine)
  89. Activité des threads • Photo de l’état des thread :

    thread dump • freeze la JVM un court instant • kill -3 • sortie dans /proc/<pid>/fd/1 • jstack fonctionne aussi mais d’expérience, pas sur une JVM mal en point • ou jcmd <pid> Thread.print -l -e > <un_fichier> • corrélation consommation cpu • a noter que jcmd ne sait pas rentrer dans les namespaces Linux avec des versions anciennes comme JDK 8 (et 11 mais pas certain) • top -b -H -n 1 -p<pid> | head -15 • printf "%x\n" <tid> • Recherche dans le thread dump de "nid=0x…"
  90. Activité des threads • Outils d’aide à l’analyse : •

    http://spotify.github.io/threaddump-analyzer/ • https://mkbrv.github.io/tda/ • Nos yeux restent très efficace • jcmd <pid> PerfCounter.print | grep java.threads
  91. • Java 11+, temps CPU et elapsed • jcmd -e

    : allocated et defined_classes (-XX:+PrintExtendedThreadInfo)
  92. Activités threads, gc … tout en un • Vision rapide

    : jvm-tools • https://github.com/aragozin/jvm-tools • Top thread, allocation, cpu user et system • GC • A installer sur toutes machines hébergeant une JVM • [sudo -u <user>] java -jar sjk-plus-<version>.jar ttop -o CPU -n 10 -p <pid>
  93. Mémoire • Contenu de la mémoire de la JVM :

    heap dump • Freeze potentiellement très long, voir impossible • Plusieurs moyen de le déclencher : • Sur OOM avec -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=… • En JMX • Avec jmap -dump:format=b,file=<dump.hprof> <pid> • Avec jcmd <pid> GC.heap_dump <full_path_dump.hprof> • Avec core dump, très rapide à générer mais nécessite gdb et la JVM qui faisait tourner le process • gdb --pid=<pid> • gcore <coredump.core> • detach • quit • Java < 9 # jmap -dump:format=b,file=<dump.hprof> java <coredump.core> • Java > 9 # jhsdb jmap --exe <java> --core <coredump.core> --binaryheap --dumpfile <dump.hprof> • Sur JVM ko, coredump et kill la JVM : kill -6 • De préférence avec la même version du JDK que la cible • Attention à ne pas faire swapper ou « oomer » la machine en écrivant dans /dev/shm • Parfois impossible à lire • À analyser avec Eclipse MAT
  94. Mémoire • Histogramme du contenu des objets de la heap

    • jmap -histo:live <pid> > <un_fichier.-$(date +%Y%m%d%H%M%S).log> • jcmd <pid> GC.class_histogram > <un_fichier.log> nécessite -XX:+UnlockDiagnosticVMOptions sauf sur JDK récent (testé avec 11) • Outil de diff : https://github.com/phraktle/histodiff
  95. Mémoire • Info finalizer • jmap -finalizerinfo <pid> • jcmd

    GC.finalizer_info <pid> • Info classes • Logs activité classloading|unloading : -Xlog:class+unload=info • jcmd <pid> GC.class_stats
  96. Mémoire • Mémoire totale d’une JVM • Heap (Xmx) •

    Metaspace • Code cache • Thread • GC internals (~ 1 - 11%), compiler structures • Symbol et internals • Direct buffer et mapped file • Librairies natives • Malloc overhead • …
  97. Mémoire • Diagnostic mémoire plus fin via le NMT -

    NativeMemoryTracking • -XX:NativeMemoryTracking=summary ou -XX:NativeMemoryTracking=detail • jcmd <pid> VM.native_memory summary|detail • Détection leak : jcmd <pid> VM.native_memory baseline et summary.diff|detail.diff • Overhead de perf de 5 à 10% • Uniquement les allocations depuis l’intérieur de la JVM Pas les MappedByteBuffers (fichiers memory mappé en mémoire virtuelle, via FileChannel.map) • Possible de rapprocher ces résultats (pour le détail) avec le contenu du fichier /proc/[pid]/smaps qui liste les pages mémoires allouées par le process ou pmap -x <pid> • NMT will shut itself down when it detects low resource conditions, such as when running low on native memory. Sometimes that may be the situation when you would really want the data! This is the flag to disable auto shutdown: -XX:-AutoShutdownNMT
  98. Metaspace en détail • capacity (used + free + waste

    + overhead) • Souci si beaucoup de deallocated • Virtual space : bien du virtuel et pas du resident • 1GB de reserved si pas de MaxMetapaceSize • MaxMetaspaceSize : limite haute de • Compress class space • Metaspace
  99. Mémoire • Mémoire pour les DirectByteBuffers, par défaut Xmx Peut

    être nécessaire de limiter : -XX:MaxDirectMemorySize Attention à -XX:+DisableExplicitGC, cela semble utilisé dans la réclamation des DirectByteBuffer, au besoin avec le CMS, plutôt utiliser ExplicitGCInvokesConcurrent & ExplicitGCInvokesConcurrentAndUnloadsClasses • Pour les I/O avec Java NIO, les non-direct ByteBuffers utilisent des DirectByteBuffers temporaires par thread Pas de limite par défaut, forte utilisation possible de mémoire native Limite de DirectByteBuffers par thread (>1.8.0_102) : -Djdk.nio.maxCachedBufferSize Permet seulement d’éviter la mise en cache et réutilisation de buffer plus grand que la limite. • Sur le NMT, avant Java 11, la zone Internal incluait les DirectByteBuffers, après c’est comptabilisé dans la zone Other. • Allocator glibc peut allouer n core * MALLOC_ARENA_MAX * 64M MALLOC_ARENA_MAX = 8 par défaut Identifiable en voyant des blocs mémoire de 65536 sur un pmap 2 ou 4 peut aider, mais à tester, performance comprise
  100. Mémoire • Reserved, commited, resident, virtual • Reserved : pre-mapped

    (utile pour avoir des adresses contiguës) avec nmap ou malloc, mais garantie sans mémoire physique derrière (PROT_NONE) • Commited : mapped (autre que avec PROT_NONE) mais pas forcément avec mémoire physique derrière Donc resident peut être inférieur à commited. • Resident : actuellement en mémoire physique • Virtual : somme de tous les mappings, pas significatif sur une JVM • Différence entre le total NMT et RSS vu par l’OS peut être due à de l’allocator malloc (et arena) : allocation d’objets de taille différente, GC, fragmentation
  101. Profiling mémoire native : jemalloc • Utile pour avoir une

    vue sur les chemins d’allocation mémoire • Peut être utilisé en production (~2% avec beaucoup de malloc) • https://github.com/jemalloc/jemalloc/releases/latest Doit être buildé avec --enable-prof Installer graphviz export LD_PRELOAD=/usr/local/lib/libjemalloc.so export MALLOC_CONF=prof:true,lg_prof_interval:30,lg_prof_sample:17,prof_prefix:<dump_path>/app java -jar ... jeprof --show_bytes --svg /path/to/java app*.heap > memory-profiling.svg • % de mémoire référencée par la JVM : osmalloc@... os:malloc doit être à 98-99% • « Ne voit pas » le code compilé/jitté
  102. Garbage collector • Logs GC à activer partout, y compris

    en production • JDK8: -XX:+PrintGCCause -XX:+PrintGCDetails -XX:+PrintTenuringDistribution -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 - XX:GCLogFileSize=10M -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -Xloggc:<un_fichier> • JDK9+ : -Xlog:gc*,gc+age*=trace,safepoint:/app/log/gc-%p- %t.log:t,level,tags:filecount=10,filesize=10M • Quelques évidences visuelles ou greppable comme le « failure » de « (concurrent mode failure) », le « failed » de « (promotion failed) » ou le « Metadata GC Threshold » • Sinon via un outil comme gceasy.io, GC Log Viewer ou Censum (commercial … Microsoft) • Via jstat -gc <pid> 2s
  103. Garbage collector • Activable et modifiable au runtime Java >

    9 • jcmd <pid> VM.log output="file=gc-%p-%t.log" what="gc=debug,gc*,age*=trace,safepoint" decorators="time,level" output_options="filecount=10,filesize=10M" • Mode plus avancé (et verbeux) : -Xlog:gc*=debug,gc+ergo*=trace,gc+age*=trace,safepoint*,pagesize,os* • Un paquet de tags disponibles : add, age, alloc, annotation, aot, arguments, attach, barrier, biasedlocking, blocks, bot, breakpoint, bytecode, cds, census, class, classhisto, cleanup, codecache, compaction, compilation, constantpool, constraints, container, coops, cpu, cset, data, datacreation, dcmd, decoder, defaultmethods, director, dump, ergo, event, exceptions, exit, fingerprint, free, freelist, gc, handshake, hashtables, heap, humongous, ihop, iklass, init, inlining, interpreter, itables, jfr, jit, jni, jvmti, liveness, load, loader, logging, malloc, mark, marking, membername, memops, metadata, metaspace, methodcomparator, mirror, mmu, module, monitorinflation, monitormismatch, nestmates, nmethod, normalize, objecttagging, obsolete, oldobject, oom, oopmap, oops, oopstorage, os, pagesize, parser, patch, path, perf, phases, plab, preorder, preview, promotion, protectiondomain, purge, redefine, ref, refine, region, reloc, remset, resolve, safepoint, sampling, scavenge, setting, smr, stackmap, stacktrace, stackwalk, start, startuptime, state, stats, stringdedup, stringtable, subclass, survivor, sweep, system, table, task, thread, time, timer, tlab, tracking, unload, unshareable, update, verification, verify, vmoperation, vmthread, vtables, vtablestubs, workgang • Via jcmd <pid> PerfCounter.print | egrep 'safepointTime|applicationTime' • % de temps dans des safepoint, pour la plupart du GC : 100 * safepointTime / safepointTime + applicationTime
  104. Garbage collector • Sujet complexe • Phases du GC •

    Durée et fréquence • Bloquant ou pas • Concurrent ou pas • Multithreadé • Points d’attention • Taille du Live data set, des espace (Young : eden + survivor), Old, Perm|Metaspace • Allocation rate et taille récupérée • Premature promotion • Cause des GC • …
  105. Garbage collector • Souci si throughput applicatif < 90 %

    (GC prend plus de 10%) • Souci si real > user + sys • Surveiller aussi le CodeCache
  106. Safepoint • Flags PrintGCApp… très utiles au diagnostic 2020-02-29T15:54:41.216+0100: 347584.525:

    Total time for which application threads were stopped: 0.1202298 seconds, Stopping threads took: 0.0008189 seconds 2020-02-29T15:54:41.217+0100: 347584.527: Application time: 0.0011745 seconds • « thread were stopped: xx seconds » • En théorie xx == real • Si pause sans GC, investigation nécessaire • -XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 (std out et déprécié JDK 11+) -Xlog:safepoint+stats=debug (à partir JDK 13) • « Stopping thread took: xx seconds » • Le GC doit attendre que les threads soient dans un état bien défini, un safepoint • Temps pour que tous les threads atteignent cet état • Pas toujours du à un GC stop the world, mais aussi heap dump, deop, … • Facteur agravant : bcq de page fault, trop de thread comparé au nombre de core et context switch, counted loop avec gros calcul • Diagnostic : -XX:+SafepointTimeout -XX:SafepointTimeoutDelay=100
  107. • jcmd • Déjà vu pour le GC, NMT …

    • Beaucoup d’autres outils : • Détail sur le JIT • Classloader et hiérarchie • Activation de flags • VM.info : beaucoup d’informations en une commande • Flight Recorder • Démarrage JMX : jcmd <pid> ManagementAgent.start config.file=<path.to.file> • …
  108. JMX • Le plus simple, un seul fichier de configuration

    # cat jmxremote.properties com.sun.management.jmxremote=true com.sun.management.jmxremote.port=<port> com.sun.management.jmxremote.ssl=true com.sun.management.jmxremote.rmi.port=<port> com.sun.management.jmxremote.password.file=jmxremote.password com.sun.management.jmxremote.access.file=jmxremote.access com.sun.management.jmxremote.registry.ssl=true com.sun.management.jmxremote.ssl.enabled.protocols=TLSv1.2 com.sun.management.jmxremote.ssl.enabled.cipher.suites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 com.sun.management.jmxremote.ssl.config.file=jmxremote.properties javax.net.ssl.keyStore=jmxremote.jks javax.net.ssl.keyStorePassword=tlspass javax.net.ssl.trustStore=truststore.jks javax.net.ssl.trustStorePassword=tlspass
  109. Quelles options sur ma JVM ? • Listes des options

    : défauts, surcharge et ergonomics • java -XX:+PrintFlagsFinal -XX:+UnlockDiagnosticVMOptions -version • | grep ':=' valeurs modifiés manuellement ou par les ergonomics • jcmd <pid> VM.flags -all • Mais n’affiche pas tout … • Depuis le JDK11, c’est encore plus clair, on sait si c’est la « command line », les « ergonomics », … • Plusieurs sites avec la liste complète par version … https://chriswhocodes.com/hotspot_options_jdk11.html
  110. • Beaucoup d’outils s’appuie sur le fichier hsperfdata • Attention

    au flag systemd PrivateTmp avec pour conséquence une localisation du hsperfdata exotique : /tmp/systemd-private-xxx-elasticsearch.service- xxxx/tmp/hsperfdata_elasticsearch/ • Utile pour browser facilement le tmp en question : nsenter -t $(systemctl show --property=MainPID --value elasticsearch.service) -m ls -la /tmp
  111. • Options pour debug TLS • JDK : -Djavax.net.debug=all •

    Weblogic specific (à ajouter) : -Dssl.debug=true -Dweblogic.StdoutDebugEnabled=true - Djava.security.debug=true
  112. Diagnostic avancé • Arthas • Opensourcé par Alibaba, outil de

    diagnostic, attachement live (nécessite telnet) • http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central- proxy&g=com.taobao.arthas&a=arthas-packaging&e=zip&c=bin&v=LATEST ./as.sh • Certains nombres de commandes accélérant le diagnostic
  113. • Monitoring dynamique de méthode d’une classe : monitor •

    Paramètres d’une méthode : watch • Valeur de retour
  114. Crash • En cas de crash, la JVM génère un

    fichier hs_err_pid<pid>.log (chemin customisable via -XX:ErrorFile) qui contient pleins d’informations intéressantes pour le diagnostic • Doc Oracle : • The operating exception or signal that provoked the fatal error • Version and configuration information • Details on the thread that provoked the fatal error and thread's stack trace • The list of running threads and their state • Summary information about the heap • The list of native libraries loaded • Command line arguments • Environment variables • Details about the operating system and CPU • Un fichier core peut aussi être généré
  115. GUI anciens • JConsole : le VisualVM historique • VisualVM

    : vue CPU (+GC), différent espace mémoire, thread, mbeans JMX avec plugin, …
  116. GUI récent • Java Mission Control (JMC) : • Le

    futur • MBean JMX sans plugin • GUI jcmd • FlightRecorder • Fantastique outil • Utilisable en production et en continu • Utilisable en ligne de commande • Allocation/lock/exception/safepoint • Opensourcé depuis JDK 11 (commercial sur JDK 8 mais backporté 8u262) • Builds officiels http://jdk.java.net/jmc/ ou officieux https://builds.shipilev.net/jmc/ • Accounting du profiling est erroné et profiling arrayCopy() impossible
  117. Java Flight Recorder • Profils : • default : 1%

    overhead max • profile : collecte plus de données, overhead plus grand • custom.jfc : via JMC Flight Recording Template Manager • Possible au démarrage de la JVM -XX:StartFlightRecording=settings=default|profile,duration=12m,name=record,filename=record.jfr avec un délai : delay=5m • Sur une durée : jcmd <pid> JFR.start duration=30s settings=default|profile filename=record.jfr avec un settings custom : settings=<full_path_vers_jfr> • La commande JFR.start renvoie un name=<id> Il sert aussi sur le JFR.stop name=<id>
  118. Java Flight Recorder • Capture continue : • jcmd <pid>

    JFR.start maxsize=500MB settings=default|profile • Repository par défaut temporaire : java.io.tmpdir • -XX:FlightRecorderOptions=repository=<path> • ou jcmd <pid> JFR.configure repositorypath=<path> stackdepth=96 • Nom du path : date_heure_pid ; donc change à chaque restart • Ecrit des chunks de 12Mo ou plus • S’accumule jusqu’à maxsize • Dump régulier possible jcmd <pid> JFR.dump filename=record-$(date +%Y%m%d%H%M%S).jfr • La taille max du dump sera aussi maxsize • Assemblage des chunks : jfr assemble <path> finalcapture.jfr
  119. Java Flight Recorder : aide fuite mémoire • JDK 10+

    : Old Object Sample • jcmd <pid> JFR.dump path-to-gc-roots=true • Pleins d’informations : => Où l’objet a été alloué (setting profile only) ? => Qui tient encore l’objet ? • Configurer le nombre d‘objets à tracker : -XX:FlightRecordingOptions=old- object-queue-size=512 (256 par défaut)
  120. Java Flight Recorder • jfr • Outil en ligne de

    commande pour capture JFR • Disponible depuis JDK 12 et 11.0.6 • Stack complète (OS->JVM) dans la capture • Exemple : • jfr print --events GarbageCollection <capture.jfr>
  121. JMC agent (WIP) • javap -p <classe_a_instrumenter> : chercher le

    descriptor des méthodes ex : descriptor: (Ljava/lang/Integer;)Lfr/enedis/soctech/javadiag/Service$HeavyObject; • Au besoin : https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3 ou un œil à la classe générée • Plus simple de créer le fichier xml avec le Preset Manager de l’UI de JMC • java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -XX:+FlightRecorder - javaagent:<path_to_org.openjdk.jmc.agent-X.jar>=<path_to_setting_file.xml> -jar … • Ex : • Print evt : jfr print --events new_preset.event.2 --stack-depth 50 new_preset.event.2 { startTime = 22:49:24.391 duration = 1,731 ms fieldKey = "99" eventThread = "http-nio-8080-exec-5" (javaThreadId = 29) stackTrace = [ fr.enedis.soctech.javadiag.Service.getAHeavyBuildObject(Integer) line: 14 fr.enedis.soctech.javadiag.Service$$FastClassBySpringCGLIB$$fad4be7f.invoke(int, Object, Object[]) org.springframework.cglib.proxy.MethodProxy.invoke(Object, Object[]) line: 218 org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint() line: 749 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() line: 163 ... ] }
  122. JMC agent (WIP) <jfragent> <config> <classprefix>__JFREvent</classprefix> <allowtostring>true</allowtostring> <allowconverter>true</allowconverter> </config> <events>

    <event id="new_preset.event.1"> <label>bla evt1</label> <description>desc evt1</description> <class>fr.enedis.soctech.javadiag.Service</class> <path>javadiag/evt1</path> <stacktrace>true</stacktrace> <rethrow>true</rethrow> <location>WRAP</location> <method> <name>clear</name> <descriptor>()V</descriptor> </method> </event> <event id="new_preset.event.2"> <label>bla evt2</label> <description>desc evt2</description> <path>javadiag/evt2</path> <class>fr.enedis.soctech.javadiag.Service</class> <stacktrace>true</stacktrace> <rethrow>true</rethrow> <method> <name>getAHeavyBuildObject</name> <descriptor>(Ljava/lang/Integer;)Lfr/enedis/soctech/javadiag/Service$HeavyObject;</descriptor> <parameters> <parameter index="0"> <name>key</name> <description>key param</description> </parameter> </parameters> </method> </event> </events> </jfragent>
  123. Profiling • Profilers (VisualVM, JProfiler, JMC, …) • Souffrent tous

    des problématiques liées aux safepoints • « Stop the world » tous les threads pour sampler • Ne voit que le « Java », pas le reste : OS, kernel, runtime JVM (GC, compiler), librairie native, code interprété, inlining, … • Modifie le code, donc pas compilé de la même manière • S’appuyer sur perf et AsyncGetCallTrace • A installer tout le temps (il peut y avoir qq settings sécurité) • AsyncGetCallTrace (API interne JDK)
  124. Profiling • async-profiler pour « tout avoir » • https://github.com/jvm-profiling-tools/async-profiler

    • Kernel, stack natives, compteurs matériels (page fault, ctx switch, …) (si exposé), stack Java complete, allocations, locks • Ok sur Java 8+ • Bug JVM : https://bugs.openjdk.java.net/browse/JDK-8178287 AsyncGetCallTrace fails to traverse valid Java stacks
  125. async-profiler • Quelques settings à modifier • sysctl -w kernel.perf_event_max_stack=4096

    • /proc/sys/kernel/perf_event_mlock_kb • echo 1 > /proc/sys/kernel/perf_event_paranoid • echo 0 > /proc/sys/kernel/kptr_restrict • Si pas loadé en tant qu’agent, pour être plus fiable : -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints • Pas besoin de root mais perf_event_paranoid setté correctement • Le fichier libasyncProfiler.so doit être accessible en lecture par le user du process cible • ./profiler.sh -d 10 -f perf.html [-i 500us] <pid> • Si service systemd avec PrivateTmp, viser un chemin sur le -f non namespacé • Palette de couleur • green : Java compilé ou classique // aqua : Java inliné brown : kernel // yellow : C++ // red : code natif
  126. async-profiler • Aussi • Si absence de stacktraces sur du

    natif (kernel > 4.2) : --cstack lbr • Profiling des allocations mémoire : -e alloc • Bleu : allocations inside TLAB, donc rapides ; orange : outside TLAB donc lentes • Surveiller les allocations humongous du G1 : -e G1CollectedHeap::humongous_obj_allocate • Profiling wall clock time : -e wall -t • Lock contention : -e lock [-- lock x ms] -o flamegraph=total • Sortie JFR (Flight recorder) : -f perf.jfr • Utile pour voir des spike • Possible de record cpu, allocation et lock en même temps : -e cpu,alloc,lock • Conversion en FlameGraph : java -cp build/converter.jar jfr2flame perf.jfr perf.html • Conversion en FlameScope : java -cp build/converter.jar jfr2nflx perf.jfr perf.nflx
  127. FlameScope • $ git clone https://github.com/Netflix/flamescope • $ cd flamescope

    • $ pip3 install -r requirements.txt • $ python3 run.py • By default, FlameScope will load a list of files from the examples dir • Peut nécessiter : • pip3 install --upgrade werkzeug
  128. FlameScope • Utile pour détecter des patterns de : •

    Periodic activity • One busy-wait thread, once per second This thread does about 20 ms of work, then sleeps for a whole second (1000 ms). It's a common pattern, and results in the wakeup offset creeping forward each second. • Variance • CPUs 50% utilized • Variable load Every 30 seconds there is 5 seconds of heavier work. • Perturbations • CPU perturbations Every so often, all CPUs max out for 100s of ms. (Eg, GC).
  129. async-profiler • Aussi • kernel > 2.6.33 • Enregistrer tous

    les invocations et stacktrace d’une méthode : -e ClassNameQualified.methodName (pour toutes les méthodes .*) • Exception précise : -e 'java.lang.NullPointerException.<init>' • Origine d’une exception sans stacktrace ou log : -e Java_java_lang_Throwable_fillInStackTrace Chercher dans le code : JNIEXPORT jobject JNICALL • Aide à l’identification éventuelle de « fuites » : • malloc : -e malloc • mprotect (extension allocated area) : -e mprotect • mmap : -e mmap • malloc sans free : LD_PRELOAD=/path/to/libasyncProfiler.so java -agentlib:asyncProfiler=start,event=nativemem,file=malloc.jfr <Your App> puis java -cp converter.jar MallocReport malloc.jfr malloc.html • Utilisation du cache OS : -e filemap:mm_filemap_add_to_page_cache • Page faults : -e page-faults • Context switchs : -e context-switches • Dès le démarrage -agentpath:<path_to_agent>/libasyncProfiler.so=start,event=<cpu|alloc>,interval=500000 ./profiler.sh -f perf.html stop <pid>
  130. Stacktrace • L’émission des stacktraces est très couteuse • La

    JVM peut les supprimer, et ainsi parfois compliquer le diagnostic • Le paramètre de contrôle est -XX:+OmitStackTraceInFastThrow
  131. Problématique • Dans le container • Pas ou peu d’outillage

    système (maintenir petite taille image et faible surface d’attaque) • JDK ou JRE ? • Mémoire limitée • PIDs différents • syscalls bloqués par seccomp • Throttling tooling du fait des quotas • Sur le host Linux • Nécessite des privilèges élevés, pas simple sur plateforme mutualisée • Doit pouvoir rentrer dans les namespaces • Avec un JDK (>10 pour avoir Attach API dans Docker), montage /tmp éventuel • Avec tout l’outillage classique (sysstat, perf, …) • Volume d’échange assez pratique (log, heap dump, flame graph, …)
  132. • systemd-cgtop • top pour cgroup • docker stats •

    top pour container • docker system df • Utilisation du disque
  133. • cgroup cpu • docker run --cpus --cpu-shares … •

    docker ps --no-trunc : id complet • cat /sys/fs/cgroup/cpuacct/docker/<container-id>/cpuacct.stat • cat /sys/fs/cgroup/cpu,cpuacct/docker/<container-id>/cpu.stat /sys/fs/cgroup/cpu.stat en cgroup v2 Ex : throttling moyen de 148 ms • Event JFR (<JDK 17) jdk.ContainerCPUThrottling • CPU share et cap causent du context switch involontaire grep nonvoluntary_ctxt_switches /proc/<pid>/task/*/status
  134. • cgroup mémoire • docker run --memory --kernel-memory … •

    cat /sys/fs/cgroup/memory/docker/<container-id>/memory.stat • attention aux JVMs : « oomkilled » avant le heapdump • cgroup io • docker run --device-read-bps --device-read-iops • cat /sys/fs/cgroup/memory/docker/<container-id>/ • blkio.throttle.read_bps_device ou blkio.throttle.write_bps_device • blkio.throttle.read_iops_device ou blkio.throttle.write_iops_device
  135. • nsenter • Exécution de commandes « dans un container

    » mais sans entrer dans les cgroups • Aussi docker exec -it <container-id> <une_commande> • -m: mount, -u: uts, -i: ipc, -n: net, -p: pid, -U: user • nsenter -t <pid> -u hostname • nsenter -t <pid> -n netstat -antp • nsenter -t <pid> -n ss -s • nsenter -t <pid> -m -p top • sidecar container, mais nécessite de redémarrer le pod • docker run -it --privileged --pid=container:<name|id> --volumes-from=<name|id> --network=container:<name|id> --ipc=container:<name|id> <tooling_image> /bin/bash • Ephemeral container sur K8S (alpha, >1.16, feature complete v1.18) • kubectl debug -c <debug_container> --image=<image_avec_tooling> <pod_a_debugger> -- bash • En attendant : kubectl replace --raw …
  136. • Confusion entre métriques du host ou du container •

    docker run … -m800m vue JDK 11 : jcmd <pid> VM.info | grep memory_limit • docker run … --cpus=1 vue JDK 11 : jcmd <pid> VM.info | grep cpu • idem loadavg, iostat
  137. • Container Metrics system • java -XshowSettings:system -version • API

    disponible en Java 11 • Pas encore exposée en JMX • java -Xlog:os+container=trace
  138. • async-profiler • Selon version de kernel, de Docker, …

    • echo 1 > /proc/sys/kernel/perf_event_paranoid • docker run --cap-add SYS_ADMIN et/ou docker run --security-opt seccomp:unconfined ou profile seccomp avec whitelisting des syscall nécessaires ou --fdtransfer • Si on ne peut pas changer perf_event_paranoid : ./profile … --all-user • Mettre async-profiler à la racine d’un volume partagé • ./profile … -f <volume>/perf.svg
  139. • Exemple avec FlightRecorder depuis le host • jcmd <pid>

    JFR.start duration=30s filename=/path/in/container/perf-tbl.jfr • jcmd <pid> JFR.dump • docker cp <container-id>:/path/in/container/perf-tbl.jfr /path/in/host ou plus rapide sur un volume • Analyse avec Mission Control
  140. • Sizing limite cgroup JVM • -XX:+AlwaysPreTouch aide • Prendre

    en compte toutes les sources de consommation mémoire, cf slide • Résident totale du process ps --no-header -o rss <pid> • Composée de • Bien se rappeler que le NMT ne suffit pas à faire le total jcmd <pid> VM.native_memory | grep -P "Total.*committed=" | grep -o -P "(?<=committed=)[0-9]+(?=KB) " • Résident des mapped files pmap -X <pid> | head -n -2 | awk '{ if (NR > 2 && $5 >0 ) sum += $7 } END { print sum }‘ • Plus mémoire possiblement utilisée par malloc or mmap, via des librairies natives et le native allocator overhead
  141. Scénarios • Démos • Différents type de charge et vmstat

    : https://www.thomas- krenn.com/en/wiki/Linux_Performance_Measurements_using_vmstat
  142. Conclusion • Un peu de théorie • Méthodologie et «

    à ne pas faire » • Etat des lieux rapides, quelques commandes à connaître • Outils plus perfectionnés • Outillage spécifique JVM • Interprétation toujours délicate : pas de conclusions hâtives @vladislavpernin
  143. Sources & références • Expériences personnelles • Brendan Gregg, Sasha

    Goldshtein, Alexey Ragozin, Kirk Pepperdine, Charlie Hunt, Monica Beckwith, Andrei Pangin, Aleksey Shipilëv, Nitsan Wakart, Richard Waburton, Thomas Stüfe, Evan Jones, Jonatan Kazmierczak, Poonam Bajaj Parhar, Marcus Hirt, Brice Dutheil, Tanel Poder, … • Google SRE • …