Les 3 connexions du client couchbase java
Avant propos
Dans les exemples de ce billet, je travaille avec 1 cluster constitué de 3 noeuds.
Le cluster gère 2 buckets, sso et cache.
4 promesses
Quand on visite la page overview de couchbase server, on nous vante 4 mérites à ce produit :
- Scalabilité facile
- l’ajout et la suppression de noeud hyper simplifiée.
- Jamais d’indisponibilité
- toutes les opérations de maintenance cluster se font sans interruption.
- Haute performance
- la vitesse d’accès aux données est constante.
- Modèle flexible
- pas de shéma, on stocke ce que l’on veut.
Nous allons voir comment ces avantages sont mis en oeuvre côté client.
Création du client
La création d’un client se fait simplement en renseignant un (j’y reviendrai) des noeuds du cluster, le nom du bucket, et l’éventuel password.
Le client offre une API riche qui permet d’intéragir simplement avec couchbase, en faisant du clé/valeur ou en interrogeant des views.
Derrière cette simplicité se cache une machinerie assez lourde …
Phase de bootstrap
Quand on crée un client, on passe une baseList
.
Cette baseList
contient une liste d’URL sur laquelle les clients
peuvent interroger une API REST afin de découvrir la topologie
du cluster et d’initier une connexion vers un bucket.
La baseList
doit contenir l’URL d’au moins un des noeuds du cluster.
Côté serveur,
chaque bucket est dans une liste de buckets,
cette liste appartient à une pool,
et il existe plusieurs pools.
Le client va récupérer successivement ces informations du plus gros grain, la liste de pools, jusqu’au bucket qu’on lui a spécifié.
La récupération de la liste des pools se fait sur http://node1:8091/pools
On voit qu’il existe une seule pool, appelée default. On récupère
ses informations sur http://node1:8091/pools/default?uuid=b7e59676b22aecc10425b23507368662
Ensuite le client récupère la liste des buckets sur
http://node1:8091/pools/default/buckets?v=125187379&uuid=e9909bc948c7ad5a9358db43e0f1d32f
Après cette phase de bootstrap, le client dispose de toutes les informations requises pour se connecter au bucket et travailler dessus. Je détaillerai ces informations plus tard.
Les 3 types de connexion du client
Le client a 3 types de connexion :
- En vert, le bucket monitor, un canal par lequel le cluster informe le client de sa topologie.
- En jaune, le canal par lequel transite le protocol couchbase (set, get, delete, …)
- En rouge, le canal par lequel le client peut interroger les vues
Le client doit ouvrir un canal jaune et rouge sur chacun des noeuds. Le canal vert est ouvert sur l’un des noeuds seulement.
Le bucket monitor
Le bucket monitor permet au client de découvrit et d’être averti des modifications de topologie du cluster.
A la phase de bootstrap le client avait finalement récupéré la liste des buckets. En détail cela contient les noeuds auxquels il est rattaché, et où sont distribuées les clés.
Dans cette description l’une des infos est la fameuse streamingUri
.
Le client ouvre une connexion permanente dessus, dite de streaming,
genre Comet.
C’est via ce canal que le client est informé des modifications de
topologie du cluster (ajout d’un noeud, noeud en failover, …).
Quand une modification survient, le client se reconfigure automatiquement.
Communication avec couchbase (jaune)
Couchbase promet des temps d’accès aux données constants. Cela est notamment dû au fait que la charge de travail est répartie équitablement sur chaque noeud du cluster. En effet, une clé est sous la responsabilité d’un seul noeud et d’un seul.
Aussi, le client à la responsabilité d’envoyer ou de demander des clés directement au bon noeud du cluster. Par conséquence, le client doit se connecter à tous les noeuds du cluster afin de travailler avec n’importe quel clé.
A la phase de bootstrap, couchbase récupère l’intégralité des généralement adresses des noeuds du cluster et y ouvre une connexion TCP permanente, généralement sur le port 11210.
Répartition des clés
A la phase de bootstrap le client récupère la vBucketServerMap
.
Elle est constituée de 4 informations :
hashAlgorithm
: l’algorithme de hashage utilisé pour répartir les clés sur les noeuds. Ici, un simple CRCnumReplica
: le nombre de fois que la clé est répliquée.serverList
: le tableau des noeuds du cluster. L’ordre est importantvBucketMap
: la répartition des clés dans les noeuds du cluster.
C’est un tableau de 1024 éléments. Chaque élément est appelé virtual bucket. Cela permet de simuler un cluster de 1024 noeuds. Un virtual bucket est un tableau. Le nombre à l’indice 0 est le noeud dit master qui est responsable de la clé. Les indices suivants sont les noeuds replicas où sont stockées les répliques.
Avec ces informations, le client est en mesure de connaitre pour une
clé k
le noeud master et les noeuds replicas.
dans notre cas (pseudo code):
indiceVBucketMap = CRC(k) modulo 1024
noeud_master = vBucketMap[indiceVBucketMap][0]
noeud_replica1 = vBucketMap[indiceVBucketMap][1]
Le client a donc bien la responsabilité d’accéder au bon noeud. A l’insertion, il envoie la clé au noeud master et aux noeuds replicas. A la récupération, le client interroge le noeud master, éventuellement les replicas s’il est en failover. Pour s’en convaicre, cette méthode, expérimentale, renvoie l’addresse du noeud master pour une clé :
Canal des vues
Bien que l’interrogation d’une vue puisse se faire sur n’importe quel noeud, un canal dédié aux vues est ouvert sur chaque noeud du cluster.
Cela permet de répartir la charge en faisant du round robin sur la liste des noeuds.
4 promesses tenues ?
- Scalabilité facile
- Le bucket monitor permet de répondre automatiquement aux changements de topologie du cluster.
- Jamais d’indisponibilité
- Le client s’adapte sans redémarrage.
- Haute performance
- Les clés sont réparties uniformément sur tous les noeuds du cluster grâce au système de virtual bucket. Aussi, l’interrogation des vues ne se fait jamais sur le même noeud. Ainsi la charge du cluster est répartie sur tous les noeuds du client.
- Modèle flexible
- Au niveau de l’API, la clé est une chaine de caractère, et la
valeur est un
Object
sérialisable. Bref, c’est libre.
Conclusion
Couchbase réussit à tenir ses promesses en délégant pas mal d’intelligence au client: localisation des noeuds, réplication, …
Ce qu’on retient aussi c’est la lourdeur d’initialisation du client. Plus les noeuds du cluster sont nombreux, plus la phase d’initialisation prend du temps car le nombre de connexions TCP à ouvrir est assez impressionnant.
Il va sans dire (mais on le dit quand même) qu’il ne faut créer qu’une seule fois un client par application.