Celery: Fuite de mémoire continue

Créé le 23 juin 2018  ·  129Commentaires  ·  Source: celery/celery

Il y a une fuite de mémoire dans le processus parent du worker de Celery.
Ce n'est pas un processus enfant exécutant une tâche.
Cela arrive soudainement tous les quelques jours.
Sauf si vous arrêtez Celery, il consomme la mémoire du serveur en des dizaines d'heures.

Ce problème se produit au moins dans Celery 4.1, et il se produit également dans Celery 4.2.
Celery fonctionne sur Ubuntu 16 et les courtiers utilisent RabbitMQ.

memory

Prefork Workers Pool RabbitMQ Broker Bug Report Critical Needs Testcase ✘ Needs Verification ✘ memory leak

Commentaire le plus utile

Pourquoi ce problème a-t-il été clos?

Tous les 129 commentaires

Utilisez-vous des flux de travail Canvas? Peut-être que # 4839 est lié.

Je suppose également que vous utilisez le pool Prefork pour la concurrence des travailleurs?

Merci georgepsarakis.

Je n'utilise pas de workflow.
J'utilise la concurrence prefork 1 sur un seul serveur.

Le taux d'augmentation semble assez linéaire, assez étrange. Le travailleur effectue-t-il des tâches pendant cette période? En outre, pouvez-vous ajouter une note avec la commande complète que vous utilisez pour démarrer le worker?

Oui. Le travailleur continue de traiter la tâche normalement.

Le worker est démarré avec la commande suivante.

/xxxxxxxx/bin/celery worker --app=xxxxxxxx --loglevel=INFO --pidfile=/var/run/xxxxxxxx.pid

Ce problème se produit à la fois dans l'environnement de production et dans l'environnement de test.
Je peux ajouter un profil de mémoire et une sortie de test à l'environnement de test.
Si je peux faire quelque chose, dites-moi quelque chose.

Nous devons comprendre ce que le worker exécute pendant le temps où l'augmentation de la mémoire est observée. Toutes les informations et détails que vous pourriez éventuellement fournir le seraient certainement. Il est également bon que vous puissiez reproduire cela.

Bien que ce cas se soit produit à un moment différent du graphique, le journal suivant a été produit au moment où la fuite de mémoire a commencé.

[2018-02-24 07:50:52,953: WARNING/MainProcess] consumer: Connection to broker lost. Trying to re-establish the connection...
Traceback (most recent call last):
File "/xxxxxxxx/lib/python3.5/site-packages/celery/worker/consumer/consumer.py", line 320, in start
blueprint.start(self)
File "/xxxxxxxx/lib/python3.5/site-packages/celery/bootsteps.py", line 119, in start
step.start(parent)
File "/xxxxxxxx/lib/python3.5/site-packages/celery/worker/consumer/consumer.py", line 596, in start
c.loop(*c.loop_args())
File "/xxxxxxxx/lib/python3.5/site-packages/celery/worker/loops.py", line 88, in asynloop
next(loop)
File "/xxxxxxxx/lib/python3.5/site-packages/kombu/async/hub.py", line 293, in create_loop
poll_timeout = fire_timers(propagate=propagate) if scheduled else 1
File "/xxxxxxxx/lib/python3.5/site-packages/kombu/async/hub.py", line 136, in fire_timers
entry()
File "/xxxxxxxx/lib/python3.5/site-packages/kombu/async/timer.py", line 68, in __call__
return self.fun(*self.args, **self.kwargs)
File "/xxxxxxxx/lib/python3.5/site-packages/kombu/async/timer.py", line 127, in _reschedules
return fun(*args, **kwargs)
File "/xxxxxxxx/lib/python3.5/site-packages/kombu/connection.py", line 290, in heartbeat_check
return self.transport.heartbeat_check(self.connection, rate=rate)
File "/xxxxxxxx/lib/python3.5/site-packages/kombu/transport/pyamqp.py", line 149, in heartbeat_check
return connection.heartbeat_tick(rate=rate)
File "/xxxxxxxx/lib/python3.5/site-packages/amqp/connection.py", line 696, in heartbeat_tick
self.send_heartbeat()
File "/xxxxxxxx/lib/python3.5/site-packages/amqp/connection.py", line 647, in send_heartbeat
self.frame_writer(8, 0, None, None, None)
File "/xxxxxxxx/lib/python3.5/site-packages/amqp/method_framing.py", line 166, in write_frame
write(view[:offset])
File "/xxxxxxxx/lib/python3.5/site-packages/amqp/transport.py", line 258, in write
self._write(s)
ConnectionResetError: [Errno 104] Connection reset by peer
[2018-02-24 08:49:12,016: INFO/MainProcess] Connected to amqp://xxxxxxxx:**@xxx.xxx.xxx.xxx:5672/xxxxxxxx

Il semble que cela se soit produit lorsque la connexion avec RabbitMQ a été temporairement coupée.

@marvelph donc cela se produit lors des reconnexions RabbitMQ? Peut-être que ces problèmes sont liés:

Oui.
Il semble que la reconnexion le déclenche.

On dirait que j'ai le même problème ... Il m'est si difficile de découvrir ce qui le déclenche et pourquoi il y a une fuite de mémoire. Cela m'énerve depuis au moins un mois. Je me replie sur le céleri utilisé 3 et tout va bien.

Pour le problème de fuite de mémoire, j'utilise ubuntu 16, céleri 4.1.0 avec rabbitmq. Je l'ai déployé via docker.

La fuite de mémoire est avec MainProcess et non ForkPoolWorker. L'utilisation de la mémoire de ForkPoolWorker est normale, mais l'utilisation de la mémoire de MainProcess augmente toujours. Pendant cinq secondes, environ 0,1 Mo de mémoire est divulgué. La fuite de mémoire ne démarre pas immédiatement après le début du travail, mais peut-être après un ou deux jours.

J'ai utilisé gdb et pyrasite pour injecter le processus en cours et essayer de gc.collect() , mais rien n'est collecté.

J'ai vérifié le journal, le consumer: Connection to broker lost. Trying to re-establish the connection... s'est produit, mais pour l'instant je ne suis pas sûr que ce soit le moment où une fuite de mémoire se produit.

Des conseils pour déboguer ce problème et savoir ce qui se passe réellement? Merci.

Puisque @marvelph a mentionné que cela pouvait être lié à la reconnexion de rabbitmq, j'essaie d'arrêter mon serveur rabbitmq. L'utilisation de la mémoire a augmenté après chaque reconnexion, voici le journal. Je peux donc confirmer ce problème https://github.com/celery/kombu/issues/843 .

Mais une fois la connexion reconnectée, l'utilisation de la mémoire cesse d'augmenter progressivement. Je ne suis donc pas sûr que ce soit la raison de la fuite de mémoire.

J'essaierai d'utiliser redis pour déterminer si ce problème de fuite de mémoire est lié ou non à rabbitmq.

[2018-06-25 02:43:33,456: WARNING/MainProcess] consumer: Connection to broker lost. Trying to re-establish the connection...
Traceback (most recent call last):
  File "/app/.heroku/python/lib/python3.6/site-packages/celery/worker/consumer/consumer.py", line 316, in start
    blueprint.start(self)
  File "/app/.heroku/python/lib/python3.6/site-packages/celery/bootsteps.py", line 119, in start
    step.start(parent)
  File "/app/.heroku/python/lib/python3.6/site-packages/celery/worker/consumer/consumer.py", line 592, in start
    c.loop(*c.loop_args())
  File "/app/.heroku/python/lib/python3.6/site-packages/celery/worker/loops.py", line 91, in asynloop
    next(loop)
  File "/app/.heroku/python/lib/python3.6/site-packages/kombu/asynchronous/hub.py", line 354, in create_loop
    cb(*cbargs)
  File "/app/.heroku/python/lib/python3.6/site-packages/kombu/transport/base.py", line 236, in on_readable
    reader(loop)
  File "/app/.heroku/python/lib/python3.6/site-packages/kombu/transport/base.py", line 218, in _read
    drain_events(timeout=0)
  File "/app/.heroku/python/lib/python3.6/site-packages/amqp/connection.py", line 491, in drain_events
    while not self.blocking_read(timeout):
  File "/app/.heroku/python/lib/python3.6/site-packages/amqp/connection.py", line 496, in blocking_read
    frame = self.transport.read_frame()
  File "/app/.heroku/python/lib/python3.6/site-packages/amqp/transport.py", line 243, in read_frame
    frame_header = read(7, True)
  File "/app/.heroku/python/lib/python3.6/site-packages/amqp/transport.py", line 418, in _read
    s = recv(n - len(rbuf))
ConnectionResetError: [Errno 104] Connection reset by peer
[2018-06-25 02:43:33,497: ERROR/MainProcess] consumer: Cannot connect to amqp://***:**@***:***/***: [Errno 111] Connection refused.
Trying again in 2.00 seconds...

[2018-06-25 02:43:35,526: ERROR/MainProcess] consumer: Cannot connect to amqp://***:**@***:***/***: [Errno 111] Connection refused.
Trying again in 4.00 seconds...

[2018-06-25 02:43:39,560: ERROR/MainProcess] consumer: Cannot connect to amqp://***:**@***:***/***: [Errno 111] Connection refused.
Trying again in 6.00 seconds...

[2018-06-25 02:43:45,599: ERROR/MainProcess] consumer: Cannot connect to amqp://***:**@***:***/***: [Errno 111] Connection refused.
Trying again in 8.00 seconds...

[2018-06-25 02:43:53,639: ERROR/MainProcess] consumer: Cannot connect to amqp://***:**@***:***/***: [Errno 111] Connection refused.
Trying again in 10.00 seconds...

[2018-06-25 02:44:03,680: ERROR/MainProcess] consumer: Cannot connect to amqp://***:**@***:***/***: [Errno 111] Connection refused.
Trying again in 12.00 seconds...

[2018-06-25 02:44:15,743: ERROR/MainProcess] consumer: Cannot connect to amqp://***:**@***:***/***: [Errno 111] Connection refused.
Trying again in 14.00 seconds...

[2018-06-25 02:44:29,790: ERROR/MainProcess] consumer: Cannot connect to amqp://***:**@***:***/***: [Errno 111] Connection refused.
Trying again in 16.00 seconds...

[2018-06-25 02:44:45,839: ERROR/MainProcess] consumer: Cannot connect to amqp://***:**@***:***/***: [Errno 111] Connection refused.
Trying again in 18.00 seconds...

[2018-06-25 02:45:03,890: ERROR/MainProcess] consumer: Cannot connect to amqp://***:**@***:***/***: [Errno 111] Connection refused.
Trying again in 20.00 seconds...

[2018-06-25 02:45:23,943: ERROR/MainProcess] consumer: Cannot connect to amqp://***:**@***:***/***: [Errno 111] Connection refused.
Trying again in 22.00 seconds...

[2018-06-25 02:45:46,002: ERROR/MainProcess] consumer: Cannot connect to amqp://***:**@***:***/***: [Errno 111] Connection refused.
Trying again in 24.00 seconds...

