Tous les produits
Search
Centre de documentation

Tair (Redis® OSS-Compatible):Mettre en œuvre un verrouillage optimiste haute performance à l'aide de TairString

Dernière mise à jour :Aug 08, 2026

Lorsque plusieurs clients lisent et mettent à jour la même clé de manière concurrente, la dernière écriture écrase silencieusement toutes les précédentes. Il s'agit d'une condition de concurrence appelée « last-write-wins ». TairString, le type de données string étendu (exString) dans Tair (Enterprise Edition), intègre un numéro de version qui fait du verrouillage optimiste une opération native. Cela vous permet de détecter et de retenter les écritures conflictuelles sans recourir à des verrous externes ou à des transactions.

Fonctionnement du verrouillage optimiste basé sur les numéros de version

Le verrouillage optimiste associe un numéro de version à chaque clé. Lorsque vous lisez une clé, vous récupérez également sa version. Lors de l'écriture, vous fournissez la version que vous avez lue. Si un autre client a modifié la clé entre-temps, la version côté serveur a été incrémentée et ne correspond plus à la vôtre : l'écriture est rejetée au lieu d'être appliquée silencieusement. Vous pouvez alors retenter l'opération avec la valeur et la version mises à jour.

TairString résout nativement ce problème : les chaînes Redis natives se composent uniquement de clés et de valeurs, sans mécanisme permettant de détecter si une clé a changé entre une lecture et une écriture.

La condition de concurrence : pourquoi le principe « last-write-wins » entraîne une perte de données

Le diagramme suivant illustre une condition de concurrence typique.

Concurrent write race condition

Prenons l'exemple d'un compteur incrémenté simultanément par deux clients. Tous deux lisent la valeur actuelle (10), calculent indépendamment 11, puis réécrivent cette valeur. Le résultat final est 11 au lieu de 12 comme attendu : l'une des incréments est perdue silencieusement. Ce schéma s'applique à toute clé partagée :

  1. key_1 contient initialement la valeur hello.

  2. L'application 1 lit hello.

  3. L'application 2 lit hello.

  4. L'application 1 écrit world dans key_1.

  5. L'application 2 écrit universe dans key_1.

L'application 1 s'attend à ce que key_1 contienne world, mais la valeur réelle est universe. Pour éviter cela, la séquence lecture-modification-écriture doit être atomique, ce que garantit précisément le mécanisme de numérotation de version de TairString.

Commandes TairString pour le verrouillage optimiste

Les TairStrings se composent de clés, de valeurs et de numéros de version. TairString intègre toutes les fonctionnalités des chaînes Redis, à l'exception des opérations sur les bits.

Remarque

Les commandes TairString et les commandes natives des chaînes Redis ne sont pas interchangeables.

Commande Objectif Comportement
EXSET Créer une clé TairString Le numéro de version par défaut est 1
EXGET Interroger une clé TairString Renvoie à la fois value et version
EXSET avec version Mettre à jour avec vérification de version L'opération réussit et incrémente la version de 1 ; elle échoue avec l'erreur ERR update version is stale si la version ne correspond pas
EXCAS Compare-And-Swap en un seul appel Vérifie la version et applique l'écriture de manière atomique ; en cas d'échec, renvoie l'erreur, la valeur actuelle et la version actuelle dans une seule réponse

Pour la référence complète des commandes, consultez exString.

Implémenter le verrouillage optimiste avec EXGET et EXSET

Le modèle de base du verrouillage optimiste utilise une boucle de nouvelle tentative : lisez la valeur et la version actuelles avec EXGET, calculez la nouvelle valeur, puis écrivez avec EXSET en passant la version que vous avez lue. Si une écriture concurrente a eu lieu entre votre lecture et votre écriture, la vérification de version échoue et la boucle recommence.

while(true){
    {value, version} = EXGET(key);      // Retrieve the value and version number of the key.
    value2 = update(...);               // Save the new value as value 2.
    ret = EXSET(key, value2, version);  // Update the key and assign the return value to the ret variable.
    if(ret == OK)
       break;                           // If the return value is OK, the update is successful and the while loop exits.
    else if (ret.contains("version is stale"))
       continue;                        // If the return value contains the "version is stale" error message, the update fails and the while loop is repeated.
}

Cela garantit que si un autre client a mis à jour la clé après votre appel EXGET, votre appel EXSET échouera au lieu d'écraser silencieusement sa modification. Chaque itération de cette boucle nécessite deux allers-retours vers Tair : un EXGET pour lire la valeur et la version actuelles, et un EXSET pour tenter l'écriture.

Remarque
  • Lorsqu'une clé TairString est supprimée puis recréée avec le même nom, la nouvelle clé commence à la version 1. Elle n'hérite pas de la version précédente.

  • Pour ignorer la vérification de version et forcer l'écrasement d'une valeur, utilisez l'option ABS avec EXSET. Consultez EXSET pour plus de détails.

Réduire les E/S avec EXCAS

La boucle EXGET puis EXSET nécessite deux opérations d'E/S par cycle de nouvelle tentative. La commande EXCAS (Compare-And-Swap) réduit ce nombre à une seule opération d'E/S par cycle, ce qui constitue une amélioration significative en cas de forte concurrence.

EXCAS vérifie la version et applique l'écriture de manière atomique en un seul aller-retour. En cas d'échec, elle renvoie les trois éléments suivants dans une seule réponse :

  • "ERR update version is stale"

  • La valeur actuelle

  • Le numéro de version actuel

Étant donné que l'état actuel est inclus dans la réponse d'échec, le prochain cycle de nouvelle tentative peut démarrer immédiatement sans nécessiter d'appel EXGET supplémentaire.

while(true){
    {ret, value, version} = excas(key, new_value, old_version)    // Use the CAS command to replace the original value with a new value.
    if(ret == OK)
       break;                                                     // If the return value is OK, the update is successful and the while loop exits.
    else (if ret.contains("update version is stale"))            // If the return value contains the "update version is stale" error message, the update fails. The values of the value and old_version variables are updated.
       update(value);
       old_version = version;
 }

Rubriques connexes