Devoxx 2014 – Construire des « Reactive Applications »

Avec sa conférence « Building Reactive Apps » à Devoxx, James Ward a présenté ce que signifie réellement l’adjectif « reactive » pour une application, avec des exemples de mise en œuvre en utilisant Play Framework et Akka, le tout en Java 8. Cette présentation a particulièrement retenu mon attention tant les problématiques abordées sont d’actualité et apparaissaient en filigrane dans plusieurs autres conférences.

Qu’est ce qu’une application « reactive » ?

De manière assez spontanée, on aurait envie de répondre qu’il s’agit d’une application « performante et dans laquelle l’utilisateur n’attend pas ». Cette considération n’est pas totalement fausse mais plutôt incomplète. Les différents points à prendre en compte, explicités dans le « Reactive Manifesto » (http://www.reactivemanifesto.org) sont les suivants :

  • La scalabilité : Il faut garantir que l’application puisse être déployée sur des systèmes distribués, et redimensionnée facilement. Cela permet de pouvoir allouer des ressources suivant le besoin selon le modèle du « pay-for-what-you-use » et donc de s’adapter aux montées en charge.
  • La résilience : Dès le début de la conception, il faut penser l’application pour qu’elle soit la plus résistante possible aux erreurs et autres aléas, qui peuvent interrompre son fonctionnement normal. A tous les niveaux de l’application, il doit être possible de revenir rapidement et simplement à un état de fonctionnement normal.
  • L’utilisateur : Ce dernier point est, sans aucun doute, le plus important, car ce qui importe le plus dans tout système d’informations, ce sont les besoins et volontés de l’utilisateur. Ce que l’utilisateur veut, c’est avoir un système où toutes ses données sont constamment synchronisées, pouvoir travailler de manière collaborative en temps réel, et surtout avoir systématiquement un retour (« feedback ») de l’application pour savoir ce qui se déroule... Une application reactive doit, de ce fait, garantir des temps de réponse les plus courts possibles.

Comment y parvenir ?

Les éléments donnés précédemment pour la définition sont clairs et, pour la plupart, ils tiennent du bon sens, mais ce qui se révèle autrement plus complexe, c’est la mise en place de tout ceci. Pour répondre à cela, James Ward a donné un certain nombre de pistes, mais pour lui, l’échange en asynchrone avec des requêtes non-bloquantes reste toujours le maître-mot.

Communication client-serveur par Websockets

Pour avoir une application qui réalise des opérations asynchrones et où les différentes requêtes ne sont pas bloquantes, il faut s’orienter vers une programmation qui se base sur des événements plutôt que des attentes actives, à commencer par les interactions entre le client et le serveur.

Habituellement, pour avoir des données à jour, dans les applications client-serveur, le client émet des requêtes vers le serveur à intervalles réguliers afin d'actualiser ses informations. Plutôt que de garder cette approche-là, qui nécessite beaucoup d’interactions réseau, il faut privilégier l’utilisation de websockets pour avoir une communication bi-directionnelle. Ainsi, lorsqu’il y a des données mises à jour sur le serveur, c’est le serveur qui informe ses clients sans que ces derniers n’aient à lancer de requêtes et l’utilisateur a toujours des informations à jour.

Traitement asynchrone des requêtes

Par exemple, dans une application client-serveur « habituelle », lorsque le client émet une requête vers le serveur, un thread sur le serveur prend en charge cette requête et appelle différents services pour constituer sa réponse. Ce thread reste alors vivant pendant l’ensemble des opérations, et si un traitement nécessite un temps important, le thread reste vivant durant ce temps. De ce fait, si le nombre de requêtes augmente, un grand nombre de threads seront actifs, on peut donc vite atteindre la limite du nombre de threads, et ne plus pouvoir répondre correctement aux futurs clients.

Dans ce cas, une approche par événements consiste à recevoir la requête sur le serveur et ne pas attendre la fin de la réalisation des longs traitements. Autrement dit, le thread en charge de traiter la requête doit faire les appels vers les services, puis s’arrêter. Ce sont les services qui doivent informer de la fin de leurs traitements afin d’envoyer la réponse au client. De cette manière, le nombre de threads actifs au même moment est beaucoup plus faible, vu que leur durée de vie est écourtée.

Pour réaliser ceci avec le Play Framework, James Ward a présenté la notion de « promesse de résultat » en utilisant la classe F.Promise<T> (cf. http://www.playframework.com/documentation/2.0.4/JavaAsync).

Parallélisation des traitements

Lorsque l’on parle de la parallélisation des traitements, il y a plusieurs niveaux à considérer, et cela reste la partie la plus difficile à mettre en œuvre. Tout d’abord, il faut privilégier la distribution des différents services sur plusieurs machines plutôt que de concentrer tous les traitements sur une seule. Mais pour arriver à cette distribution, un système de communication entre services via des messages doit être mis en place pour que les échanges puissent être asynchrones.

Au-delà de la distribution des traitements sur plusieurs noeuds, à l’échelle d’une seule machine, il est recommandé d’utiliser plusieurs threads pour les opérations lourdes afin de tirer profit des architectures multi-cœurs des machines. Or, de nombreuses difficultés apparaissent quand on s’attaque à la parallélisation, notamment, la gestion des verrous, les problèmes de concurrence d’accès… Pour limiter ces difficultés là, James a présenté l’utilisation des Akka Actors avec le Play Framework. Cela permet de gérer des opérations sur plusieurs threads assez facilement grâce à l’échange et au traitement de messages (cf. http://doc.akka.io/docs/akka/snapshot/general/actors.html).

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.