0

J'ai un problème étrange. J'ai un module en cours d'exécution sur gae qui met beaucoup de petites tâches sur la file d'attente de tâches par défaut. Les tâches accèdent au même module ndb. Chaque tâche accède à un tas de données à partir de quelques tables différentes puis appelle put.La contention de données ndb s'aggrave

Les premières tâches fonctionnent bien, mais que le temps continue, je commence à obtenir ces derniers sur le put final:

suspended generator _put_tasklet(context.py:358) raised TransactionFailedError(too much contention on these datastore entities. please try again.) 

J'Enveloppez la vente avec un essai et mis dans un délai aléatoire il retente quelques fois. Cela a atténué un peu le problème, cela arrive plus tard.

Voici quelques pseudo-code pour ma tâche:

def my_task(request): 
    stuff = get_ndb_instances() #this accessed a few things from different tables 
    better_stuff = process(ndb_instances) #pretty much just a summation 
    try_put(better_stuff) 
    return {'status':'Groovy'} 

def try_put(oInstance,iCountdown=10): 
    if iCountdown<1: 
     return oInstance.put() 
    try: 
     return oInstance.put() 
    except: 
     import time 
     import random 
     logger.info("sleeping") 
     time.sleep(random.random()*20) 
     return oInstance.try_put(iCountdown-1) 

Sans utiliser try_put la file d'attente obtient environ 30% du chemin à travers jusqu'à ce qu'il cesse de fonctionner. Avec le try_put, il va plus loin, comme 60%.

Est-ce qu'une tâche est en attente sur les connexions ndb après la fin de la connexion? Je n'utilise pas explicitement les transactions.

EDIT:

il semble y avoir une certaine confusion sur ce que je demande. La question est: pourquoi les conflits ndb s'aggravent avec le temps. J'ai beaucoup de tâches en cours d'exécution simultanément et ils accèdent au ndb d'une manière qui peut provoquer des conflits. Si la contention est détectée, une nouvelle tentative est effectuée, ce qui élimine parfaitement la contention. Pour un peu de temps. Les tâches continuent de s'exécuter et de s'exécuter et plus elles retournent avec succès, plus la contention est importante. Même si les processus utilisant les données contestées doivent être terminés. Y at-il quelque chose qui se passe sur les poignées de datastore qui ne devrait pas l'être? Que se passe-t-il?

EDIT2:

Voici un peu plus sur les structures clés en jeu:

Mes modèles NDB sont assis dans une hiérarchie où nous avons quelque chose comme ça (la direction des flèches spécifie les relations entre parents et enfants, à savoir: type a un tas d'instances d'enfants, etc.)

Type->Instance->Position 

les ids des positions sont limitées à quelques noms différents, il y a plusieurs milliers de cas et pas beaucoup de types.

Je calcule un tas de Positions, puis fais un try_put_multi (similaire à try_put d'une manière évidente) et obtient des conflits. Je vais lancer le code très bientôt et obtenir une trace complète à inclure ici.

+1

Avez-vous vraiment essayé/sauf? –

+0

Quelle est la structure de clé utilisée, quel type d'erreur de contention obtenez-vous? –

+0

Copie possible de ["Trop de contention" lors de la création d'une nouvelle entité dans le stock de données] (http://stackoverflow.com/questions/17308179/too-much-contention-when-creating-new-entity-in-datastore) –

Répondre

0

La contention s'aggravera si vous dépassez continuellement le groupe de 1 écriture/transaction par entité par seconde. La réponse est dans le fonctionnement de Megastore/Paxo et comment Cloud Datastore gère les contentions dans le backend.

Lorsque 2 écritures sont tentées en même temps sur différents nœuds dans Megastore, une transaction est gagnante et l'autre échoue. Cloud Datastore détecte cette contention et réessaie plusieurs fois la transaction ayant échoué. Habituellement, cela se traduit par la réussite de la transaction sans qu'aucune erreur ne soit signalée au client.

Si des tentatives d'écriture soutenues supérieures à la limite recommandée sont tentées, la probabilité qu'une nouvelle tentative de transaction soit répétée augmente. Le nombre de transactions dans un état de réessai interne augmente également. Finalement, les transactions commenceront à atteindre notre limite de réessai interne et retourneront une erreur de contention au client.

La méthode du sommeil aléatoire est une manière incorrecte de gérer les situations de réponse aux erreurs. Vous devriez plutôt regarder dans back-off exponentielle avec gigue (example).

De même, le cœur de votre problème est un taux d'écriture élevé dans un groupe d'entités unique. Vous devez vérifier si la fonction parentale explicite est requise (en la supprimant sinon) ou si vous devez partitionner le groupe d'entités d'une manière qui soit logique en fonction de vos requêtes et de vos exigences de cohérence.