2009-11-26 10 views
2

Je ne sais pas comment gérer cela dans un magasin de données BigTable.Dans une banque de données BigTable, en ce qui concerne la concurrence, comment "verrouiller" une entité?

Imaginez l'exemple suivant (juste pour expliquer le concept L'exemple ne correspond pas à mon modèle de données réelles.):

  • J'ai une entité de compteur qui assure le suivi du nombre de transactions dans mon dataStore. Supposons que le 'compte' actuel est 100.
  • Maintenant, deux requêtes Web lisent cette valeur en même temps.
  • Les deux requêtes Web ajoutent une nouvelle transaction
  • Et enfin les deux mettent à jour le compteur (à 101).

La valeur du compteur est maintenant inexacte. Il devrait être 102.

Des suggestions sur la façon de gérer cette situation? Puis-je "verrouiller" le compteur pour m'assurer que la seconde requête Web ne l'a pas encore lue jusqu'à ce que la première requête Web soit terminée?

Répondre

4

Vous avez plusieurs options:

  • Selon la portée de votre compteur et vos entités, ont les entités de transaction soient des entités enfants du compteur. Ensuite, vous pouvez insérer une transaction et mettre à jour le compteur transactionally. Gardez à l'esprit que cela limite votre taux de mise à jour à environ 1-5 QPS.
  • Si vos décomptes ne doivent pas être précis à 100%, insérez l'entité et mettez à jour le compteur (en utilisant une transaction à entité unique) séparément. Vous pouvez exécuter un cronjob régulier pour recompter le nombre d'entités et corriger le compteur si les erreurs le forcent à être désynchronisé.
  • Vous pouvez créer le vôtre limited distributed transaction support.
+0

Merci Nick. Quand vous dites "insérer une transaction", voulez-vous dire exécuter une fonction dans db.run_in_transaction? Quand je fais une "lecture" dans ma fonction transactionnelle, va-t-elle "verrouiller" l'objet et lancer une erreur si un autre thread essaie d'accéder à une valeur qui est maintenant "obsolète"? Merci, je suis encore nouveau dans la façon dont bigTable gère les transactions :) – willem

+0

Eh bien, vous avez appelé vos entités "Transactions", alors quand j'ai dit "insérer une transaction", je voulais dire "insérer une 'entité" de transaction ".Les lectures à l'intérieur des transactions sont transactionnelles, cependant, oui - seulement avec une concurrence optimiste plutôt qu'avec des verrous. –

1

En plus des options que Nick vous propose, vous pouvez envisager de partitionner le compteur.

Conserver plusieurs compteurs, et choisir un pour mettre à jour de manière à ce qu'il soit (idéalement) impossible ou (à défaut) improbable que deux demandes choisissent simultanément le même fragment.

Vous avez alors d'autres options. Vous pouvez faire une transaction avec le fragment en tant que parent (ce qui réduit la contention par rapport à un seul compteur), bien que vous vous retrouviez avec votre nouvelle entité Transaction ayant un parent choisi arbitrairement. Ou ne vous embêtez pas avec une transaction, auquel cas vous devrez probablement corriger le compte de temps en temps, comme avec l'option de non-transaction de Nick.

Pour lire le nombre total, vous additionnez tous les fragments. Vous ne les lirez pas tous «en même temps», mais c'est généralement bien. En lisant n'importe quel compteur, il peut augmenter entre quand vous le lisez, et quand vous utilisez la valeur, donc la valeur est vraiment juste une limite inférieure. L'addition des fragments n'est pas différente, sauf que cela prend probablement plus de temps.