[2018-06-25 02:46:10,109: INFO/MainProcess] Connected to amqp://***:**@***:***/***
[2018-06-25 02:46:10,212: INFO/MainProcess] mingle: searching for neighbors
[2018-06-25 02:46:10,291: WARNING/MainProcess] consumer: Connection to broker lost. Trying to re-establish the connection...
Traceback (most recent call last):
  File "/app/.heroku/python/lib/python3.6/site-packages/celery/worker/consumer/consumer.py", line 316, in start
    blueprint.start(self)
  File "/app/.heroku/python/lib/python3.6/site-packages/celery/bootsteps.py", line 119, in start
    step.start(parent)
  File "/app/.heroku/python/lib/python3.6/site-packages/celery/worker/consumer/mingle.py", line 40, in start
    self.sync(c)
  File "/app/.heroku/python/lib/python3.6/site-packages/celery/worker/consumer/mingle.py", line 44, in sync
    replies = self.send_hello(c)
  File "/app/.heroku/python/lib/python3.6/site-packages/celery/worker/consumer/mingle.py", line 57, in send_hello
    replies = inspect.hello(c.hostname, our_revoked._data) or {}
  File "/app/.heroku/python/lib/python3.6/site-packages/celery/app/control.py", line 132, in hello
    return self._request('hello', from_node=from_node, revoked=revoked)
  File "/app/.heroku/python/lib/python3.6/site-packages/celery/app/control.py", line 84, in _request
    timeout=self.timeout, reply=True,
  File "/app/.heroku/python/lib/python3.6/site-packages/celery/app/control.py", line 439, in broadcast
    limit, callback, channel=channel,
  File "/app/.heroku/python/lib/python3.6/site-packages/kombu/pidbox.py", line 315, in _broadcast
    serializer=serializer)
  File "/app/.heroku/python/lib/python3.6/site-packages/kombu/pidbox.py", line 290, in _publish
    serializer=serializer,
  File "/app/.heroku/python/lib/python3.6/site-packages/kombu/messaging.py", line 181, in publish
    exchange_name, declare,
  File "/app/.heroku/python/lib/python3.6/site-packages/kombu/messaging.py", line 203, in _publish
    mandatory=mandatory, immediate=immediate,
  File "/app/.heroku/python/lib/python3.6/site-packages/amqp/channel.py", line 1732, in _basic_publish
    (0, exchange, routing_key, mandatory, immediate), msg
  File "/app/.heroku/python/lib/python3.6/site-packages/amqp/abstract_channel.py", line 50, in send_method
    conn.frame_writer(1, self.channel_id, sig, args, content)
  File "/app/.heroku/python/lib/python3.6/site-packages/amqp/method_framing.py", line 166, in write_frame
    write(view[:offset])
  File "/app/.heroku/python/lib/python3.6/site-packages/amqp/transport.py", line 275, in write
    self._write(s)
ConnectionResetError: [Errno 104] Connection reset by peer
[2018-06-25 02:46:10,375: INFO/MainProcess] Connected to amqp://***:**@***:***/***
[2018-06-25 02:46:10,526: INFO/MainProcess] mingle: searching for neighbors
[2018-06-25 02:46:11,764: INFO/MainProcess] mingle: all alone

Bien que j'aie vérifié les journaux, j'ai trouvé un journal de reconnexion au moment de la fuite de mémoire, mais il y avait aussi un cas où une fuite de mémoire a commencé au moment où la reconnexion ne s'est pas produite.
Je suis d'accord avec l'idée de jxlton.

De plus, lorsque j'utilisais Celery 3.x, je n'ai pas rencontré un tel problème.

Même problème ici
screenshot 2018-06-25 11 09 22
Tous les quelques jours, je dois redémarrer les travailleurs en raison de ce problème
il n'y a pas d'indices significatifs dans les journaux, mais je soupçonne que les reconnexions peuvent affecter; depuis que j'ai reconnecté des entrées de journal quelque part dans le temps lorsque la mémoire commence à augmenter constamment
Ma conf est ubuntu 17, 1 serveur - 1 travailleur avec 3 concurrences; lapin et redis sur le backend; tous les packages sont les dernières versions

@marvelph @ dmitry-kostin pourriez-vous s'il vous plaît fournir votre configuration exacte (en omettant bien sûr les informations sensibles) et éventuellement une tâche, ou un exemple, qui reproduit le problème? En outre, avez-vous une estimation de l'intervalle de temps de fonctionnement moyen auquel l'augmentation de la mémoire de travail commence à apparaître?

la configuration est proche de celle par défaut

importations = ('app.tasks',)
result_persistent = Vrai
task_ignore_result = Faux
task_acks_late = Vrai
worker_concurrency = 3
worker_prefetch_multiplier = 4
enable_utc = Vrai
timezone = 'Europe / Moscou'
broker_transport_options = {'visibilité_timeout': 3600, 'confirm_publish': True, 'fanout_prefix': True, 'fanout_patterns': True}

screenshot 2018-06-25 11 35 17
Fondamentalement, il s'agit d'un nouveau nœud déployé; il a été déployé le 21/06 18-50; a commencé à grandir le 23/06 vers 05h00 et s'est finalement écrasé le 23/06 vers 23h00

la tâche est assez simple et il n'y a pas de superlogique là-bas, je pense que je peux reproduire toute la situation sur un projet clair temporaire mais je n'ai pas de temps libre pour le moment, si j'ai de la chance, j'essaierai de faire un exemple complet le week-end

UPD
comme vous pouvez le voir, la tâche elle-même consomme de la mémoire, vous pouvez la voir par des pics sur le graphique, mais le moment où la mémoire a commencé à fuir il n'y avait aucune tâche produite ou aucune autre activité

@marvelph @ dmitry-kostin @jxltom J'ai remarqué que vous tracemalloc pour le processus? Vous devrez peut-être corriger le processus de travail pour enregistrer les traces d'allocation de mémoire, faites-moi savoir si vous avez besoin d'aide pour cela.

@georgepsarakis Vous voulez dire activer tracemalloc dans les statistiques des travailleurs et des journaux, comme les 10 principaux fichiers d'utilisation de la mémoire, à un intervalle spécifique tel que 5 minutes?

@jxltom Je pense que quelque chose comme ça aiderait à localiser la partie du code qui est responsable. Qu'est-ce que tu penses?

@georgepsarakis J'ai essayé d'utiliser gdb et https://github.com/lmacken/pyrasite pour injecter le processus de fuite de mémoire et démarrer le débogage via tracemalloc. Voici le top 10 des fichiers avec la plus forte utilisation de mem.

J'utilise resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024 et l'utilisation de la mémoire augmente progressivement.

>>> import tracemalloc
>>> 
>>> tracemalloc.start()
>>> snapshot = tracemalloc.take_snapshot()
>>> top_stats = snapshot.statistics('lineno')
>>> for stat in top_stats[:10]:
...     print(stat)
... 
/app/.heroku/python/lib/python3.6/site-packages/kombu/utils/eventio.py:84: size=12.0 KiB, count=1, average=12.0 KiB
/app/.heroku/python/lib/python3.6/site-packages/celery/worker/heartbeat.py:47: size=3520 B, count=8, average=440 B
/app/.heroku/python/lib/python3.6/site-packages/amqp/method_framing.py:166: size=3264 B, count=12, average=272 B
/app/.heroku/python/lib/python3.6/site-packages/celery/events/dispatcher.py:142: size=3060 B, count=10, average=306 B
/app/.heroku/python/lib/python3.6/site-packages/celery/events/dispatcher.py:157: size=2912 B, count=8, average=364 B
/app/.heroku/python/lib/python3.6/site-packages/amqp/abstract_channel.py:50: size=2912 B, count=8, average=364 B
/app/.heroku/python/lib/python3.6/site-packages/kombu/messaging.py:181: size=2816 B, count=12, average=235 B
/app/.heroku/python/lib/python3.6/site-packages/kombu/messaging.py:203: size=2816 B, count=8, average=352 B
/app/.heroku/python/lib/python3.6/site-packages/celery/events/dispatcher.py:199: size=2672 B, count=6, average=445 B
/app/.heroku/python/lib/python3.6/site-packages/amqp/channel.py:1734: size=2592 B, count=8, average=324 B

Voici la différence entre deux instantanés après environ 5 minutes.

>>> snapshot2 = tracemalloc.take_snapshot()
>>> top_stats = snapshot2.compare_to(snapshot, 'lineno')
>>> print("[ Top 10 differences ]")
[ Top 10 differences ]

>>> for stat in top_stats[:10]:
...     print(stat)
... 
/app/.heroku/python/lib/python3.6/site-packages/celery/worker/heartbeat.py:47: size=220 KiB (+216 KiB), count=513 (+505), average=439 B
/app/.heroku/python/lib/python3.6/site-packages/celery/events/dispatcher.py:142: size=211 KiB (+208 KiB), count=758 (+748), average=285 B
/app/.heroku/python/lib/python3.6/site-packages/amqp/method_framing.py:166: size=210 KiB (+206 KiB), count=789 (+777), average=272 B
/app/.heroku/python/lib/python3.6/site-packages/celery/events/dispatcher.py:157: size=190 KiB (+187 KiB), count=530 (+522), average=366 B
/app/.heroku/python/lib/python3.6/site-packages/amqp/abstract_channel.py:50: size=186 KiB (+183 KiB), count=524 (+516), average=363 B
/app/.heroku/python/lib/python3.6/site-packages/celery/events/dispatcher.py:199: size=185 KiB (+182 KiB), count=490 (+484), average=386 B
/app/.heroku/python/lib/python3.6/site-packages/kombu/messaging.py:203: size=182 KiB (+179 KiB), count=528 (+520), average=353 B
/app/.heroku/python/lib/python3.6/site-packages/kombu/messaging.py:181: size=179 KiB (+176 KiB), count=786 (+774), average=233 B
/app/.heroku/python/lib/python3.6/site-packages/amqp/channel.py:1734: size=165 KiB (+163 KiB), count=525 (+517), average=323 B
/app/.heroku/python/lib/python3.6/site-packages/kombu/async/hub.py:293: size=157 KiB (+155 KiB), count=255 (+251), average=632 B

Des suggestions sur la façon de continuer à déboguer cela? Je n'ai aucune idée de la façon de procéder. Merci.

@georgepsarakis

Je veux un peu de temps pour couper le projet pour la reproduction.

C'est la mise en céleri.

BROKER_URL = [
    'amqp://xxxxxxxx:[email protected]:5672/zzzzzzzz'
]
BROKER_TRANSPORT_OPTIONS = {}

Le planificateur a les paramètres suivants.

CELERYBEAT_SCHEDULE = {
    'aaaaaaaa_bbbbbbbb': {
        'task': 'aaaa.bbbbbbbb_cccccccc',
        'schedule': celery.schedules.crontab(minute=0),
    },
    'dddddddd_eeeeeeee': {
        'task': 'dddd.eeeeeeee_ffffffff',
        'schedule': celery.schedules.crontab(minute=0),
    },
}

Sur EC 2, j'utilise Supervisord pour le faire fonctionner.

@georgepsarakis
Étant donné que mon environnement de test peut tolérer une dégradation des performances, vous pouvez utiliser tracemalloc.
Pouvez-vous créer un céleri corrigé pour vider l'utilisation de la mémoire?

@jxltom Je parie que tracemalloc avec 5 minutes n'aidera pas à localiser le problème
Par exemple, j'ai 5 nœuds et seulement 3 d'entre eux ont eu ce problème au cours des 4 derniers jours, et 2 ont bien fonctionné pendant tout ce temps, il sera donc très difficile de localiser le problème.
J'ai l'impression qu'il y a une bascule qui s'allume, puis la mémoire commence à augmenter, jusqu'à ce que la consommation de mémoire de ce commutateur soit très bonne

