2017-02-03 1 views
0

J'ai une tâche d'arrière-plan fonctionnant sous Celery sur Heroku, qui obtient fréquemment "Erreur R14 (quota de mémoire dépassé)" et "Erreur R15 (quota de mémoire largement dépassé)" de temps en temps. Je charge beaucoup de choses depuis la base de données (via Django sur Postgres), mais il faut charger un gros objet, le traiter, puis disposer de la référence et charger le prochain gros objet.Est-ce que les poubelles Python se rassemblent quand Heroku avertit que le quota de mémoire est largement dépassé (R15)?

Ma question est, est-ce que le garbage collector sait qu'il doit fonctionner avant d'atteindre la limite de mémoire d'Heroku? Dois-je lancer manuellement le gc?

Une autre chose est que ma tâche échoue parfois, puis Celery réessaye automatiquement, et il réussit. Cela devrait être déterministe. Je me demande si quelque chose traîne en mémoire après que la tâche soit terminée, et prend quand même de l'espace quand la prochaine tâche commence. Redémarrer le processus de travail efface la mémoire et la laisse réussir. Peut-être que Django ou la base de données a des caches qui ne sont pas effacés?

J'utilise la taille standard 2x. Je pourrais aller à performance-m ou performance-l, mais en essayant d'éviter cela car cela coûterait plus d'argent.

+1

Je doute que le processus python connaisse le quota de mémoire, donc je suppose qu'il n'exécute pas le garbage collector. Dans tous les cas, la récupération manuelle des ordures n'est utile que dans un petit nombre de cas limites où beaucoup de mémoire peut être libérée, mais les seuils de collecte automatique ne sont pas atteints. Il est plus probable que vous utilisiez simplement beaucoup de mémoire, auquel cas la récupération de place ne peut rien nettoyer. – knbk

+0

Pouvez-vous coller votre code de travail qui récupère des objets? Il y a probablement un problème ici, peut-être que vous n'utilisez pas un générateur ou que vous chargez des choses trop avec empressement. L'erreur de mémoire que donne Heroku signifie que vous commencerez à utiliser la mémoire d'échange (sur le disque), ce qui est très lent. Finalement, si vous atteignez 1,5x votre mémoire en échange, Heroku va redémarrer votre processus et le céleri ré-essayera tous les travaux. – rdegges

Répondre

0

On dirait que le problème est que je n'utilise pas .iterator() pour itérer sur le jeu de requête principal. Même si je libère les structures de données que je crée après chaque itération, les résultats de la requête sont tous mis en cache.

Malheureusement, je ne peux pas utiliser .iterator(), car j'utilise largement prefetch_related.

J'ai besoin d'une méthode hybride. Je pense que cela impliquera de traiter le queryset de haut niveau par lots. Il n'aura pas complètement l'avantage d'un nombre fini de requêtes que prefetch_related a, mais il sera mieux qu'une requête par objet de modèle.