Blog Zenika

#CodeTheWorld

Crafting Software

Elasticsearch : modes de communication et plugin ØMQ

Elasticsearch est un projet open source, développé en Java et basé sur l’excellente librairie Apache Lucene, qui fournit des fonctionnalités de recherche avancées pour les sites web et les applications métier. Ses caractéristiques les plus connues sont sa capacité à indexer et rechercher des informations sur un très grand volume de données, sa nature distribuée qui facilite la clusterisation de serveurs de moteurs de recherche, et son API REST/JSON très complète.

Il existe plusieurs façons de communiquer avec un serveur (ou un ensemble de serveurs) Elasticsearch. La plus simple est d’utiliser l’API REST sur le protocole HTTP, mais il en existe d’autres. Voici donc un petit tour d’horizon des modes de transport existants pour communiquer avec Elasticsearch, ainsi qu’une présentation plus détaillée du plugin ØMQ.

HTTP

Elasticsearch dispose d’un module appelé “HTTP”, activé par défaut, qui expose l’API REST au travers d’un serveur Web. Ainsi, il suffit d’un simple client HTTP (nous utilisons dans nos exemples cURL) pour exécuter des opérations d’indexation de documents :

$ curl -XPUT http://localhost:9200/library/book/1 -d '{
    "title" : "Lucene in Action",
    "authors" : ["Michael McCandless", "Erik Hatcher", "Otis Gospodnetic"]
}'

Ou des recherches de documents :

$ curl -XGET http://localhost:9200/library/_search?q=title:lucene

Pour les traitements en masse, par exemple lorsqu’un grand nombre de documents doivent être indexés successivement, une bonne pratique consiste à utiliser l’API “Bulk”. Une requête “bulk” contient simplement un ensemble d’opérations à exécuter de façon groupée, qui seront envoyées au cluster Elasticsearch en une seule fois.

$ cat operations
{ "index" : { "_index" : "library", "_type" : "book", "_id" : "1" } }
{  "title" : "Lucene in Action" }
{ "index" : { "_index" : "library", "_type" : "book", "_id" : "2" } }
{  "title" : "Spring Batch in Action" }
…

Ce dernier fournira en retour un rapport d’exécution de chacune des opérations :

$ curl -s -XPOST localhost:9200/_bulk --data-binary @operations
{
    "took":16,
    "items":[
        {"index":{"_index":"library","_type":"book","_id":"1","_version":1,"ok":true}},
        {"index":{"_index":"library","_type":"book","_id":"2","_version":1,"ok":true}},
        (...)
    ]
}

Si ce mode de transport est le plus simple et intuitif, ce n’est pas forcément le plus adapaté à toutes les situations.
Par exemple, lorsqu’un très grand nombre de documents courts doivent être indexés de façon non prédictible : dans ce cas, les documents ne peuvent pas être groupés de façon efficace dans une requête “bulk” (car nous ne savons pas quand ils sont générés) et le temps de requête/réponse HTTP peut constituer un goulet d’étranglement. Une autre situation est lorsque le protocole HTTP est tout simplement interdit pour des raisons techniques ou de sécurité.
Heureusement, Elasticsearch propose d’autres alternatives : Thrift, Memcached et ØMQ.

Thrift

Apache Thrift permet de définir des contrats d’échanges entre services dans un fichier de configuration et de générer à partir de ce fichier plusieurs clients RPC dans différents langages de programmation.
Le projet Elasticsearch dispose d’un plugin de transport “Thrift” installable sous forme de plugin, et met à disposition le fichier de définition correspondant pour la génération de clients RPC. Thrift offre théoriquement de meilleures performances que le mode de transport HTTP, et permet de réaliser les mêmes opérations (indexation, recherche, administration) que ce dernier.

Memcached

Memcached est un système de gestion de cache distribué où les données sont stockées en mémoire, au sein d’un cluster. Il suffit ensuite d’utiliser l’un des nombreux clients disponibles pour se connecter au serveur et y stocker ou récupérer des données.
Un mode de transport “memcached” a été implémenté pour Elasticsearch. Toutefois, ce dernier n’expose pas l’intégralité de l’API REST.

ØMQ

ØMQ (aussi appellé ZeroMQ ou zmq) est une librairie de sockets connue pour ses excellentes performances. Développée en C/C++, son API est disponible dans de nombreux langages dont Java.
Cette librairie fournit des sockets capables d’échanger des messages sur un réseau (en TCP ou multicast), entre threads d’une application via un espace mémoire (on parle alors de in-process) ou encore entre processus d’une même machine (inter-process).
ØMQ permet aussi d’implémenter différents patterns de communication tels que request/reply, publish/suscribe, fanout ou encore la distribution de messages à destination de plusieurs workers (chargés du traitement des messages).
Le plugin “transport-zeromq” expose l’API REST d’Elasticsearch via des sockets ØMQ. N’importe quelle application cliente qui dispose de cette librairie peut alors soumettre des opérations à un cluster Elasticsearch sous forme de message ØMQ et exploiter la réponse obtenue en retour.
Le format des messages n’est pas imposé par la librairie ØMQ. Toutefois, le plugin pour Elasticsearch s’attend à des messages au format suivant :

<Method PUT,DELETE, POST...>|<URI, including parameters>|<JSON content>

Voici un exemple de message:

PUT|/library/book/1|{"title" : "Lucene in Action", "authors" : ["Michael McCandless", "Erik Hatcher", "Otis Gospodnetic"]}

Les réponses générées auront le format suivant:

<Status code>|<Status name>|<JSON reply content>

Par exemple:

201|CREATED|{"ok" : true, "_index" : "library", "_type" : "book", "_id" : "1", "_version" : 1}

Pour des questions de performances, le plugin ØMQ utilise une implémentation du pattern router-dealer:
Elasticsearch ZeroMQ Transport Plugin Architecture
Dans ce pattern, une socket “Router” écoute et réceptionne les messages entrants envoyés par les différents clients, la communication Client-Router s’effectuant via TCP.
Chaque message reçu est ensuite directement routé vers une seconde socket appelée “Dealer” au moyen d’une “Queue” (qui s’apparente à un canal de communication entre 2 sockets où chaque message reçu par l’une est directement transféré à l’autre).
Le rôle de la socket Dealer est de distribuer les messages réceptionnés entre plusieurs Workers chargés de les traiter de façon asynchrone (la communication Dealer-Workers s’effectue in-process sur un pattern request/reply). Ce sont ces Workers qui exécutent les opérations (indexation, recherche, administration) dans le cluster Elasticsearch. Le résultat de l’exécution de l’opération est ensuite encapsulé dans un message, puis envoyé comme réponse par le Worker au Dealer, puis du Dealer au Router, et enfin du Router au client à l’initiative du message d’origine.
Le plugin de transport ØMQ offre lui aussi de meilleures performances que le mode de transport HTTP tout en exposant l’intégralité de l’API REST.
Le plugin peut être installé avec la procédure habituelle. Son code source est disponible sur github.

Laisser un commentaire

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

En savoir plus sur Blog Zenika

Abonnez-vous pour poursuivre la lecture et avoir accès à l’ensemble des archives.

Continue reading