etcd API
Ce document a pour objectif de présenter une vue d’ensemble des principes fondamentaux de l’API v3 d’etcd. Il ne doit pas être confondu avec l’API etcd v2, dépréciée à partir d’etcd v3.5. Il ne prétend pas être exhaustif, mais vise à se concentrer sur les idées de base nécessaires à la compréhension d’etcd, sans les distractions des appels d’API moins courants. Toutes les API etcd sont définies dans des services gRPC , qui catégorisent les appels de procédure distante (RPC) compris par le serveur etcd. Une liste complète de toutes les RPC etcd est documentée au format markdown dans le listing des API gRPC .
Services gRPC
Chaque requête d’API envoyée à un serveur etcd est un appel de procédure à distance gRPC. Les appels RPC dans etcd sont catégorisés selon leur fonctionnalité en services.
Les services importants pour la gestion de l’espace clé de etcd incluent :
- KV - Crée, met à jour, récupère et supprime des paires clé-valeur.
- Watch - Surveille les modifications apportées aux clés.
- Lease - Primitives pour consommer les messages de maintien de connexion client.
Les services qui gèrent le cluster lui-même incluent :
- Auth - Mécanisme d’authentification basée sur les rôles pour authentifier les utilisateurs.
- Cluster - Fournit des informations sur les membres et des fonctionnalités de configuration.
- Maintenance - Prend des instantanés de récupération, défait les fragments du magasin et retourne des informations d’état par membre.
Requêtes et réponses
Toutes les requêtes RPC dans etcd suivent le même format. Chaque RPC dispose d’une fonction Name qui prend NameRequest en argument et renvoie NameResponse en réponse. Par exemple, voici la description de la requête RPC Range :
En-tête de réponse
Toutes les réponses de l’API etcd incluent un en-tête de réponse qui contient des métadonnées du cluster pour la réponse :
- Cluster_ID - l’identifiant du cluster générant la réponse.
- Member_ID - l’identifiant du membre générant la réponse.
- Revision - la révision du magasin clé-valeur lors de la génération de la réponse.
- Raft_Term - le terme Raft du membre lors de la génération de la réponse.
Une application peut lire le champ Cluster_ID ou Member_ID pour s’assurer qu’elle communique avec le cluster (membre) prévu.
Les applications peuvent utiliser le champ Revision pour connaître la dernière révision du magasin clé-valeur. Cela est particulièrement utile lorsque les applications spécifient une révision historique afin d’effectuer une time travel query et souhaitent connaître la dernière révision au moment de la requête.
Les applications peuvent utiliser Raft_Term pour détecter quand le cluster termine une nouvelle élection de leader.
API clé-valeur
L’API Clé-Valeur manipule des paires clé-valeur stockées dans etcd. La majorité des requêtes adressées à etcd sont généralement des requêtes clé-valeur.
Primitives système
Paire clé-valeur
Une paire clé-valeur est l’unité minimale manipulable par l’API clé-valeur. Chaque paire clé-valeur possède un certain nombre de champs, définis au format protobuf :
- Clé - clé sous forme d’octets. Une clé vide n’est pas autorisée.
- Valeur - valeur sous forme d’octets.
- Version - version de la clé. Une suppression réinitialise la version à zéro, et toute modification de la clé augmente sa version.
- Révision_Création - révision de la dernière création sur la clé.
- Révision_Modification - révision de la dernière modification sur la clé.
- Bail - identifiant du bail attaché à la clé. Si le bail est égal à zéro, aucun bail n’est attaché à la clé.
En plus de la clé et de sa valeur, etcd attache des métadonnées de révision supplémentaires au message de clé. Ces informations de révision ordonnent les clés selon leur date de création et de modification, ce qui est utile pour gérer la concurrence dans la synchronisation distribuée. Les verrous partagés distribués du client etcd verrous partagés distribués utilisent la révision de création pour attendre la possession du verrou. De même, la révision de modification est utilisée pour détecter les conflits sur l’ensemble de lecture du mémoire transactionnelle logicielle et attendre les mises à jour du élection du leader .
Révisions
etcd maintient un compteur 64 bits valable pour l’ensemble du cluster, appelé révision du magasin, qui est incrémenté à chaque modification de l’espace clé. La révision sert d’horloge logique globale, ordonnant séquentiellement toutes les mises à jour du magasin. Le changement représenté par une nouvelle révision est incrémental ; les données associées à une révision sont celles qui ont modifié le magasin. En interne, une nouvelle révision signifie écrire les modifications dans l’arbre B+ du backend, indexées par la révision incrémentée.
Les révisions prennent davantage de valeur lorsqu’on considère le backend contrôle de concurrence à plusieurs versions d’etcd. Le modèle MVCC signifie que le magasin clé-valeur peut être consulté à partir de révisions passées, car les anciennes versions des clés sont conservées. La politique de conservation de cet historique peut être configurée par les administrateurs du cluster afin de gérer finement le stockage ; en général, etcd supprime les anciennes révisions des clés selon un horaire. Un cluster etcd typique conserve les données obsolètes des clés pendant plusieurs heures. Cela permet également une gestion fiable des déconnexions longues des clients, et non seulement des perturbations réseau transitoires : les observateurs reprennent simplement à partir de la dernière révision historique observée. De même, pour lire dans le magasin à un instant précis, les requêtes de lecture peuvent être étiquetées avec une révision afin de retourner les clés selon une vue de l’espace des clés au moment où cette révision a été validée.
Plages de clés
Le modèle de données etcd indexe toutes les clés dans un espace binaire plat. Cela diffère des autres systèmes de magasin clé-valeur qui organisent les clés selon une structure hiérarchique en répertoires. Au lieu de lister les clés par répertoire, les clés sont listées par intervalles de clés [a, b).
Ces intervalles sont souvent appelés « plages » dans etcd. Les opérations sur les plages sont plus puissantes que les opérations sur les répertoires. Comme un magasin hiérarchique, les plages permettent les recherches par clé unique via [a, a+1) (par exemple, [‘a’, ‘a\x00’) recherche ‘a’) et les recherches par répertoire en codant les clés selon leur profondeur dans l’arborescence. En plus de ces opérations, les plages peuvent également encoder des préfixes ; par exemple, la plage ['a', 'b') recherche toutes les clés dont le préfixe est la chaîne ‘a’.
Par convention, les plages pour une requête sont indiquées par les champs key et range_end. Le champ key est la première clé de la plage et doit être non vide. Le champ range_end est la clé suivant la dernière clé de la plage. Si range_end n’est pas fourni ou est vide, la plage est définie comme ne contenant que la clé fournie. Si range_end est égal à key plus un (par exemple, “aa”+1 == “ab”, “a\xff”+1 == “b”), alors la plage représente toutes les clés ayant pour préfixe la clé. Si les deux champs key et range_end sont égaux à ‘\0’, la plage représente toutes les clés. Si range_end est égal à ‘\0’, la plage correspond à toutes les clés supérieures ou égales à la clé fournie.
Plage
Les clés sont récupérées depuis le magasin clé-valeur à l’aide de l’appel d’API Range, qui prend un RangeRequest :
- Clé, PlageFin - Plage de clés à récupérer.
- Limite - nombre maximal de clés retournées pour la requête. Si la limite est définie à 0, elle est traitée comme sans limite.
- Révision - instantané du magasin clé-valeur à utiliser pour la plage. Si la révision est inférieure ou égale à zéro, la plage concerne le dernier magasin clé-valeur. Si la révision est compactée, la réponse renvoie ErrCompacted.
- OrdreTri - ordre de tri pour les requêtes triées.
- CibleTri - champ du magasin clé-valeur à trier.
- Sérialisable - active les lectures locales sérialisables pour la requête de plage. Par défaut, Range est linéarisable ; elle reflète le consensus actuel du cluster. Pour de meilleures performances et disponibilité, au prix de lectures potentiellement obsolètes, une requête de plage sérialisable est servie localement sans nécessiter de consensus avec les autres nœuds du cluster.
- ClésUniquement - ne retourne que les clés, et non les valeurs.
- ComptageUniquement - ne retourne que le nombre de clés dans la plage.
- MinRévisionMod - borne inférieure des révisions de modification des clés ; filtre les révisions inférieures.
- MaxRévisionMod - borne supérieure des révisions de modification des clés ; filtre les révisions supérieures.
- MinRévisionCréation - borne inférieure des révisions de création des clés ; filtre les révisions inférieures.
- MaxRévisionCréation - borne supérieure des révisions de création des clés ; filtre les révisions supérieures.
Le client reçoit un message RangeResponse de l’appel Range :
- Kvs - la liste des paires clé-valeur correspondant à la requête de plage. Lorsque
Count_Onlyest défini,Kvsest vide. - More - indique s’il reste des clés à renvoyer dans la plage demandée si
limitest défini. - Count - le nombre total de clés satisfaisant la requête de plage.
Pour les plages de clés importantes où le tamponnage de la réponse complète est indésirable, consultez RangeStream .
RangeStream
RangeStream retourne le même jeu de résultats que Range, mais le serveur fractionne la réponse en une séquence de morceaux et la diffuse au client. Cela évite de stocker entièrement de grandes plages en mémoire côté serveur ou côté client. RangeStream accepte les mêmes RangeRequest que Range.
Le client reçoit un flux de messages RangeStreamResponse à partir de l’appel RangeStream :
Remplissage des champs par tranches :
- Kvs - chaque tranche contient une tranche disjointe du résultat. En concaténant les
kvsde chaque tranche dans l’ordre de leur arrivée, on obtient le même ensemble de clés qu’une unique requêteRange. - Header, More, Count - renseignés uniquement dans la dernière tranche, et uniquement lorsque le flux se termine sans erreur. Les tranches précédentes laissent ces champs à zéro. Appliquer
proto.Mergesur lerange_responsede chaque tranche donne unRangeResponseéquivalent à ce queRangeaurait retourné.
Si le flux se termine avec une erreur, aucun morceau ne contient de header, more ou count valide.
Chaque morceau du flux est servi en référence à la même révision. Si la requête ne définit pas Revision, le serveur capture la dernière révision validée au moment du démarrage du flux et la réutilise pour le reste du flux.
RangeStream ne prend pas en charge les ordres de tri personnalisés ni les filtres de révision (min_mod_revision, max_mod_revision, min_create_revision, max_create_revision). Les requêtes utilisant l’un ou l’autre retournent Unimplemented. RangeStream n’est également pas pris en charge par le proxy gRPC etcd.
Il existe deux méthodes courantes pour consommer un RangeStream :
- Traitez chaque tranche indépendamment. Adapté aux scénarios à haute performance où le client souhaite décoder et agir sur les clés au fur et à mesure de leur arrivée, plutôt que de collecter l’ensemble du résultat d’abord. Le client itère les tranches et traite
kvsde chacune, puis litheader,moreoucountde la dernière tranche après la fin propre du flux. - Assemblez une seule réponse. Adapté lorsque le client souhaite obtenir un résultat équivalent à une requête unaire
Range. Le client fusionne chaquerange_responsede tranche en un seulRangeResponse(par exemple, à l’aide deproto.Merge). Le résultat fusionné contient l’intégralité dekvs, ainsi queheader,moreetcountprovenant de la dernière tranche. Le client Go fournitclientv3.GetStreamToGetResponsecomme aide pour ce schéma.
Mettre
Les clés sont stockées dans le magasin clé-valeur en émettant un appel à Put, qui prend un PutRequest :
- Clé - le nom de la clé à insérer dans le magasin clé-valeur.
- Valeur - la valeur, en octets, à associer à la clé dans le magasin clé-valeur.
- Bail - l’identifiant de bail à associer à la clé dans le magasin clé-valeur. Une valeur de bail égale à 0 indique l’absence de bail.
- Préc_Kv - lorsque défini, renvoie les données de la paire clé-valeur précédente à la mise à jour effectuée par cette
Putrequête. - Ignorer_Valeur - lorsque défini, met à jour la clé sans modifier sa valeur actuelle. Retourne une erreur si la clé n’existe pas.
- Ignorer_Bail - lorsque défini, met à jour la clé sans modifier son bail actuel. Retourne une erreur si la clé n’existe pas.
Le client reçoit un message PutResponse de l’appel Put :
- Prev_Kv - la paire clé-valeur écrasée par
Put, siPrev_Kva été défini dansPutRequest.
Supprimer une plage
Les plages de clés sont supprimées à l’aide de l’appel DeleteRange, qui prend un DeleteRangeRequest :
- Clé, PlageFin — Plage de clés à supprimer.
- ValeurPrécédente — si définie, retourne le contenu des paires clé-valeur supprimées.
Le client reçoit un message DeleteRangeResponse de l’appel DeleteRange :
- Supprimé - nombre de clés supprimées.
- Prev_Kv - liste de toutes les paires clé-valeur supprimées par l’opération
DeleteRange.
Transaction
Une transaction est une construction atomique If/Then/Else sur le magasin clé-valeur. Elle fournit une primitive pour regrouper des requêtes dans des blocs atomiques (c’est-à-dire then/else), dont l’exécution est protégée (c’est-à-dire if) en fonction du contenu du magasin clé-valeur. Les transactions peuvent être utilisées pour protéger les clés contre des mises à jour concurrentes non désirées, pour mettre en œuvre des opérations compare-and-swap, et pour développer des contrôles de concurrence de niveau supérieur.
Une transaction peut traiter atomiquement plusieurs requêtes en une seule requête. Pour les modifications du magasin clé-valeur, cela signifie que la révision du magasin n’est incrémentée qu’une seule fois pour la transaction, et que tous les événements générés par la transaction auront la même révision. Toutefois, les modifications apportées à la même clé plusieurs fois au sein d’une même transaction sont interdites.
Toutes les transactions sont protégées par une conjonction de comparaisons, similaire à une instruction If. Chaque comparaison vérifie une seule clé dans le magasin. Elle peut vérifier l’absence ou la présence d’une valeur, la comparer à une valeur donnée, ou vérifier la révision ou la version d’une clé. Deux comparaisons différentes peuvent s’appliquer à la même clé ou à des clés différentes. Toutes les comparaisons sont appliquées de manière atomique ; si toutes les comparaisons sont vraies, la transaction est considérée comme réussie et etcd applique le bloc de requête then / success, sinon elle est considérée comme échouée et applique le bloc de requête else / failure.
Chaque comparaison est encodée sous la forme d’un message Compare :
- Résultat - le type d’opération de comparaison logique (par exemple, égal, inférieur à, etc.).
- Cible - le champ clé-valeur à comparer. Soit la version de la clé, la révision de création, la révision de modification ou la valeur.
- Clé - la clé pour la comparaison.
- Cible_Union - les données spécifiées par l’utilisateur pour la comparaison.
Après le traitement du bloc de comparaison, la transaction applique un bloc de requêtes. Un bloc est une liste de messages RequestOp :
- Request_Range - une
RangeRequest. - Request_Put - une
PutRequest. Les clés doivent être uniques. Elle ne peut pas partager de clés avec d’autres opérations Put ou Delete. - Request_Delete_Range - une
DeleteRangeRequest. Elle ne peut pas partager de clés avec des requêtes Put ou Delete.
Ensemble, une transaction est émise par un appel API Txn, qui prend un TxnRequest :
- Compare - Une liste de prédicats représentant une conjonction de termes servant à protéger la transaction.
- Success - Une liste de requêtes à traiter si toutes les évaluations des tests Compare retournent true.
- Failure - Une liste de requêtes à traiter si l’une quelconque des évaluations des tests Compare retourne false.
Le client reçoit un message TxnResponse de l’appel Txn :
- Réussi - Indique si
Comparea été évalué à true ou false. - Réponses - Liste des réponses correspondant aux résultats de l’application du bloc
Successsi réussi est true, ou du blocFailuresi réussi est false.
La liste Responses correspond aux résultats de la liste RequestOp appliquée, chaque réponse étant encodée sous la forme d’un ResponseOp :
Le ResponseHeader inclus dans chaque réponse interne ne doit en aucun cas être interprété.
Si les clients doivent obtenir la dernière révision, ils doivent toujours vérifier le ResponseHeader au niveau supérieur dans TxnResponse.
API de surveillance
L’API Watch fournit une interface basée sur des événements pour surveiller de manière asynchrone les modifications apportées aux clés. Une surveillance etcd attend les modifications apportées aux clés en surveillant continuellement à partir d’une révision donnée, actuelle ou historique, et diffuse les mises à jour des clés vers le client.
Événements
Chaque modification de chaque clé est représentée par des messages Event. Un message Event fournit à la fois les données de la mise à jour et le type de mise à jour :
- Type - Le type d’événement. Un type PUT indique que de nouvelles données ont été stockées pour la clé. Un type DELETE indique que la clé a été supprimée.
- KV - La paire clé-valeur associée à l’événement. Un événement PUT contient la paire clé-valeur actuelle. Un événement PUT avec kv.Version=1 indique la création d’une clé. Un événement DELETE contient la clé supprimée, dont la révision de modification est définie sur la révision de la suppression.
- Prev_KV - La paire clé-valeur de la clé à la révision immédiatement antérieure à l’événement. Pour économiser la bande passante, cette information n’est renseignée que si la surveillance a explicitement activé cette fonctionnalité.
Surveillance des flux
Les surveillance sont des requêtes à exécution longue et utilisent des flux gRPC pour transmettre les données d’événements. Un flux de surveillance est bidirectionnel : le client écrit dans le flux pour établir des surveillance et lit pour recevoir les événements de surveillance. Un seul flux de surveillance peut multiplexer plusieurs surveillance distinctes en étiquetant les événements avec des identifiants propres à chaque surveillance. Cette multiplexion permet de réduire la charge mémoire et le surcroît de connexion sur le cluster central etcd.
Pour en savoir plus sur les garanties relatives aux événements de surveillance, veuillez consulter garanties de l’API etcd .
Un client crée une surveillance en envoyant un WatchCreateRequest sur un flux renvoyé par Watch :
- Clé, PlageFin - La plage de clés à surveiller.
- RévisionDébut - Une révision facultative à partir de laquelle commencer la surveillance de manière inclusive. Si elle n’est pas fournie, la diffusion en continu des événements suit la révision indiquée dans l’en-tête de réponse de création de surveillance. L’historique complet des événements peut être surveillé à partir de la dernière révision de compactage.
- NotificationProgression - Lorsqu’elle est définie, la surveillance reçoit périodiquement une réponse de surveillance sans événements, si aucun événement récent n’est disponible. Cela est utile lorsque les clients souhaitent récupérer un observateur déconnecté à partir d’une révision connue récente. Le serveur etcd détermine la fréquence d’envoi des notifications en fonction de la charge actuelle du serveur.
- Filtres - Liste des types d’événements à filtrer côté serveur.
- ValeurPrécédente - Lorsqu’elle est définie, la surveillance reçoit les données clé-valeur antérieures à l’événement. Cela est utile pour connaître les données qui ont été écrasées.
En réponse à un WatchCreateRequest ou si un nouvel événement est détecté pour une surveillance déjà établie, le client reçoit un WatchResponse :
- Watch_ID - l’identifiant de la surveillance correspondant à la réponse.
- Créé - défini à true si la réponse correspond à une requête de création de surveillance. Le client doit stocker l’identifiant et s’attendre à recevoir des événements pour cette surveillance sur le flux. Tous les événements envoyés à l’observateur créé auront le même watch_id.
- Annulé - défini à true si la réponse correspond à une requête d’annulation de surveillance. Aucun événement supplémentaire ne sera envoyé à l’observateur annulé.
- Révision_Compactée - défini à la révision historique minimale disponible dans etcd si un observateur tente de surveiller à une révision compactée. Cela se produit lorsqu’un observateur est créé à une révision compactée ou lorsque l’observateur ne parvient pas à suivre l’évolution du magasin clé-valeur. L’observateur sera annulé ; la création de nouvelles surveillances avec la même start_revision échouera.
- Événements - une liste d’événements nouveaux, dans l’ordre, correspondant à l’identifiant de surveillance donné.
Si le client souhaite cesser de recevoir des événements pour une surveillance, il émet un WatchCancelRequest :
- Watch_ID - l’ID de la surveillance à annuler afin qu’aucun événement supplémentaire ne soit transmis.
API bail
Les bails sont un mécanisme de détection de la disponibilité des clients. Le cluster accorde des bails avec une durée de vie. Un bail expire si le cluster etcd ne reçoit pas de keepAlive dans le délai TTL imparti.
Pour lier les bails au magasin clé-valeur, chaque clé peut être associée à au plus un bail. Lorsqu’un bail expire ou est révoqué, toutes les clés associées à ce bail sont supprimées. Chaque clé supprimée génère un événement de suppression dans l’historique des événements.
Obtention des bails
Les bails sont obtenus via l’appel d’API LeaseGrant, qui prend un LeaseGrantRequest :
- TTL - le délai d’expiration conseillé, en secondes.
- ID - l’identifiant demandé pour le bail. Si l’ID est défini à 0, etcd choisira un identifiant.
Le client reçoit un LeaseGrantResponse de l’appel LeaseGrant :
- ID - l’identifiant du bail pour le bail accordé.
- TTL - est le délai d’expiration, en secondes, sélectionné par le serveur pour le bail.
- ID - l’identifiant du bail à révoquer. Lorsque le bail est révoqué, toutes les clés associées sont supprimées.
Keep alives
Les bails sont actualisés à l’aide d’un flux bidirectionnel créé à l’aide de l’appel d’API LeaseKeepAlive. Lorsque le client souhaite actualiser un bail, il envoie un LeaseKeepAliveRequest sur le flux :
- ID - l’identifiant du bail dont il faut maintenir la validité.
Le flux de maintien de connexion répond avec un LeaseKeepAliveResponse :
- ID - le bail qui a été actualisé avec un nouveau délai de validité.
- TTL - le nouveau délai de validité, en secondes, restant pour le bail.