J'ai essayé de savoir si des problèmes similaires se produisaient dans d'autres systèmes en cours d'exécution.
La fréquence d'occurrence varie, mais une fuite de mémoire s'est produite sur trois systèmes utilisant Celery 4.x, et cela ne s'est pas produit sur un système.
Le système qui a une fuite de mémoire est Python 3.5.x, et le système sans fuite de mémoire est Python 2.7.x.

@ dmitry-kostin Quelle est la différence avec les deux autres nœuds normaux, utilisent-ils tous les deux le même rabbitmq comme courtier?

Puisque notre discussion a mentionné que cela pouvait être lié à rabbitmq, j'ai commencé un autre nouveau nœud avec la même configuration, sauf pour utiliser redis à la place. Jusqu'à présent, ce nœud n'a pas de fuite de mémoire après 24 heures de fonctionnement. Je le posterai ici s'il y a une fuite de mémoire plus tard

@marvelph Voulez -vous dire que les trois systèmes avec une fuite de mémoire utilisent python3 alors que celui qui convient le mieux utilise python2?

@jxltom pas de différence du tout, et oui, ils sont sur python 3 & rabit en tant que courtier et redis sur le backend
J'ai fait un exemple de test pour reproduire ceci, si cela réussit dans quelques jours, je donnerai des informations d'identification à ce serveur pour quelqu'un qui sait comment localiser ce bogue

@jxltom
Oui.
En ce qui concerne mon environnement, les problèmes ne se produisent pas dans Python 2.

J'ai suivi la fuite de mémoire via tracemalloc sur une période plus longue.

L'utilisation de la mémoire de départ rapportée par le module resource est 146.58MB , après les 3,5 heures, il indique que l'utilisation de la mémoire est 224.21MB .

Voici la différence de cliché rapportée par tracemalloc

>>> snapshot2 = tracemalloc.take_snapshot(); top_stats = snapshot2.compare_to(snapshot, 'lineno')
>>> for stat in top_stats[:10]:
...     print(stat)
... 
/app/.heroku/python/lib/python3.6/site-packages/celery/worker/heartbeat.py:47: size=3619 KiB (+3614 KiB), count=8436 (+8426), average=439 B
/app/.heroku/python/lib/python3.6/site-packages/celery/events/dispatcher.py:142: size=3470 KiB (+3466 KiB), count=12529 (+12514), average=284 B
/app/.heroku/python/lib/python3.6/site-packages/amqp/method_framing.py:166: size=3418 KiB (+3414 KiB), count=12920 (+12905), average=271 B
/app/.heroku/python/lib/python3.6/site-packages/celery/events/dispatcher.py:157: size=3149 KiB (+3145 KiB), count=8762 (+8752), average=368 B
/app/.heroku/python/lib/python3.6/site-packages/amqp/abstract_channel.py:50: size=3099 KiB (+3096 KiB), count=8685 (+8676), average=365 B
/app/.heroku/python/lib/python3.6/site-packages/celery/events/dispatcher.py:199: size=3077 KiB (+3074 KiB), count=8354 (+8345), average=377 B
/app/.heroku/python/lib/python3.6/site-packages/kombu/messaging.py:203: size=3020 KiB (+3017 KiB), count=8723 (+8713), average=355 B
/app/.heroku/python/lib/python3.6/site-packages/kombu/messaging.py:181: size=2962 KiB (+2959 KiB), count=12952 (+12937), average=234 B
/app/.heroku/python/lib/python3.6/site-packages/amqp/channel.py:1734: size=2722 KiB (+2718 KiB), count=8623 (+8613), average=323 B
/app/.heroku/python/lib/python3.6/site-packages/kombu/async/hub.py:293: size=2588 KiB (+2585 KiB), count=4193 (+4188), average=632 B

Des idées? On dirait que ce n'est pas un seul fichier qui fuit?

J'ai également importé gc , et gc.collect() renvoie 0 ...

@georgepsarakis J'ai pu reproduire ceci, envoyez-moi un ping pour accéder aux crédits

Mise à jour: J'ai mis à jour le courtier de rabbitmq vers redis en mettant à jour l'url du courtier en tant que variable d'environnement et en gardant le docker / code complètement identique. Et il fonctionne pendant 4 jours et il n'y a pas de fuite de mémoire .

Je pense donc que ce problème est lié au courtier rabbitmq.

Si possible, essayez d'exécuter la commande de référence, mentionnée ici: https://github.com/celery/celery/issues/2927#issuecomment -171455414

Ce système exécute des ouvriers avec 20 serveurs.
Une fuite de mémoire s'est produite hier, mais elle se produit sur presque tous les serveurs en même temps.
memoryleak

Je ne sais pas si c'est lié, laissez-le ici au cas où cela aiderait.

J'ai un problème différent avec le céleri et le rabbitmq (le céleri perd la connexion et commence à se reconnecter plusieurs fois par seconde, le processeur passe à 100% sur 1 noyau, le battement ne peut pas envoyer de nouvelles tâches, il faut redémarrer le céleri).

La raison pour laquelle je signale ceci ici est le déclencheur: après des jours de surveillance, je pense avoir localisé le début du problème et il semble que rabbitmq déplace certains messages de la mémoire vers le disque. À ce moment-là, le céleri commence à essayer de se reconnecter aussi vite que possible et les journaux de rabbitmq montrent des dizaines d'opérations de connexion / déconnexion par seconde, par lots d'environ 10 à la fois. Le redémarrage de rabbitmq ne résout pas le problème, le redémarrage de céleri le résout tout de suite. Je n'ai pas de correctif approprié, mais à titre d'exemple, définir une politique d'expiration permettant aux messages de toujours rester en mémoire fonctionne autour du problème et je ne l'ai pas vu depuis.

Étant donné que certains détails de ce problème correspondent à ce que j'ai vu (échanger rabbitmq avec redis le corrige, il n'y a pas de point de départ clair, cela se produit sur plus d'un travailleur / serveur en même temps), je suppose qu'il pourrait y avoir un déclencheur commun et cela pourrait être le même que j'ai repéré.

La suite de tests passe de https://github.com/celery/celery/tree/master/funtests/stress à https://github.com/celery/cyanide et ne prend en charge que Python2.

Je le lance donc en Python2 avec rabbitmq comme courtier. Il a permis !join: connection lost: error(104, 'Connection reset by peer') recueillir

Voici le journal de la suite de tests.

➜  cyanide git:(master) pipenv run python -m cyanide.bin.cyanide
Loading .env environment variables…
Cyanide v1.3.0 [celery 4.2.0 (windowlicker)]

Linux-4.13.0-45-generic-x86_64-with-debian-stretch-sid

[config]
.> app:    cyanide:0x7fb097f31710
.> broker: amqp://**:**@**:**/cyanide
.> suite: cyanide.suites.default:Default

[toc: 12 tests total]
.> 1) manyshort,
.> 2) always_timeout,
.> 3) termbysig,
.> 4) timelimits,
.> 5) timelimits_soft,
.> 6) alwayskilled,
.> 7) alwaysexits,
.> 8) bigtasksbigvalue,
.> 9) bigtasks,
.> 10) smalltasks,
.> 11) revoketermfast,
.> 12) revoketermslow

+enable worker task events...
+suite start (repetition 1)
[[[manyshort(50)]]]
 1: manyshort                            OK (1/50) rep#1 runtime: 15.00 seconds/15.01 seconds
 1: manyshort                            OK (2/50) rep#1 runtime: 13.16 seconds/28.17 seconds
 1: manyshort                            OK (3/50) rep#1 runtime: 13.29 seconds/41.46 seconds
 1: manyshort                            OK (4/50) rep#1 runtime: 13.70 seconds/55.16 seconds
 1: manyshort                            OK (5/50) rep#1 runtime: 13.77 seconds/1.15 minutes
 1: manyshort                            OK (6/50) rep#1 runtime: 13.91 seconds/1.38 minutes
!join: connection lost: error(104, 'Connection reset by peer')
!Still waiting for 1000/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',)
!Still waiting for 1000/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',)
!Still waiting for 475/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',)
!Still waiting for 1000/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',)
!Still waiting for 1000/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',)
!Still waiting for 475/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',)
!Still waiting for 1000/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',)
!Still waiting for 1000/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',)
!join: connection lost: error(104, 'Connection reset by peer')
failed after 7 iterations in 3.12 minutes
Traceback (most recent call last):
  File "/home/***/.pyenv/versions/2.7.15/lib/python2.7/runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/home/***/.pyenv/versions/2.7.15/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/home/***/Documents/Python-Dev/cyanide/cyanide/bin/cyanide.py", line 62, in <module>
    main()
  File "/home/***/Documents/Python-Dev/cyanide/cyanide/bin/cyanide.py", line 58, in main
    return cyanide().execute_from_commandline(argv=argv)
  File "/home/***/.local/share/virtualenvs/cyanide-Vy3PQPTU/lib/python2.7/site-packages/celery/bin/base.py", line 275, in execute_from_commandline
    return self.handle_argv(self.prog_name, argv[1:])
  File "/home/***/.local/share/virtualenvs/cyanide-Vy3PQPTU/lib/python2.7/site-packages/celery/bin/base.py", line 363, in handle_argv
    return self(*args, **options)
  File "/home/***/.local/share/virtualenvs/cyanide-Vy3PQPTU/lib/python2.7/site-packages/celery/bin/base.py", line 238, in __call__
    ret = self.run(*args, **kwargs)
  File "/home/***/Documents/Python-Dev/cyanide/cyanide/bin/cyanide.py", line 20, in run
    return self.run_suite(names, **options)
  File "/home/***/Documents/Python-Dev/cyanide/cyanide/bin/cyanide.py", line 30, in run_suite
    ).run(names, **options)
  File "cyanide/suite.py", line 366, in run
    self.runtest(test, iterations, j + 1, i + 1)
  File "cyanide/suite.py", line 426, in runtest
    self.execute_test(fun)
  File "cyanide/suite.py", line 447, in execute_test
    fun()
  File "cyanide/suites/default.py", line 22, in manyshort
    timeout=10, propagate=True)
  File "cyanide/suite.py", line 246, in join
    raise self.TaskPredicate('Test failed: Missing task results')
cyanide.suite.StopSuite: Test failed: Missing task results

Voici le journal du travailleur.

➜  cyanide git:(master) pipenv run celery -A cyanide worker -c 1
Loading .env environment variables…

 -------------- celery@** v4.2.0 (windowlicker)
---- **** ----- 
--- * ***  * -- Linux-4.13.0-45-generic-x86_64-with-debian-stretch-sid 2018-07-03 12:59:28
-- * - **** --- 
- ** ---------- [config]
- ** ---------- .> app:         cyanide:0x7fdc988b4e90
- ** ---------- .> transport:   amqp://**:**@**:**/cyanide
- ** ---------- .> results:     rpc://
- *** --- * --- .> concurrency: 1 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- 
 -------------- [queues]
                .> c.stress         exchange=c.stress(direct) key=c.stress


[2018-07-03 12:59:29,883: WARNING/ForkPoolWorker-1] ! Still waiting for 1000/1000: [e6e71bed-8e58-4e7e-96c5-f56b583a37af, 42fd4f97-4ff5-4e0e-b874-89e7b3f0ff22, 3de45eeb-9b89-41bc-8284-95a4c07aa34a,...]: TimeoutError('The operation timed out.',) !
[2018-07-03 12:59:29,886: WARNING/ForkPoolWorker-1] ! Still waiting for 1000/1000: [e6e71bed-8e58-4e7e-96c5-f56b583a37af, 42fd4f97-4ff5-4e0e-b874-89e7b3f0ff22, 3de45eeb-9b89-41bc-8284-95a4c07aa34a,...]: TimeoutError('The operation timed out.',) !
[2018-07-03 12:59:30,964: WARNING/ForkPoolWorker-1] + suite start (repetition 1) +
[2018-07-03 12:59:30,975: WARNING/ForkPoolWorker-1] ---  1: manyshort                             (0/50) rep#1 runtime: 0.0000/0.0000 ---
[2018-07-03 13:01:07,835: WARNING/ForkPoolWorker-1] ! join: connection lost: error(104, 'Connection reset by peer') !
[2018-07-03 13:01:17,918: WARNING/ForkPoolWorker-1] ! Still waiting for 1000/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',) !
[2018-07-03 13:01:27,951: WARNING/ForkPoolWorker-1] ! Still waiting for 1000/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',) !
[2018-07-03 13:01:38,902: WARNING/ForkPoolWorker-1] ! Still waiting for 475/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',) !
[2018-07-03 13:01:48,934: WARNING/ForkPoolWorker-1] ! Still waiting for 1000/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',) !
[2018-07-03 13:01:58,961: WARNING/ForkPoolWorker-1] ! Still waiting for 1000/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',) !
[2018-07-03 13:02:09,906: WARNING/ForkPoolWorker-1] ! Still waiting for 475/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',) !
[2018-07-03 13:02:19,934: WARNING/ForkPoolWorker-1] ! Still waiting for 1000/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',) !
[2018-07-03 13:02:29,964: WARNING/ForkPoolWorker-1] ! Still waiting for 1000/1000: [1624cd7a-3cc0-474a-b957-b0484f6b4937, 2b436525-73de-4062-bd6b-924cbd11ba74, ce04cb5e-a99e-41e2-95dc-e9bc351e606d,...]: TimeoutError(u'The operation timed out.',) !
[2018-07-03 13:02:37,900: WARNING/ForkPoolWorker-1] ! join: connection lost: error(104, 'Connection reset by peer') !

J'ai mis à jour pour utiliser le céleri 3.1.25 avec la même suite de tests de stress, tout va bien.

BTW Pour tous ceux qui recherchent une solution rapide - le remplacement de lapin par redis résout le problème comme @jxltom l'a suggéré, j'ai plus d'une semaine de travail stable avec redis seulement maintenant
Le problème est donc certainement quelque part près de la bordure de lapin <-> céleri

@dieeasy, nous avons rencontré le même problème. Je suppose que vous utilisez le backend des résultats RPC. Si tel est le cas, essayez de passer au backend des résultats de base de données et voyez si cela aide. Le problème qui en cause est: https://github.com/celery/kombu/pull/779 et est expliqué ici: https://github.com/celery/kombu/pull/779#discussion_r134961611

J'ai le même problème de fuite de mémoire
Mémoire
image

Version
python 3.6.5 céleri 4.2.1 backend redis courtier rabbitmq

Config

[celery]
broker_url=amqp://taunt:[email protected]:5672/%2ftaunt
celery_result_backend=redis://xx.xx.xx.xx:6379
# 7days
celery_task_result_expires=604800
celery_task_serializer=msgpack
celery_result_serializer=json
celery_accept_content=json,msgpack
celery_timezone=Asia/Shanghai
celery_enable_utc=True

[cmd]
worker=True
proj=app.worker.celery
log_level=INFO
name=send_im%%h
queue=im
autoscale=10,3
concurrency=10

`` python

- - codage: utf-8 - -

à partir de la file d'attente d'importation de kombu, Exchange
à partir du journal d'importation oslo_log en tant que journalisation

depuis app.conf import CONF

LOG = logging.getLogger (__ nom__)

céleri_queues = (
File d'attente ('im', exchange = Exchange ('sender'), routing_key = 'im'),
File d'attente ('sms', exchange = Exchange ('sender'), routing_key = 'sms'),
File d'attente ('mail', exchange = Exchange ('sender'), routing_key = 'mail'),
File d'attente ('ivr', exchange = Exchange ('sender'), routing_key = 'ivr')
)

celery_routes = {
'sender.im': {'queue': 'im', 'routing_key': 'im'},
'sender.sms': {'queue': 'sms', 'routing_key': 'sms'},
'sender.mail': {'queue': 'mail', 'routing_key': 'mail'},
'sender.ivr': {'queue': 'ivr', 'routing_key': 'ivr'}
}

config = {
'COURTIER_URL': CONF.celry.broker_url,
'CELERY_RESULT_BACKEND': CONF.cellery.cellery_result_backend,
'CELERY_TASK_RESULT_EXPIRES': CONF.cellery.cellery_task_result_expires,
'CELERY_TASK_SERIALIZER': CONF.cellery.cellery_task_serializer,
'CELERY_RESULT_SERIALIZER': CONF.cellery.cellery_result_serializer,
'CELERY_ACCEPT_CONTENT': CONF.cellery.cellery_accept_content.split (','),
'CELERY_TIMEZONE': CONF.cellery.cellery_timezone,
'CELERY_ENABLE_UTC': CONF.cellery.cellery_enable_utc,
'CELERY_QUEUES': céleri_queues,
'CELERY_ROUTES': céleri_routes
}

