Salut,
Ce fil ne pose pas de question. Je voulais juste partager avec vous un p’tit bout d’histoire que nous avons eu au boulot.
Je travail sur un bus applicatif. Pour faire simple on reçois des fichiers via différents protocoles et on les envoies à différents destinataire avec éventuellement un peu de traitement sur ces fichiers.
Tous les fichiers qui arrivent passe par un script bash qui fait appel à inotifywait pour savoir quel fichiers il doit traiter.
La première version de ce script était assez naïve. Elle fait une boucle sur inotifywait et traite le fichier qui viens d’arriver avant d’attendre un nouvel évènement. C’est très mauvais d’un point de vu performance. Dès que l’on monte un peu en charge, le traitement d’un fichier devient trop long. Il faut savoir que le noyau maintient une liste d’évènements inotify. Si on est trop lent pour traiter les évènements ils s’accumule, jusqu’à atteindre une limite de 16 000 et quelques évènements. À ce moment là si le noyau reçois encore une évènement, il va ajouter un évènement pour dire qu’il a un overflow. Bref niveau perf on était pas terrible.
La grosse optimisation a était de créer des « workers », on garde un processus principal qui attend les évènements et il transmet chaque évènement à un worker qui lui fait le boulot. Pour faire ça c’est très simple, il suffit d’utiliser xargs. Nous avons décidé de ne pas utiliser de pipe pour la communication entre le processus principal et xargs car les pipes sont limités en taille (4kio si ma mémoire est bonne). On utilise donc un fichier et on fait une rotation régulière de ce dernier.
Une fois fait on a commencé à avoir des performances décentes sous forte charge mais on a remarqué via time que la quasi totalité du temps était passé en espace noyau. Ça vient entre autre du nombre de fork que lance chaque worker. Pour résoudre ça nous avons utilisé tout ce que je connais comme raffinements pour éviter l’usage de grep, sed, cur, awk etc. On a gagné 50% de performance avec ça.
Il reste quelques fork aux quels on ne peut pas échapper en bash comme curl et surtout des appels un peu trop régulier à la commande date (pour le logging). Bash 4.2 offre une super solution pour ça prinf permet d’utiliser un formateur de date au quel on peut passer -1 pour indiquer la date courante. Mais nous utilisons bash 4.1 donc on ne peut rien faire ainsi. Une solution (pas encore mis en place) serait de faire faire ces appels par un autre processus qui loggerait pour tous les autres (et qui ferrais entre autre appels à date¹), mais ce n’est pas encore mis en place.
Bref tout ça pour dire que ce n’est pas parce que l’on fait des script shell que le script et forcément lent. Ici on a mis en place un paterne multitâche en très peu de temps et très simplement et quand on commence à regarder les performance sous forte charge les fork commencent à prendre vraiment beaucoup (trop) de temps.
¹ : l’intérêt c’est que le logging ne deviens plus bloquant