System Design

Lectures linéarisables dans les systèmes multi-régions

Construire des systèmes géographiquement distribués n'est plus un luxe ; c'est une exigence. Que ce soit pour la conformité réglementaire, l'optimisation de la latence ou la reprise après sinistre, les équipes déploient de plus en plus leurs applications sur plusieurs régions AWS ou zones Google Cloud. Cependant, le déplacement des données entre régions introduit un défi fondamental : maintenir des garanties de cohérence forte tout en conservant des performances acceptables. Dans cet article, nous explorerons comment implémenter des lectures linéarisables à l'aide de deux des principaux services de bases de données gérés : Google Cloud Spanner et Amazon DynamoDB.

Pourquoi la linéarisabilité est importante

La linéarisabilité est le niveau le plus élevé du modèle de cohérence dans la hiérarchie. Elle garantit que chaque lecture renvoie la valeur écrite par la dernière écriture terminée, et que chaque écriture est appliquée de manière atomique dans tout le système. Dans un contexte multi-régions, l'atteinte de cet objectif est difficile car les partitions réseau sont courantes et la distance physique introduit une latence significative. Sans linéarisabilité, les utilisateurs pourraient voir des données obsolètes après une écriture, ce qui entraîne des bugs critiques dans les transactions financières, la gestion des stocks ou les états de session. Pour les chemins critiques de votre application, les lectures linéarisables fournissent un filet de sécurité que les modèles de cohérence éventuelle ne peuvent tout simplement pas offrir.

Google Cloud Spanner : La vraie linéarisabilité

Spanner a été conçu dès le départ pour fournir une cohérence forte à l'échelle mondiale. Il utilise une technique appelée "TrueTime" pour gérer l'incertitude des horloges à travers plusieurs centres de données. Lorsque vous effectuez une lecture dans Spanner, vous pouvez spécifier le niveau d'isolation pour garantir la linéarisabilité. Par défaut, les lectures Spanner sont sérialisables, ce qui est même plus fort que la linéarisabilité, mais vous pouvez ajuster vos niveaux d'isolation pour des cas d'utilisation spécifiques.

from google.cloud import spanner

def get_account_balance(client, account_id):
    with client.snapshot(
        read_timestamp=None,  # Utilise la cohérence forte par défaut
        staleness=None,
        min_read_timestamp=None,
        max_staleness=None
    ) as snapshot:
        sql = "SELECT balance FROM Accounts WHERE id = @id"
        params = {"id": account_id}
        param_types = {"id": spanner.param_types.INT64}
        result = snapshot.execute_sql(sql, params=params, param_types=param_types)
        for row in result:
            return row[0]

Notez l'utilisation de read_timestamp=None dans l'instantané. Cela indique une lecture forte, qui attend l'horloge pour s'assurer que la lecture est linéarisable. Bien que cela introduise un petit délai dû à l'incertitude de l'horloge, cela garantit que vous ne lisez jamais une valeur qui a été remplacée par une écriture plus récente. Pour les lectures sensibles à la latence où un léger délai est acceptable, l'architecture de Spanner vous permet d'équilibrer efficacement la cohérence et la vitesse.

Amazon DynamoDB : Atteindre la linéarisabilité avec des lectures conditionnelles

DynamoDB est principalement un magasin à cohérence éventuelle, mais il offre une option de lecture "fortement cohérente". En définissant ConsistentRead=True dans votre requête de lecture, vous vous assurez que la lecture reflète la dernière écriture. Cependant, dans une configuration multi-régions utilisant DynamoDB Global Tables, l'atteinte d'une vraie linéarisabilité nécessite un traitement soigneux de la gestion des versions et des mises à jour conditionnelles.

DynamoDB Global Tables utilise par défaut une stratégie de résolution de conflits du type "le dernier écrivain gagne". Pour obtenir un comportement linéarisable, vous devez implémenter un vecteur de version ou une horloge logique dans votre couche applicative. Lorsqu'une écriture a lieu, vous incrémentez un numéro de version. Lors de la lecture, vous vous assurez que la lecture est cohérente avec la dernière version dans toutes les régions.

import boto3

dynamodb = boto3.client('dynamodb', region_name='us-east-1')

def get_item_strongly_consistent(table_name, key):
    response = dynamodb.get_item(
        TableName=table_name,
        Key=key,
        ConsistentRead=True
    )
    return response.get('Item')

Bien que ConsistentRead fournisse une cohérence forte au sein d'une région, la linéarisabilité inter-régions nécessite une logique supplémentaire. Un modèle pratique consiste à utiliser un jeton "lecture après écriture". Après une écriture, le client reçoit un ID d'écriture unique. Les lectures suivantes peuvent inclure cet ID pour s'assurer qu'elles ne renvoient pas de données obsolètes d'une autre région qui n'a pas encore synchronisé la dernière écriture. Cette approche imite la linéarisabilité au niveau applicatif, garantissant que les utilisateurs voient toujours l'état le plus récent.

Modèles pratiques pour l'implémentation

Lors de la conception de votre système, prenez en compte les modèles suivants :

  • Cohérence hybride : Utilisez des lectures linéarisables uniquement pour les chemins de données critiques, tels que les transactions financières ou l'authentification de session. Pour les autres données, telles que les journaux ou les analyses, la cohérence éventuelle est suffisante et plus rentable.
  • Réplicas de lecture avec jetons de cohérence : Dans DynamoDB, utilisez des lectures conditionnelles avec des numéros de version pour vous assurer que la lecture reflète la dernière écriture. Dans Spanner, exploitez les modèles de cohérence intégrés pour éviter la gestion manuelle des versions.
  • Prise en compte de la latence : Les lectures linéarisables introduisent une latence supplémentaire. Concevez votre API pour gérer cela de manière élégante, éventuellement en utilisant des mises à jour d'interface utilisateur optimistes où le client suppose le succès et se réconcilie avec le serveur plus tard.

Conclusion

L'implémentation de lectures linéarisables dans les systèmes multi-régions est une tâche complexe mais réalisable. Google Cloud Spanner fournit un support intégré pour la cohérence forte, ce qui en fait un choix simple pour les équipes qui privilégient la cohérence avant tout. Amazon DynamoDB offre de la flexibilité grâce à ses lectures fortement cohérentes et à la gestion des versions au niveau applicatif, permettant aux développeurs d'adapter leurs modèles de cohérence à des besoins spécifiques. En comprenant les compromis et en utilisant les bons outils, vous pouvez construire des systèmes multi-régions robustes qui maintiennent l'intégrité des données sans sacrifier les performances. À mesure que votre système évolue, rappelez-vous que la cohérence est un spectre, et choisir le bon niveau pour chaque chemin de données est la clé d'une architecture réussie.

Share: