Elasticsearch et son 'tribe' node
On me demande parfois, dans des missions de conseil, de pouvoir et savoir faire du multi-site avec Elasticsearch.
Souvent cette demande vise l’interrogation de plusieurs sites, autonomes quant à leurs données applicatives, mais de manière centralisée, ou la mise en place de plans de reprise d’activité (PRA) à partir de sites distants ayant un même niveau de ‘fraîcheur’ des données que le site principal (réfléchir également à l’architecture suivante dans ce dernier cas).
Elasticsearch préconise de ne pas faire de multi-site en raison des temps de latence potentiellement grands entre les deux sites et tous les risques réseaux qui viennent s’ajouter à ceux qui existent déjà avec une installation de cluster sur un même sous-réseau (firewalls, routeurs, proxies …).
Pour ceux qui souhaitent tout de même faire ce genre de choses, une des solutions proposées par la société Elastic est le ‘tribe’ node:
- Voir ici pour plus de détails.
Le tribe node permet de créer un cluster qui regroupe d’autres clusters pour pouvoir y lire de manière quasi transparente ou même … y indexer des documents.
NB : Quelques restrictions tout de même sur des opérations de type méta : Voir les exceptions d’utilisation ici
Un ‘tribe’ node ne sert-il qu’au multi-site ?
Nous avons vu que le tribe node est préconisé par la société Elastic pour les accès multi-sites…
Mais il ne s’agit pas du seul cas d’utilisation !
Dans une approche ELK (Stack Elasticsearch/Logstash/Kibana), il peut aussi être utile de spécialiser une collecte des logs applicatives par branche métier.
Mais que faire en cas de composants transverses utilisés de manière indifférenciée par plusieurs de ces branches ?
Les questions deviennent alors :
- Où ces composants transverses doivent-ils déverser leur logs ?
- Peut-on interroger ces logs à partir des différentes branches métier ?
- Dois-je multiplexer les logs pour les stocker dans chaque référentiel métier de logs ?
- Devrai-je subir des coûts de stockage redondant ?
- …
Vous le sentez venir, le ‘tribe’ node est là pour vous aider.
Génèse d’un ‘tribe’ node
Paramètres
Nous allons présenter les paramètres à mettre en place pour la création d’un ‘tribe’ node.
Les clusters joints étant autonomes, ils sont déclarés et instanciés de manière classique sans aucun paramétrage particulier. La seule chose à vérifier est qu’aucun firewall ne bloque les communications TCP entrantes et sortantes sur le port 9300 par défaut pour chaque noeud et qu’aucun noeud n’est bindé en localhost pour être joignable via un nom d’hôte ou IP connus des autres machines.
Le ‘tribe’ node quant à lui doit avoir un paramétrage particulier pour chaque cluster que l’on souhaite y agréger.
Voici un exemple de déclaration d’un cluster à joindre au ‘tribe’ node dans le fichier config/elasticsearch.yml qui lui correspond :
tribe:
cluster_1:
cluster.name: cluster_1
discovery.zen.ping.multicast.enabled: false
discovery.zen.ping.unicast.hosts: ["169.254.186.228:9300"]
network.bind_host: 169.254.186.200
network.publish_host: 169.254.186.200
On note ici plusieurs points :
- chaque section sous ‘tribe’ représente un cluster (ici, ‘cluster_1’)
- chaque sous-section représente un cluster mais également un ‘local node’ qu’il va falloir binder à une adresse visible des noeuds composant les clusters joints.
- Ici, 169.254.186.200 représente l’adresse IP de la machine portant le ‘tribe’ node et le ‘tribe’ node local instancié pour joindre le cluster ‘cluster_1’.
- Le node name du ”tribe’ node local’ est dérivé du nom du ‘tribe’ node. Ex : ‘tribeNode/cluster_1’
- chaque sous-section doit avoir une section ‘discovery.zen.ping.unicast.hosts’ pour trouver les noeuds du cluster ‘cluster_1’ parmi les sous-réseaux accessibles. Ici, 169.254.186.228 représente l’adresse IP d’un noeud composant le cluster ‘cluster_1’
Voici l’ensemble du paramétrage avec 2 clusters joints ‘cluster_1’ et ‘cluster_2’ :
node.name: tribeNode
network.bind_host: 169.254.186.200
network.publish_host: 169.254.186.200
tribe:
cluster_1:
cluster.name: cluster_1
discovery.zen.ping.multicast.enabled: false
discovery.zen.ping.unicast.hosts: ["169.254.186.228:9300"]
network.bind_host: 169.254.186.200
network.publish_host: 169.254.186.200
cluster_2:
cluster.name: cluster_2
discovery.zen.ping.multicast.enabled: false
discovery.zen.ping.unicast.hosts: ["169.254.186.229:9300"]
network.bind_host: 169.254.186.200
network.publish_host: 169.254.186.200
Avec la table des correspondances suivantes:
Rôle | IP |
---|---|
‘tribe’ node | 169.254.186.200 |
Noeud du cluster ‘cluster_1’ | 169.254.186.228 |
Noeud du cluster ‘cluster_2’ | 169.254.186.229 |
Notes
Les index de chaque cluster ne doivent pas avoir de collision de nom entre les clusters regroupés.
Les noeuds de clusters différents peuvent avoir un nom identique.
Il est possible de créer des alias de même nom sur les différents clusters joints. Voir cas d’utilisation plus bas.
Tests grandeur nature
Pour le tester, nous allons prendre le cas d’utilisation de deux clusters elasticsearch dans lesquels nous souhaitons rechercher de manière transparente sans savoir de quel cluster viennent les données.
Exemple d’utilisation fréquent: Des logs sont centralisés par branche fonctionnelle mais des logs d’applications transverses doivent pouvoir être associées à ces thèmes fonctionnels pour un parcours des données dans Kibana…
Création des clusters et indexation des documents de test
- Pour créer et tester les clusters, installer sur les machines mentionnées plus haut un elasticsearch de dernière génération.
- Installer le plugin head grâce à la commande suivante exécutée à partir du répertoire d’installation :
$bin/plugin install mobz/elasticsearch-head
- Indexer les documents:
$curl - XPUT 'http://169.254.186.228:9200/index1_cluster_1/book/1' - d '{ "title": "The Hitchhikers Guide to the Galaxy", "author": "Douglas Adams" }' $curl - XPUT 'http://169.254.186.228:9200/index2_cluster_1/movie/1' - d '{ "title": "Star Wars", "creator": "George Lucas" }' $curl - XPUT 'http://169.254.186.229:9200/index1_cluster_2/movie/1' - d '{ "title": "Terminator", "creator": "James Cameron" }' $curl - XPUT 'http://169.254.186.229:9200/index2_cluster_2/book/1' - d '{ "title": "I, Robot", "author": "Isaac Asimov" }'
Chercher parmi tous les index de tous les clusters joints
$curl -XPOST http://169.254.186.200:9200/_search?pretty=true -d'{"query":{"match_all": {}}}'
{
"took": 7,
"timed_out": false,
"_shards": {
"total": 20,
"successful": 20,
"failed": 0
},
"hits": {
"total": 4,
"max_score": 1.0,
"hits": [{
"_index": "index1_cluster_1",
"_type": "book",
"_id": "1",
"_score": 1.0,
"_source": {
"title": "The Hitchhikers Guide to the Galaxy",
"author": "Douglas Adams"
}
}, {
"_index": "index1_cluster_2",
"_type": "movie",
"_id": "1",
"_score": 1.0,
"_source": {
"title": "Terminator",
"author": "James Cameron"
}
}, {
"_index": "index2_cluster_1",
"_type": "movie",
"_id": "1",
"_score": 1.0,
"_source": {
"title": "Star Wars",
"Creator": "George Lucas"
}
}, {
"_index": "index2_cluster_2",
"_type": "book",
"_id": "1",
"_score": 1.0,
"_source": {
"title": "I, Robot",
"author": "Isaac Asimov"
}
}]
}
}
Gestion des alias
Une bonne pratique de mise en oeuvre d’Elasticsearch nécessite l’utilisation des alias.
Ces alias permettent notamment de ne pas montrer aux utilisateurs les index réels qu’ils utilisent. Ceci est d’ailleurs très utile pour des opérations de maintenance comme un changement de mapping qui nécessite souvent une réindexation…
Avec un alias, vous l’aurez compris, pas besoin d’aller modifier des configurations d’applications utilisatrices pour basculer de l’ancien index avec son ancien mapping au nouveau. Il suffit de changer le ou les index pointés par l’alias…
Pour notre exemple, nous allons essayer de créer des alias de même noms mais sur des cluster différents pour voir si l’on peut à partir d’un seul nom d’alias, récupérer des documents de clusters différents…
$curl -XPOST http://169.254.186.228:9200/_aliases -d '{"actions":[{"add":{"index":"index1_cluster_1","alias":"index1_clusters"}}]}'
$curl -XPOST http://169.254.186.229:9200/_aliases -d '{"actions":[{"add":{"index":"index1_cluster_2","alias":"index1_clusters"}}]}'
Puis nous rechercherons sur cet alias:
$curl -XPOST http://169.254.186.200:9200/index1_clusters/_search?pretty=true -d'{"query":{"match_all": {}}}'
{
"took": 6,
"timed_out": false,
"_shards": {
"total": 10,
"successful": 10,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1.0,
"hits": [{
"_index": "index1_cluster_1",
"_type": "book",
"_id": "1",
"_score": 1.0,
"_source": {
"title": "The Hitchhikers Guide to the Galaxy",
"author": "Douglas Adams"
}
}, {
"_index": "index1_cluster_2",
"_type": "movie",
"_id": "1",
"_score": 1.0,
"_source": {
"title": "Terminator",
"creator": "James Cameron"
}
}]
}
}
Nous voyons que nous obtenons bien via un seul alias deux documents qui sont pourtant répartis sur deux clusters différents.
Conclusion
Le ‘tribe’ node est un outil puissant qui peut permettre de masquer la complexité d’une infrastructure tout en permetant d’avoir une urbanisation propre, peu coûteuse et modulaire.
Peu de redondance, un seul accès aux données, utilisation de manière transparente pour les clients, scalabilité…
Autant d’atouts qui doivent vous inciter à penser ‘tribu’ !
Tests réalisés avec l’aide de Pierre Raby.
Intéressant ! En admettant que les clusters ES soient dans le cloud (régions différentes, voire fournisseurs cloud différents), est-ce que ça fonctionne toujours ? Il y a une question de coût aussi car les flux de données sortants d’un cloud sont payants.
Je connais un peu moins les infrastructures cloud. Mais ce type de configuration me semble difficile à demander à un prestataire de paas … et certainement moins utile dans ces cas là;-)
Pour moi, si une entreprise demande à une autre de gérer son cluster dans le cloud, c’est au prestataire de voir et/ou proposer ses propres paramètres de déploiement multi-sites et de gérer la sécurité des données . Au client d’accepter ou non le contrat…
Bonjour TONY,
Merci pour cette présentation que je trouve très utile ,
Je suis dans le même cas et j’aimerai avoir des suggestions pour la mise en place de deux cluster ES (3 nodes chacun) , séparés dans deux sites distants .
Ma question est, peut-on avoir une architecture avec le TRIBE, ou il y aura des données identiques dans les deux clusters ( càd que les clusters vont fetcher la même data ). Le but final est d’avoir une sorte de tolérance aux pannes , si jamais le premier site(cluster est DOWN), on aura toujours le second qui répond .
Merci
Seddik