Auditez vos applications réactives !

Programmation réactive

A l’occasion de #Scala.IO 2014 Paris, OCTO Technology présente « reactive-audit ». Un outil open source capable de détecter tous les appels bloquants à la machine virtuelle Java.

Les approches réactives sont de plus en plus présentes, via des des frameworks comme Akka, Play, RxJava, AsyncHttpClient ou Vert.X. Ces modèles sont exigeant vis-à-vis des développeurs qui doivent être particulièrement vigilants à ne pas utiliser d’API bloquantes.

Dans des environnements conçus dès le départ avec ce modèle, comme Node.JS par exemple, ce n’est pas un problème. Il n’y a tous simplement pas d’API bloquantes proposées.

Pour des frameworks utilisant des systèmes plus anciens comme Java ou .Net, le risque d’utiliser directement ou indirectement (via une librairie) un code bloquant n’est pas nul. Comme ces architectures utilisent un pool de threads de taille fixe et limitée pour distribuer les traitements des événements, une maladresse peut ralentir considérablement les performances du système.

Dans le cadre d’une utilisation sous Java, nous proposons un outil d’audit qui détecte, lors de l’exécution, tous les appels bloquants devant être évités. Il s’agit d’un agent à la JVM qui vérifie, à l’exécution, l’invocation de toutes les API du SDK (+500). Si un appel bloquant est détecté, une stack-trace ainsi que le nom du thread correspondant est loggé.

Cette outil travaille en run. En effet, il n’est pas possible de détecter un appel à une API bloquante lors de la compilation. Java étant un langage objet, il bénéficie du polymorphisme. Par exemple il n’est pas possible de savoir a priori si l’invocation de Writer.write(…) est appliquée sur un tampon en mémoire, sur un fichier dans le cloud ou sur un socket réseau.

L’outil instrumente le code lors du chargement dans la JVM. Ainsi, il est possible de vérifier, lors de l'exécution, que l'instance utilisée est bien associée à un flux réseau ou un fichier et non à la mémoire. L'idée est d'intervenir juste après le chargement des classes par le Classloader, pour manipuler le byte code juste avant l'invocation de defineClass().

Instrumenter le code permet une analyse lors de l'exécution, à chaque appel de méthode. Il est ainsi possible de spécifier :

  • Les threads autorisés à utiliser des API bloquantes (le thread main ou les threads en dehors du thread pool, pour gérer les backups ou les timeouts par exemple) ;
  • les threads non autorisés à les utiliser (les threads du thread pool) ;
  • des méthodes annotées comme étant autorisées à utiliser des API bloquantes (@TolerateLatency), même dans les mauvais threads (le développeur en assume alors les conséquences) ;
  • les méthodes annotées pour ne jamais être invoquées dans les threads réactifs (@WithLatency);
  • et même retarder le début de l'analyse pour permettre aux différents frameworks de s'initialiser sans contraintes, avec des appels bloquants si nécessaire.

Vous trouverez tout cela sur le compte Github d’OCTO Technology, ici.

Cet outil a vocation à être utilisé en tests d'intégrations et en tests de recette. Ainsi, en parcourant les différents scénarios d'usages, les appels bloquants seront identifiés.

Comme le code est instrumenté par la JVM, il n’est pas nécessaire d’intervenir à la compilation. Lancer un audit est très simple, cela consiste à ajouter des paramètres à la JVM lors du lancement.

Une fois le projet téléchargé est dézipé, ajoutez le répertoire bin correspondant à votre PATH. Ensuite, l’invocation de reactive-audit suivie éventuellement d’un nom de framework, permet d’initialiser les variables d’environnement correspondantes.

FrameworkWindowsMac/linux
unknown> reactive-audit > java %AUDIT_OPTS% ...$ source reactive-audit $ java %AUDIT_OPTS% ...
jetty> reactive-audit jetty > java %AUDIT_OPTS% -jar start.jar$ source reactive-audit jetty $ java %AUDIT_OPTS% -jar start.jar
catalina> reactive-audit catalina -run catalina run$ reactive-audit catalina -run catalina run
play> reactive-audit play -run activator run$ reactive-audit play -run activator run
vert.x> reactive-audit vertx -run vertx run ...$ reactive-audit vertx -run vertx run ...
maven> reactive-audit maven -run mvn ...$ reactive-audit maven -run mvn ...
gradle> reactive-audit gradle -run gradle ...$ reactive-audit gradle -run gradle ...
sbt> reactive-audit sbt -run sbt ...$ reactive-audit sbt -run sbt ...

Le sous-projet reactive-audit-integration montre comment utiliser l’outil directement dans un script Maven, Gradle ou SBT.

Ce projet est Open Source : remontez-nous tous vos essais, remarques, extensions, etc.

Philippe PRADOS, François-Xavier Bonnet, Yacine Benabderrahmane et l'équipe réactive.