**Startup**
```python

def make_command() -> list:
    log_path = f'{CONF.log_dir}{os.sep}{CONF.log_file}'
    command_name = f'{sys.path[0]}{os.sep}celery'
    command = [command_name, 'worker', '-A', CONF.cmd.proj, '-E']
    if CONF.cmd.log_level:
        command.extend(['-l', CONF.cmd.log_level])
    if CONF.cmd.queue:
        command.extend(['-Q', CONF.cmd.queue])
    if CONF.cmd.name:
        command.extend(['-n', CONF.cmd.name])
    # if CONF.cmd.autoscale:
    #     command.extend(['--autoscale', CONF.cmd.autoscale])
    if CONF.cmd.concurrency:
        command.extend(['--concurrency', CONF.cmd.concurrency])
    command.extend(['-f', log_path]) 
    return command


if CONF.cmd.worker:
    LOG.info(make_command())
    entrypoint = celery.start(argv=make_command())

Je peux fournir plus d'informations si nécessaire.

Pour ce que ça vaut, j'ai ce problème et je peux le reproduire de manière cohérente en ouvrant la console de gestion rabbitmq, en accédant aux connexions et en fermant les connexions avec le trafic de céleri à rabbitmq.

J'ai testé avec céleri 4.1 et 4.2 et rabbitmq 3.7.7-1
EDIT: également python version 3.6.5 et ubuntu 16.04 (image AWS EC2)

J'ai une fuite de mémoire avec le céleri 4.2.1 et le courtier redis. La mémoire passe de 100 Mio à 500 Mio (limité) en 3 heures, et les travailleurs sont marqués comme déconnectés en fleur. Prefork pool et gevent présentent le même problème.

@yifeikong ce n'est peut-être pas le même problème, mais pour votre cas, pourriez-vous essayer la solution proposée https://github.com/celery/celery/pull/4839#issuecomment -447739820?

@georgepsarakis J'utilise Python 3.6.5, donc je ne suis pas affecté par ce bogue. J'utiliserai tracemalloc pour faire quelques recherches. S'il s'agissait d'un bug du céleri, j'ouvrirai un nouveau numéro. Merci

Peut-être même cause avec # 5047 , il semble que ce bug puisse conduire à un phénomène différent.

Nous sommes confrontés à la même fuite de mémoire exécutant Celery 4.2.1, Kombu 4.2.2 et python3.6 avec RabbitMQ comme courtier.

$ celery --app=eventr.celery_app report

software -> celery:4.2.1 (windowlicker) kombu:4.2.2-post1 py:3.6.8
            billiard:3.5.0.5 py-amqp:2.4.0
platform -> system:Linux arch:64bit imp:CPython

Je peux dire que nous avons essayé beaucoup de choses que d'autres personnes ont mentionnées comme solutions de contournement possibles (redis en tant que courtier, en utilisant jemalloc, libamqp, chemin de singe __del__ sur AsyncResult ) mais nous avons toujours eu une fuite de mémoire.

En analysant notre journal, nous avons remarqué que nous avions beaucoup de messages liés aux battements de cœur manqués à cause des potins.

{"asctime": "2019-01-25 13:40:06,486", "levelname": "INFO", "name": "celery.worker.consumer.gossip", "funcName": "on_node_lost", "lineno": 147, "message": "missed heartbeat from celery@******"}

Une dernière chose que nous avons essayée était de désactiver les potins en exécutant les workers avec --without-gossip , étonnamment, la désactivation des potins avait un effet immédiat.

Tu peux le voir ici:
celery-memory-14d

Depuis que nous avons désactivé les potins dans deux projets exécutant des ouvriers céleri, la consommation de mémoire s'est améliorée.

Si vous faites attention, avant nous avions des pics de mémoire similaires à ceux décrits ici https://github.com/celery/celery/issues/4843#issuecomment -399833781

Une chose que j'ai essayé de comprendre pleinement, c'est quelles sont les implications de la désactivation complète des potins, puisqu'ils ne sont décrits que comme une communication entre les travailleurs <-> travailleurs, si quelqu'un pouvait faire la lumière à ce sujet, je serais très reconnaissant.

J'espère que cela aide et merci pour le travail acharné.

Pourquoi ce problème a-t-il été clos?

Il y a des commentaires et un intérêt actifs pour ce numéro, alors je rouvre.

Eh bien @georgepsarakis puisque nous avons diagnostiqué ma fuite comme n'étant pas # 4839, et que vous soupçonniez que c'était # 4843, je vais au moins passer à ce fil de fuite pour le moment. Je ne suis pas sûr que le numéro 4843 soit ma fuite non plus. Selon le problème initial sur ce fil:

Ce problème se produit au moins dans Celery 4.1, et il se produit également dans Celery 4.2.
Celery fonctionne sur Ubuntu 16 et les courtiers utilisent RabbitMQ.

Je suis actuellement sur:

python 2.7.12
Ubuntu 16.04.1 amd64
RabbitMQ 3.7.5

utilisant:

Céleri 4.1.1
librabbitmq 2.0.0
amqp 2.4.0
vigne 1.1.4
billard 3.5.0.5
kombu 4.2.2.post1
gevent 1.2.2

Cependant, Celery 4.1.1 + gevent 1.2.2 ne fuit pas pour moi (ni Celery 3.1.25 + gevent 1.2.2 AFAICT); Celery 4.2.1 + gevent 1.3.7 le fait. Malheureusement, gevent 1.3.7 et gevent 1.2.2 ne sont pas interchangeables pour démontrer (ou exclure) une bibliothèque gevent comme source possible du problème.

EDIT: Hmm ... il semble y avoir un correctif gevent (022f447dd) qui semble pouvoir corriger l'erreur que j'ai rencontrée. Je vais essayer de faire en sorte que cela fonctionne.

J'ai appliqué 022f447 à Celery 4.1.1 et installé gevent 1.3.7. Cette combinaison Celery + Gevent a fonctionné ... et a produit des modèles d'utilisation de la mémoire cohérents avec la fuite que j'ai rencontrée. Je vais installer Celery 4.2.1 + gevent 1.2.2 (avec le patch inverse) et voir si j'obtiens le modèle habituel d'utilisation de la mémoire.

Je remarque que gevent 1.4.0 est sorti. Peut-être que je devrais aussi faire un tourbillon pour voir comment cela se comporte.

Celery 4.2.1 + gevent 1.2.2 + patch inversé pour gevent 1.2.2 ne semble pas produire la fuite, tout comme Celery 4.2.1 + gevent 1.3.7.

Celery 4.2.1 + gevent 1.4.0 semble fuir à peu près au même taux que gevent 1.3.7 AFAICT.

https://github.com/celery/celery/blob/9f0a554dc2d28c630caf9d192873d040043b7346/celery/events/dispatcher.py

    def _publish(self, event, producer, routing_key, retry=False,
                 retry_policy=None, utcoffset=utcoffset):
        exchange = self.exchange
        try:
            producer.publish(...)
        except Exception as exc:  # pylint: disable=broad-except
            if not self.buffer_while_offline:  # <-- False by default
                raise
            self._outbound_buffer.append((event, routing_key, exc))  # <---- Always buffered

    def send(self, type, blind=False, utcoffset=utcoffset, retry=False,
            ...
            if group in self.buffer_group:   # <--- Never true for eventlet & gevent
                ...
                if len(buf) >= self.buffer_limit:
                    self.flush()     #  <---- Never flushed even when grows above limit
                ...
            else:
                return self.publish(type, fields, self.producer, blind=blind,
                                    Event=Event, retry=retry,

https://github.com/celery/celery/blob/b2668607c909c61becd151905b4525190c19ff4a/celery/worker/consumer/events.py

    def start(self, c):
        # flush events sent while connection was down.
        prev = self._close(c)
        dis = c.event_dispatcher = c.app.events.Dispatcher(
            ...
            # we currently only buffer events when the event loop is enabled
            # XXX This excludes eventlet/gevent, which should actually buffer.
            buffer_group=['task'] if c.hub else None,
            on_send_buffered=c.on_send_event_buffered if c.hub else None,
        )
        if prev:
            dis.extend_buffer(prev)
            dis.flush()    # <---- The only (!) chance to flush on [g]event[let] is on reconnect.

Maintenant, si je comprends bien ce que fait l'AMQP sous le capot, alors il a son propre rythme cardiaque et lorsqu'il détecte une connexion interrompue, il avance et se reconnecte sous le capot. Selon les types d'événements activés (potins, battements de cœur), cela peut fuir assez rapidement.
Cela devrait être vrai pour toutes les versions de eventlet et gevent, mais certaines pourraient présenter des problèmes de connexion qui aggraveraient / rendraient les choses plus visibles.

Salut,

Je soupçonne que nous avons le même problème.
Notre configuration est ci-dessous. Puis-je annuler ou confirmer qu'il s'agit du même problème abordé ici?

Python: 2,7
Céleri: 4.2.1
Système d'exploitation: version CentOS 6.10
Redis comme courtier

Dans l'image ci-jointe, vous pouvez voir:

  1. La consommation de mémoire augmente constamment et diminue au redémarrage.
  2. Le 13 janvier, nous sommes passés du céleri 3.1.25 à 4.2.1. La consommation de mémoire augmente le rythme.

image

METTRE À JOUR

Indépendamment de ce problème, nous sommes passés à python 3.6 et depuis, il semble que la fuite ne se produise plus.

image
(la mise à niveau a eu lieu le 19 février)

@georgepsarakis

Je ne sais pas à quel point cela est pertinent, mais mes 2 Go d'espace SWAP sont épuisés par le céleri en production. Arrêter Flower n'a pas effacé la mémoire, mais arrêter Celery l'a fait.

quelqu'un pourrait-il essayer le céleri 4.3rc1?

@auvipy J'ai installé Celery 4.3.0rc1 + gevent 1.4.0. pip a amélioré le billard à 3.6.0.0 et kombu 4.3.0.

Un peu perplexe, le fait que vine 1.2.0 ne soit pas également requis par le paquet rc1, étant donné que # 4839 est corrigé par cette mise à jour.

Quoi qu'il en soit, Celery 4.3.0 rc1 semble fonctionner correctement.

@ ldav1s merci beaucoup pour les commentaires. Ainsi, vine est déclaré comme une dépendance dans py-amqp en fait. Dans les nouvelles installations, la dernière version de vine sera installée mais cela peut ne pas se produire dans les versions existantes.

@thedrow peut-être

Ouvrons un numéro à ce sujet et discutons-en là.

Celery 4.3.0rc1 + gevent 1.4.0 fonctionne depuis quelques jours maintenant. On dirait qu'il fuit de la même manière que Celery 4.2.1 + gevent 1.4.0.

image

Avoir la même fuite avec céleri 4.2.1, python 3.6

Des mises à jour à ce sujet?

avoir le même problème ici

Les salutations,

Je rencontre un problème similaire, mais je ne suis pas sûr que ce soit la même chose.

Après avoir migré notre application de céleri dans un environnement / réseau différent, les ouvriers du céleri ont commencé à fuir. Auparavant, l'application céleri et l'instance rabbitmq se trouvaient dans le même environnement / réseau.

Ma configuration est sur Python 3.6.5:

amqp (2.4.2)
billiard (3.5.0.5)
celery (4.1.1)
eventlet (0.22.0)
greenlet (0.4.15)
kombu (4.2.1)
vine (1.3.0)

céleri

broker_url = rabbitmq
result_backend = mongodb
task_acks_late = True
result_expires = 0
task_default_rate_limit = 2000
task_soft_time_limit = 120
task_reject_on_worker_lost = True
loglevel = 'INFO'
worker_pool_restarts = True
broker_heartbeat = 0
broker_pool_limit = None

L'application est composée de plusieurs workers avec pool d'événements, démarrés via une commande dans supervisord:

[program:worker1]
command={{ celery_path }} worker -A celery_app --workdir {{ env_path }} -l info -E -P eventlet -c 250 -n worker1@{{ hostname }} -Q queue1,queue2

Le comportement de fuite de mémoire ressemble à ceci, toutes les ~ 10 heures généralement 1 travailleur, max 2 commencent à fuir:
image

J'ai donc créé un message de diffusion à exécuter sur chaque travailleur, pour utiliser tracemalloc, c'est le résultat de la commande top sur la machine, il n'y a qu'un seul travailleur qui fuit avec 1464m:

217m   1%   2   0% /usr/bin/python3 -m celery worker -A celery_app --workdir   379
189m   1%   0   0% /usr/bin/python3 -m celery worker -A celery_app --workdir   377     
1464m   9%   1   0% /usr/bin/python3 -m celery worker -A celery_app --workdir   378
218m   1%   0   0% /usr/bin/python3 -m celery worker -A celery_app --workdir   376 
217m   1%   2   0% /usr/bin/python3 -m celery worker -A celery_app --workdir   375
217m   1%   3   0% /usr/bin/python3 -m celery worker -A celery_app --workdir   394
163m   1%   0   0% /usr/bin/python3 -m celery beat -A celery_app --workdir /app

tracemalloc TOP 10 résultats sur le travailleur qui fuit

[2019-03-29 07:18:03,809: WARNING/MainProcess] [ Top 10: worker5<strong i="6">@hostname</strong> ]

[2019-03-29 07:18:03,809: WARNING/MainProcess] /usr/lib/python3.6/site-packages/eventlet/greenio/base.py:207: size=17.7 MiB, count=26389, average=702 B

[2019-03-29 07:18:03,810: WARNING/MainProcess] /usr/lib/python3.6/site-packages/kombu/messaging.py:203: size=16.3 MiB, count=44422, average=385 B

[2019-03-29 07:18:03,811: WARNING/MainProcess] /usr/lib/python3.6/site-packages/celery/worker/heartbeat.py:49: size=15.7 MiB, count=39431, average=418 B

[2019-03-29 07:18:03,812: WARNING/MainProcess] /usr/lib/python3.6/site-packages/celery/events/dispatcher.py:156: size=13.0 MiB, count=40760, average=334 B

[2019-03-29 07:18:03,812: WARNING/MainProcess] /usr/lib/python3.6/site-packages/eventlet/greenio/base.py:363: size=12.9 MiB, count=19507, average=695 B

[2019-03-29 07:18:03,813: WARNING/MainProcess] /usr/lib/python3.6/site-packages/amqp/transport.py:256: size=12.7 MiB, count=40443, average=328 B

[2019-03-29 07:18:03,814: WARNING/MainProcess] /usr/lib/python3.6/site-packages/celery/events/dispatcher.py:138: size=12.4 MiB, count=24189, average=539 B

[2019-03-29 07:18:03,814: WARNING/MainProcess] /usr/lib/python3.6/site-packages/amqp/transport.py:256: size=12.3 MiB, count=19771, average=655 B

[2019-03-29 07:18:03,815: WARNING/MainProcess] /usr/lib/python3.6/site-packages/amqp/connection.py:505: size=11.9 MiB, count=39514, average=317 B

[2019-03-29 07:18:03,816: WARNING/MainProcess] /usr/lib/python3.6/site-packages/kombu/messaging.py:181: size=11.8 MiB, count=61362, average=201 B

TOP 1 avec 25 cadres

TOP 1

[2019-03-29 07:33:05,787: WARNING/MainProcess] [ TOP 1: worker5<strong i="10">@hostname</strong> ]

[2019-03-29 07:33:05,787: WARNING/MainProcess] 26938 memory blocks: 18457.2 KiB

[2019-03-29 07:33:05,788: WARNING/MainProcess] File "/usr/lib/python3.6/site-packages/eventlet/greenio/base.py", line 207

[2019-03-29 07:33:05,788: WARNING/MainProcess] mark_as_closed=self._mark_as_closed)

[2019-03-29 07:33:05,789: WARNING/MainProcess] File "/usr/lib/python3.6/site-packages/eventlet/greenio/base.py", line 328

[2019-03-29 07:33:05,789: WARNING/MainProcess] timeout_exc=socket_timeout('timed out'))

[2019-03-29 07:33:05,790: WARNING/MainProcess] File "/usr/lib/python3.6/site-packages/eventlet/greenio/base.py", line 357

[2019-03-29 07:33:05,790: WARNING/MainProcess] self._read_trampoline()

[2019-03-29 07:33:05,790: WARNING/MainProcess] File "/usr/lib/python3.6/site-packages/eventlet/greenio/base.py", line 363

[2019-03-29 07:33:05,791: WARNING/MainProcess] return self._recv_loop(self.fd.recv, b'', bufsize, flags)

[2019-03-29 07:33:05,791: WARNING/MainProcess] File "/usr/lib/python3.6/site-packages/amqp/transport.py", line 440

[2019-03-29 07:33:05,791: WARNING/MainProcess] s = recv(n - len(rbuf))

[2019-03-29 07:33:05,792: WARNING/MainProcess] File "/usr/lib/python3.6/site-packages/amqp/transport.py", line 256

[2019-03-29 07:33:05,792: WARNING/MainProcess] frame_header = read(7, True)

[2019-03-29 07:33:05,792: WARNING/MainProcess] File "/usr/lib/python3.6/site-packages/amqp/connection.py", line 505

[2019-03-29 07:33:05,793: WARNING/MainProcess] frame = self.transport.read_frame()

[2019-03-29 07:33:05,793: WARNING/MainProcess] File "/usr/lib/python3.6/site-packages/amqp/connection.py", line 500

[2019-03-29 07:33:05,793: WARNING/MainProcess] while not self.blocking_read(timeout):

[2019-03-29 07:33:05,793: WARNING/MainProcess] File "/usr/lib/python3.6/site-packages/kombu/transport/pyamqp.py", line 103

[2019-03-29 07:33:05,794: WARNING/MainProcess] return connection.drain_events(**kwargs)

[2019-03-29 07:33:05,794: WARNING/MainProcess] File "/usr/lib/python3.6/site-packages/kombu/connection.py", line 301

[2019-03-29 07:33:05,794: WARNING/MainProcess] return self.transport.drain_events(self.connection, **kwargs)

[2019-03-29 07:33:05,795: WARNING/MainProcess] File "/usr/lib/python3.6/site-packages/celery/worker/pidbox.py", line 120

[2019-03-29 07:33:05,795: WARNING/MainProcess] connection.drain_events(timeout=1.0)

J'espère que cela pourrait aider, il n'y a aucune erreur dans les journaux, autre que le battement de cœur manqué entre les travailleurs. J'essaye maintenant d'utiliser la version exacte des bibliothèques que nous utilisions l'ancien env.

MISE À JOUR: En utilisant les mêmes versions de lib dépendances exactes et un battement de cœur de courtier toutes les 5 minutes, l'application a semblé stable pendant plus longtemps: plus de 2 jours, qu'elle n'a encore fui.

Il y avait un petit pic continuant pendant environ 1 heure de temps en temps, mais ils étaient "absorbés / collectés" .. le dernier semble avoir commencé le pic.

Après le 1er pic, 1ère rampe, j'ai redémarré l'ouvrier qui fuyait .. comme vous pouvez voir qu'un autre ouvrier a commencé à fuir après lui ou probablement il fuyait déjà, 2ème rampe.

image

Je vais tester sans battement de coeur.

MISE À JOUR: sans battement de cœur encore fuite après 2 jours, même comportement

440m   3%   1   0% /usr/bin/python3 -m celery worker -A celery_app --without-heartbeat --workdir /app -l info -E -P eventlet -c 250 -Ofair -n worker1@ -Q p_1_queue,p_2_queue
176m   1%   0   0% /usr/bin/python3 -m celery worker -A celery_app --without-heartbeat --workdir /app -l info -E -P eventlet -c 250 -Ofair -n worker2@ -Q p_1_queue,p_2_queue
176m   1%   2   0% /usr/bin/python3 -m celery worker -A celery_app --without-heartbeat --workdir /app -l info -E -P eventlet -c 250 -Ofair -n worker5@ -Q p_1_queue,p_2_queue
176m   1%   1   0% /usr/bin/python3 -m celery worker -A celery_app --without-heartbeat --workdir /app -l info -E -P eventlet -c 250 -Ofair -n worker3@ -Q p_1_queue,p_2_queue
176m   1%   1   0% /usr/bin/python3 -m celery worker -A celery_app --without-heartbeat --workdir /app -l info -E -P eventlet -c 250 -Ofair -n worker4@ -Q p_1_queue,p_2_queue
171m   1%   1   0% /usr/bin/python3 -m celery worker -A celery_app --without-heartbeat --workdir /app -l info -E -P eventlet -c 20 -n worker_p_root@ -Q p_root_queue
157m   1%   0   0% /usr/bin/python3 -m celery beat -A celery_app --workdir /app --schedule /app/beat.db -l info

image

METTRE À JOUR:
En utilisant céleri 4.3.0 il semble que le problème soit résolu et il est stable depuis une semaine
image

amqp (2.4.2)
billiard (3.6.0.0)
celery (4.3.0)
eventlet (0.24.1)
greenlet (0.4.15)
kombu (4.5.0)
vine (1.3.0)

S'il vous plaît laissez-moi savoir si je peux aider d'une manière ou d'une autre, en instrumentant le code. Si nécessaire, veuillez fournir des liens et des exemples.

Merci

J'ai aussi une fuite de mémoire. Il semble que j'ai réussi à trouver la cause.
https://github.com/celery/celery/blob/master/celery/events/dispatcher.py#L75
Je peux voir que ce tampon commence à se développer après des problèmes de connexion avec le lapin. Je ne comprends pas pourquoi il échoue finalement à effacer les événements, il continue de croître avec le temps et consomme de plus en plus de bélier. Passer buffer_while_offline=False ici https://github.com/celery/celery/blob/master/celery/worker/consumer/events.py#L43 semble corriger la fuite pour moi. Quelqu'un peut-il s'il vous plaît vérifier si cela est lié?

@ yevhen-m merci beaucoup! Cela nous a aidés à résoudre la fuite de mémoire!

C'est bien que nous ayons une solution de contournement, mais pouvons-nous s'il vous plaît trouver une solution appropriée?

suivre continuellement ce problème de fuite de mémoire

image

celery-pod-screencshot-lastweek

J'utilise du céleri dans un environnement de production et je le déploie via docker.
Comme la capture d'écran, nous avons le même problème.
Notre configuration de production est illustrée ci-dessous.

Image parent Docker: python 3.6.8-buster
Version céleri: 4.2.0
Options de commande:

  • concurrence 4
  • multiplicateur de prélecture 8
  • Aucun result_backend
  • acks_late et refuse_on_worker_lost

Je me demande si la mise à niveau de la version de céleri vers 4.3.0 résout le problème de fuite de mémoire.

Merci!

céleri 4.4.0 est la dernière écurie

Équipe, y a-t-il une mise à jour sur ce problème? Cela a-t-il été résolu et corrigé dans céleri 4.4.0?

Équipe, y a-t-il une mise à jour sur ce problème? Cela a-t-il été résolu et corrigé dans céleri 4.4.0?

Malheureusement non. Il est maintenant abordé.

Équipe, y a-t-il une mise à jour sur ce problème? Cela a-t-il été résolu et corrigé dans céleri 4.4.0?

il sera disponible à 4.4.1

il sera disponible à 4.4.1

est-ce corrigé dans la version actuelle 4.4.1?

@auvipy Le problème est toujours présent dans Celery 4.4.2 et 4.4.6. Nous constatons les mêmes fuites de mémoire sur tous les nœuds de calcul.

BROKER_POOL_LIMIT = None
CELERY_ACKS_LATE = False
CELERY_TRACK_STARTED = True
CELERYD_MAX_TASKS_PER_CHILD = 1
CELERYD_PREFETCH_MULTIPLIER = 1
BROKER_TRANSPORT_OPTIONS = {
    'fanout_prefix': True,
    'fanout_patterns': True,
    'visibility_timeout': 43200,
    'health_check_interval': 180,
    'socket_keepalive': True,
    'retry_on_timeout': True,
}

Le céleri ouvrier est démarré avec des indicateurs -O fair --without-heartbeat --without-gossip -c 1 -l . Nous utilisons également les indicateurs -n et -Q pour définir le nom du travailleur et les files d'attente. Fonctionnement en mode pré-fourche. Redis est configuré à la fois en tant que courtier et magasin de résultats.

image

~ Nous voyons de nombreux battements de cœur manqués sur des tâches de longue durée. Le problème signalé dans les problèmes liés persiste donc. ~

C'est la même chose avec les battements cardiaques désactivés.

@jsynowiec Quand j'ai rencontré ce problème, la seule chose qui fonctionnait pour moi était de gérer les travailleurs avec des potins désactivés, j'ai mentionné quelque chose à ce sujet ici https://github.com/celery/celery/issues/4843#issuecomment -459789086

Nous rencontrons le même problème avec céleri 4.4.2 et redis en tant que courtier. Sur une période de 48 heures, le céleri consomme jusqu'à 60 Go de RAM jusqu'à ce qu'il manque finalement de mémoire.
Aucune des solutions citées ici n'a eu d'effet sur ce comportement.

Nous rencontrons le même problème avec céleri 4.4.2 et redis en tant que courtier. Sur une période de 48 heures, le céleri consomme jusqu'à 60 Go de RAM jusqu'à ce qu'il manque finalement de mémoire.
Aucune des solutions citées ici n'a eu d'effet sur ce comportement.

Avez-vous essayé notre dernière version de correctif?
Avez-vous les mêmes conditions que l'OP?

Des fuites de mémoire sont toujours présentes sur la v4.4.6 Nous exécutons des workers avec les paramètres listés dans un commentaire précédent . OP utilise RabbitMQ, nous utilisons Redis en tant que courtier.

image

+1, notant que l'utilisation de la mémoire augmente progressivement sur 24 heures, même avec un travail minimal. Je pense que cette question devrait être rouverte.

pouvez-vous profiler et découvrir la racine de votre fuite de mémoire?

Des fuites de mémoire sont toujours présentes sur la v4.4.6 Nous exécutons des workers avec les paramètres listés dans un commentaire précédent . OP utilise RabbitMQ, nous utilisons Redis en tant que courtier.

image

Il semble que ce soit un problème différent ou que notre correctif n'était pas correct.
Puisque cela a résolu le problème du PO, c'est probablement un problème différent, non?

[2020-07-31 10:51:53,176: WARNING/MainProcess] /usr/local/lib/python3.8/site-packages/redis/client.py:90: size=19.2 KiB (+19.2 KiB), count=180 (+180), average=109 B
[2020-07-31 10:53:53,271: WARNING/MainProcess] /usr/local/lib/python3.8/site-packages/redis/client.py:90: size=230 KiB (+211 KiB), count=2160 (+1980), average=109 B
[2020-07-31 10:54:53,364: WARNING/MainProcess] /usr/local/lib/python3.8/site-packages/redis/client.py:90: size=250 KiB (+19.2 KiB), count=2340 (+180), average=109 B

....

[2020-07-31 12:24:10,633: WARNING/MainProcess] /usr/local/lib/python3.8/site-packages/redis/client.py:90: size=49.9 MiB (+76.8 KiB), count=478620 (+720), average=109 B
[2020-07-31 12:25:14,528: WARNING/MainProcess] /usr/local/lib/python3.8/site-packages/redis/client.py:90: size=49.9 MiB (+19.2 KiB), count=478800 (+180), average=109 B
[2020-07-31 12:27:22,346: WARNING/MainProcess] /usr/local/lib/python3.8/site-packages/redis/client.py:90: size=49.9 MiB (+57.6 KiB), count=479340 (+540), average=109 B
[2020-07-31 12:28:26,265: WARNING/MainProcess] /usr/local/lib/python3.8/site-packages/redis/client.py:90: size=50.2 MiB (+269 KiB), count=481860 (+2520), average=109 B

CELERY_RESULT_BACKEND = False CELERY_IGNORE_RESULT = True CELERY_MAX_TASKS_PER_CHILD = 1 CELERY_WORKER_PREFETCH_MULTIPLIER = 1 CELERY_TASK_RESULT_EXPIRES = 10 CELERY_BROKER_POOL_LIMIT = 70 CELERY_REDIS_MAX_CONNECTIONS = 100
app.conf.broker_transport_options = {'visibility_timeout': 43200}

celery -A proj worker --concurrency=70 --prefetch-multiplier=1 -Ofair --pool=gevent -n --without-gossip --without-mingle

Le client Redis perd de la mémoire? J'utilise céleri v4.4.6 avec gevent, redis en tant que courtier et aucun résultat.

C'est peut-être aussi un problème. C'est peut-être à Gevent?
CC @jamadden @andymccurdy
Pouvez-vous nous aider à résoudre ce problème et à vous assurer qu'aucune mémoire ne fuit de votre côté?

C'est peut-être à Gevent?

Nous n'utilisons pas gevent . Les ouvriers sont démarrés avec concurrence = 1 et prefork.

Salut les gars, je ne sais pas pourquoi ce problème est fermé, nous avons ce problème depuis 2 ans maintenant, mettant à jour la dernière version de Celery à chaque fois, et ayant toujours de gros serveurs (64-128 Go de RAM) constamment à court de RAM parce que de ces problèmes de fuite de mémoire.

Existe-t-il une solution de contournement sans revenir à Celery 3 ou remplacer Rabbitmq?

Cela rend Celery complètement instable dans les environnements de production, j'espère que cela peut être corrigé, nous ne pouvons pas revenir à Celery 3, nous prévoyons donc de passer à une autre solution (peut-être Dramatiq) afin de ne plus nous inquiéter du fait que Celery mange toute la RAM des serveurs. production tous les 2 jours.

@arielcamino - J'ai utilisé le paramètre worker_max_tasks_per_child pour remplacer les instances de worker après 100 ~ tâches, ce qui a aidé à maintenir l'utilisation de la mémoire, au moins pour mes serveurs. J'exécute de minuscules instances de 512 Mo et cela a aidé (auparavant, cela épuisait ma RAM), alors peut-être que cela vous aidera.

@Skowt wow, c'est super utile, merci beaucoup! J'essaierai tout de suite.

@arielcamino - J'ai utilisé le paramètre worker_max_tasks_per_child pour remplacer les instances de worker après 100 ~ tâches, ce qui a aidé à maintenir l'utilisation de la mémoire, au moins pour mes serveurs. J'exécute de minuscules instances de 512 Mo et cela a aidé (auparavant, cela épuisait ma RAM), alors peut-être que cela vous aidera.

Merci d'avoir partagé votre solution de contournement. Cela n'a pas aidé ici - nous utilisons cependant redis.

@thedrow Je ne suis au courant d'aucune fuite de mémoire dans redis-py. Si redis-py avait une fuite, je suppose que quelqu'un l'aurait rencontrée en dehors de l'environnement Celery et l'aurait signalée au suivi des problèmes redis-py.

Heureux d'aider là où je peux (j'utilise Celery w / Redis en tant que courtier sur plusieurs projets), mais je n'ai pas rencontré ce problème dans mes déploiements.

Je n'ai connaissance d'aucune fuite de mémoire dans les versions actuelles de gevent. Je suppose (j'espère) que quelqu'un aurait dit quelque chose s'il avait rencontré cela (cela s'est produit une ou deux fois auparavant). Mes déploiements actuels de gevent ont plusieurs travailleurs (Web et arrière-plan) pendant des semaines à la fois en utilisant beaucoup gevent et nous n'avons pas rencontré de fuites de mémoire.

Salut les gars, je ne sais pas pourquoi ce problème est fermé, nous avons ce problème depuis 2 ans maintenant, mettant à jour la dernière version de Celery à chaque fois, et ayant toujours de gros serveurs (64-128 Go de RAM) constamment à court de RAM parce que de ces problèmes de fuite de mémoire.

Existe-t-il une solution de contournement sans revenir à Celery 3 ou remplacer Rabbitmq?

Cela rend Celery complètement instable dans les environnements de production, j'espère que cela peut être corrigé, nous ne pouvons pas revenir à Celery 3, nous prévoyons donc de passer à une autre solution (peut-être Dramatiq) afin de ne plus nous inquiéter du fait que Celery mange toute la RAM des serveurs. production tous les 2 jours.

Combien de travailleurs avez-vous? Combien de tâches exécutez-vous? À quelle fréquence exécutez-vous ces tâches et combien de temps prennent-elles généralement pour se terminer?

La raison pour laquelle Rabbitmq / céleri commence à utiliser beaucoup de RAM peut être liée à la quantité de tâches en file d'attente. Si vous mettez trop de tâches en file d'attente et que les travailleurs ne peuvent pas toutes les terminer, cela agrandira la file d'attente et cette file d'attente utilisera de plus en plus de RAM et finira par consommer toute la RAM disponible. Je pense que ce problème pourrait également survenir avec Redis.

J'ai une autre théorie mais je veux d'abord savoir si cela pourrait être la raison de votre problème.

@ardilom désolé, je viens de réaliser que nous n'envoyons pas de données RabbitMQ au datadog, mais je vais essayer de clarifier notre situation, c'est ainsi que la RAM de certains serveurs diminue tous les 2 jours:
memory-leaks-1

Nous vérifions toujours le nombre de tâches en attente, et est normalement autour de 0 (ces données datent d'il y a quelques jours):

memory-leaks-2

Nous exécutons environ 250000 tâches par jour, nous avons environ 10 travailleurs, chacun avec environ 4 à 10 simultanés, le temps d'exécution moyen est d'environ 5 secondes, cela dépend du type de tâche.

Nous vérifions toujours messages_ready pour nous assurer qu'il n'y a pas trop de tâches en file d'attente (c'est ce que vous voyez dans la deuxième image), pensez-vous qu'il est correct de mesurer messages_ready ? Nous avons finalement quelques pics, mais normalement ils sont proches de 0.

Pour résoudre le problème, je redémarre simplement le travailleur Celery manuellement et l'utilisation de la RAM redevient normale.

Faites-moi savoir si vous avez besoin de quelque chose d'autre, je viens de changer le paramètre de worker_max_tasks_per_child sur l'un des serveurs de tâches, pour voir s'il y a une différence avec le reste après l'application de la configuration.

Merci!

Salut les gars, c'est pour confirmer que le changement de worker_max_tasks_per_child à 1000 dans mon cas, a corrigé le problème, merci encore @Skowt

Quelque chose que je n'ai pas mentionné hier, j'utilise le mode "prefork", peut-être que passer à gevent est une autre façon de résoudre le problème.

@arielcamino Ce problème a été résolu car nous avons résolu une fuite de mémoire spécifique. Nous n'avons pas encore trouvé une autre cause pour la fuite de mémoire. Nous savons qu'il y a un problème mais nous ne savons pas comment le reproduire.
Nous avons besoin de quelqu'un ayant accès à un environnement de production où le bogue se reproduit pour déboguer le problème.
Si nous n'en avons pas, nous devrons déterminer que ce problème ne peut pas être résolu.

Bonjour, pouvons-nous rouvrir ce numéro? Nous rencontrons des fuites similaires, en utilisant céleri == 4.4.7 (avec rabbitmq), nous avons le travailleur stable pendant quelques heures, parfois beaucoup plus, puis tout à coup commence à fuir lentement et finit par utiliser toute la mémoire.

Utilisation actuelle de prefork avec --concurrency=1 et le drapeau --max-tasks-per-child=100 ce qui ne semble pas aider car le processus parent semble être celui qui fuit.

celery_leak

Je peux fournir plus d'informations pour vous aider à déboguer ce problème.

Bonjour, pouvons-nous rouvrir ce numéro? Nous rencontrons des fuites similaires, en utilisant céleri == 4.4.7 (avec rabbitmq), nous avons le travailleur stable pendant quelques heures, parfois beaucoup plus, puis tout à coup commence à fuir lentement et finit par utiliser toute la mémoire.

Utilisation actuelle de prefork avec --concurrency=1 et le drapeau --max-tasks-per-child=100 ce qui ne semble pas aider car le processus parent semble être celui qui fuit.

celery_leak

Je peux fournir plus d'informations pour vous aider à déboguer ce problème.

rouvrir le problème n'est pas un gros problème, c'est l'intérêt de quelqu'un confronté à cela en production et aider à suivre et à apporter un correctif ou au moins à découvrir la cause de la fuite dans la production.

Je peux certainement aider, mais je suis à court d'idées sur ce qu'il faut faire, j'ai utilisé quelques outils mais je n'ai pas pu identifier grand-chose sur le problème. La seule chose qui le réduit un peu, ce sont les instantanés tracemalloc que j'ai pris, qui montrent l'augmentation de la mémoire aux mêmes endroits toutes les deux minutes environ. Voici le top 10 comparant deux instantanés:

/usr/local/lib/python3.8/site-packages/celery/events/dispatcher.py:148: size=259 KiB (+218 KiB), count=1026 (+867), average=259 B
/usr/local/lib/python3.8/site-packages/kombu/messaging.py:178: size=231 KiB (+194 KiB), count=1056 (+888), average=224 B
/usr/local/lib/python3.8/site-packages/amqp/connection.py:513: size=217 KiB (+182 KiB), count=703 (+591), average=316 B
/usr/local/lib/python3.8/site-packages/celery/events/dispatcher.py:214: size=207 KiB (+174 KiB), count=704 (+592), average=302 B
/usr/local/lib/python3.8/site-packages/kombu/messaging.py:200: size=204 KiB (+171 KiB), count=704 (+592), average=296 B
/usr/local/lib/python3.8/site-packages/amqp/transport.py:253: size=203 KiB (+171 KiB), count=703 (+591), average=296 B
/usr/local/lib/python3.8/site-packages/amqp/connection.py:508: size=184 KiB (+154 KiB), count=703 (+591), average=268 B
/usr/local/lib/python3.8/site-packages/celery/worker/consumer/consumer.py:445: size=182 KiB (+153 KiB), count=352 (+296), average=528 B
/usr/local/lib/python3.8/site-packages/amqp/channel.py:1758: size=169 KiB (+143 KiB), count=703 (+593), average=247 B
/usr/local/lib/python3.8/site-packages/kombu/asynchronous/hub.py:301: size=167 KiB (+140 KiB), count=351 (+295), average=486 B

Le problème existe toujours
Cela se produit lorsqu'une tâche de céleri accède au contexte de l'application pour effectuer une fonctionnalité
Il ne le libère ni ne le supprime après avoir effectué la tâche

--max-tasks-per-child=

n'a pas été utile

Bonjour, pouvons-nous rouvrir ce numéro? Nous rencontrons des fuites similaires, en utilisant céleri == 4.4.7 (avec rabbitmq), nous avons le travailleur stable pendant quelques heures, parfois beaucoup plus, puis tout à coup commence à fuir lentement et finit par utiliser toute la mémoire.
Utilisation actuelle de prefork avec --concurrency=1 et le drapeau --max-tasks-per-child=100 ce qui ne semble pas aider car le processus parent semble être celui qui fuit.
celery_leak
Je peux fournir plus d'informations pour vous aider à déboguer ce problème.

rouvrir le problème n'est pas un gros problème, c'est l'intérêt de quelqu'un confronté à cela en production et aider à suivre et à apporter un correctif ou au moins à découvrir la cause de la fuite dans la production.

pour moi si j'ajoute --max-tasks-per-child ça marche.
comme pour cet exemple d'arguments --autoscale=5,2 --max-tasks-per-child=40 le résultat est comme ceci

Screenshot 2020-08-13 at 2 26 13 PM

Bien que je pense qu'une récente mise à niveau du céleri a introduit la fuite de mémoire, je ne peux pas être totalement confiant. Je partagerai que le paramètre suivant a résolu la fuite.

Je ne peux pas dire quels paramètres sont valides par la documentation, donc je suis les paramètres de toutes ces valeurs dans mon fichier de paramètres Django.

CELERY_CONCURRENCY = CELERY_WORKER_CONCURRENCY = 1
CELERY_MAX_TASKS_PER_CHILD = CELERY_WORKER_MAX_TASKS_PER_CHILD = 1

Cela ne résout pas la fuite que nous constatons, comme cela se produit également dans la piscine gevent. Ce que j'ai remarqué, c'est que nous avons la file d'attente de céleriev assez chargée. Parce que le tracemalloc a montré la répartition des événements comme l'une des sources possibles de la fuite, j'ai explicitement désactivé les événements de tâche et désactivé notre instance de fleur, pour l'instant, il semble que la fuite ne se produit plus, je vais la laisser fonctionner pendant le week-end et partager les résultats ici.

sources possibles de la fuite J'ai explicitement désactivé les événements de tâche et désactivé notre instance de fleur

Point de données anecdotiques de quelqu'un qui a observé ce problème en silence depuis le début (et ne l'a jamais expérimenté directement): je suis au courant d'un autre projet (avec une charge de travail non négligeable pour le céleri) où faire ce qui précède a eu le même résultat: arrêter une fuite de mémoire. N'ayant que des informations de seconde main, je ne peux évidemment pas confirmer qu'il s'agissait du même problème sous-jacent (AFAIK, c'était rabbitmq, aucune idée de gevent, etc.), mais il est intéressant que cela soit corrélé.

Je soupçonne que cela a quelque chose à voir avec la connexion rabbitmq, la pile que nous avons observée cette fuite:

  • céleri (dernière version): soit prefork ou gevent pool, les deux montrent le même modèle de fuite.
  • rabbitmq (cloudamqp SaaS)
  • fleur

Nous avons vérifié toutes nos tâches à la recherche de fuites et n'avons trouvé aucune fuite, c'est pourquoi je soupçonne d'être quelque chose du côté du céleri.

Un fait intéressant est que nous avons actuellement de nombreux ouvriers en cours d'exécution, et j'ai remarqué que, une fois que l'on commence à fuir, cela apparaît également sur la fleur comme hors ligne.

Comme je n'avais plus d'idées où chercher, j'ai désactivé les événements de fleurs et de tâches et je continuerai à surveiller si la fuite reviendra ou non.

Je suis ouvert à croire que c'est une autre partie de ma pile qui fuit de la mémoire à ce stade. Le céleri a peut-être eu un comportement fortuit dans le passé qui a contribué à contrôler les fuites de mémoire, mais nous tous ensemble ne semble pas avoir suffisamment de problèmes similaires pour le confirmer. Je sais que beaucoup d'entre nous courent soit ...

  • Un grand nombre de tâches imbriquées à la fois, ou
  • Quelques monolithiques qui lancent le traitement multicœur au sein du travailleur

Dans ces cas, nous devons simplement être intelligents pour autoriser ou interdire un certain niveau de concurrence, de mise en file d'attente de tâches et de tâches par travailleur enfant. De plus, nous devrions tous utiliser des protections intégrées qui peuvent tuer les tâches gourmandes en mémoire avant qu'elles n'aient la possibilité de planter nos serveurs.

Un nombre croissant de personnes exécutent des processus lourds liés au processeur et à la mémoire dans le céleri, ce pour quoi il n'était pas vraiment fait, donc je pense que la documentation de démarrage rapide devrait inclure plus de détails à ce sujet.

Comme déjà mentionné dans mes commentaires précédents, nous exécutons des workers avec à la fois max-tasks-per-child et la concurrence définie sur 1 depuis longtemps. Cela ne fait rien contre les fuites de mémoire. De plus, nous utilisons Redis comme backend à la fois, courtier et résultats.

D'après mes observations, lorsque RabbitMQ est utilisé comme courtier, si la définition de max-tasks-per-child à 1 "résout" la fuite de mémoire, c'est probablement un problème avec l'implémentation de la tâche, pas le céleri.

Ce que nous observons et rapportons est différent. Même si nous laissons le travailleur inactif pendant plusieurs jours, sans traiter une seule tâche, il perd encore de la mémoire à un point où il atteint la limite de mémoire et est tué par le superviseur. Vous pouvez trouver plus de détails et de graphiques de mémoire dans les commentaires précédents.

Avec un travailleur traitant une seule tâche dans les délais prévus, le graphique de la mémoire devrait plus ou moins afficher une forme d'onde carrée, mais vous pouvez clairement voir que l'utilisation globale de la mémoire augmente.
Screenshot 2020-08-14 at 20 42 24

J'ai réussi à mettre le profilage des céleri-ouvrières sur notre feuille de route. Je partagerai les vidages de mémoire et plus de détails lorsque nous commencerons à travailler là-dessus.

Je peux confirmer que la désactivation de la fleur (et la désactivation explicite des événements de tâche via les paramètres) a corrigé la fuite.

Comme je l'ai mentionné précédemment, au moment où le travailleur a commencé à fuir, j'ai remarqué dans la fleur qu'elle se déconnecterait et que le céleriev était toujours assez occupé, alors j'ai suivi la voie facile et j'ai éteint la fleur.

Malheureusement, je n'ai pas pu trouver le morceau de code à l'origine de la fuite. Mais au moins, il y a ce travail autour.

alors probablement ce n'est pas un problème de céleri mais de fleur?

@auvipy flower déclenche le problème, mais la fuite se produit définitivement sur le travailleur (céleri)

@auvipy flower déclenche le problème, mais la fuite se produit définitivement sur le travailleur (céleri)

assez juste. Merci d'avoir partagé.

J'utilise Celery avec Redis et Flower, et je dois dire que je ne vois actuellement aucun problème de mémoire. Y a-t-il quelque chose que vous voulez de moi en ce qui concerne les données?

@auvipy n'utilise pas Flower. Les travailleurs sont démarrés avec les événements désactivés.

@auvipy n'utilise pas Flower. Les travailleurs sont démarrés avec les événements désactivés.

veuillez essayer de déboguer et trouver la racine de la fuite de mémoire. pourrait être du céleri ou votre pourrait. il serait préférable que vous puissiez partager les tests unitaires et d'intégration

veuillez essayer de déboguer et trouver la racine de la fuite de mémoire. pourrait être du céleri ou votre pourrait. il serait préférable que vous puissiez partager les tests unitaires et d'intégration

Mentionné ici , que nous voyons des MOO dus à une fuite de mémoire d'un ouvrier céleri même si aucune tâche n'est traitée par le travailleur.
Impossible de partager les tests unitaires ou d'intégration car cela exposerait la propriété intellectuelle de l'entreprise. Pardon. Mais j'ai réussi à ajouter une tâche pour capturer les vidages de mémoire sur les travailleurs de production sur notre feuille de route interne. Partagera des compteurs et des références pour quelques scénarios une fois terminé.

@jsynowiec Si vous pouvez le faire avant la version 5.0.0 GA (suivez # 6266 pour les mises à jour), ce serait génial.

Une fois qu'un correctif arrive dans master, il sera également rétroporté vers 4.x.

@thedrow Quand est-ce que GA de 5.0 est prévu? Malheureusement, nous avons du code hérité qui doit encore être migré vers Py3 😞 donc nous sommes bloqués avec Celery 4 pour le moment.

Nous avons un bloqueur de version et de la documentation à compléter.
La réponse est très bientôt.

Je peux confirmer que la désactivation de la fleur arrête la fuite. Nous fonctionnons sans fuite depuis près d'un mois maintenant.

Il y a donc encore un bogue quelque part dans notre mécanisme de publication d'événements.
Quelqu'un a-t-il une idée de ce que cela pourrait être?

Nous n'utilisons pas Flower et les workers sont démarrés sans --events , mais nous rencontrons des fuites de mémoire continues.

La réponse est très bientôt.

J'ai réussi à attribuer une priorité élevée à l'obtention de vidages de mémoire et de compteurs d'objets des travailleurs de la production. Je devrais pouvoir publier des données dans les semaines à venir. Nous avons également élevé la priorité sur la finalisation du portage py2-> py3 afin que tout soit exécuté et profilé à l'aide de Python 3

Ce qui m'inquiète, c'est que nous parlons ici de deux problèmes différents.

Apparemment. L'un est lié aux événements et peut-être à Flower, utilisant peut-être aussi RabbitMQ en tant que courtier. Selon les problèmes rapportés ici, sur GitHub, cela fait surface ici et là depuis quelques années. L'autre (qui affecte mon projet) est lié à différents composants et très probablement lié à l'utilisation de Redis en tant que courtier. Ou peut-être à la racine, ce sont les mêmes problèmes qui proviennent du même code qui sait 🤷🏼. Comme celui avec trail gardant une trace des sous-tâches et des instances de fuite de AsyncResult 😉

@thedrow @auvipy Je vous

De plus, lors de la finalisation de la migration Python3, nous avons rencontré un autre problème qui semble lié à https://github.com/celery/celery/issues/4470 ou https://github.com/celery/celery/issues/5359. Sous certaines conditions sur les systèmes Linux, lors de l'utilisation de Redis comme courtier, les appels à join_native bloquent indéfiniment bien que toutes les tâches du groupe soient déjà effectuées. Un strace rapide indique qu'il est littéralement suspendu à la lecture, ce qui peut indiquer des éléments de bas niveau du noyau / lib. Pour l'instant, nous sommes passés au plain, regroupant join en nous concentrant sur les fuites de mémoire.

Bonjour à tous - enfin certaines données: céleri-memtrace-1.tar.xz , signature , ma clé .

L'archive contient tracemalloc logs de 8 nœuds de calcul après ~ 16 jours, un graphique d'utilisation de la mémoire pour la période et des informations sur la version (y compris la bannière de démarrage de Celery).

Honnêtement, je n'ai pas passé beaucoup de temps à analyser tout cela, mais a) notre code n'a jamais été dans la liste, b) cela peut aussi bien être une interaction étrange avec SQLAlchemy que nous utilisons également partout, il n'est donc pas impossible que le problème est ailleurs, ou c'est un problème de combinaison / interaction.

Si d'autres détails seraient utiles, veuillez demander. Nous continuons également à exécuter ces 8 travailleurs avec cette journalisation de l'utilisation de la mémoire, donc nous serons peut-être en mesure de collecter plus / de meilleures données.

EDIT : Ce commentaire de ce fil est également lié - nous utilisons toujours les mêmes paramètres.

J'espère que vous trouverez la cause de cette fuite.
Je vais essayer de prendre le temps de creuser moi-même.

Je me demande si cela pourrait aider à atténuer le problème.
https://reliability.substack.com/p/run-python-servers-more-efficly

Nous étudions la possibilité que l'origine des fuites de mémoire se trouve dans la bibliothèque de requêtes et non dans le céleri lui-même. Quelqu'un d'autre qui subit des fuites de mémoire dans le céleri en utilisant des demandes dans les tâches?

@ErrorInPersona Oui, nous enregistrons les MOO dans les nœuds de calcul avec et sans demandes .

@drbig Une chance?

Screenshot_2020-11-17_12-56-28

Bon, regardez le "vert", le parquet monte, lentement mais sûrement ... Donc à part une rapide confirmation de "oui, c'est toujours un problème" pas grand chose à ajouter de mon côté, malheureusement.

Cependant, j'ai parcouru le lien fourni par - try running some workers with jemalloc forced in , donc j'y reviendrai, _ventually_.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

keisetsu picture keisetsu  ·  3Commentaires

aTylerRice picture aTylerRice  ·  3Commentaires

pymatffm picture pymatffm  ·  3Commentaires

asmodehn picture asmodehn  ·  3Commentaires

Xuexiang825 picture Xuexiang825  ·  3Commentaires