Django Postgres утечка памяти - PullRequest
3 голосов
/ 01 апреля 2020

У меня есть пользовательская команда Django (v 2.0.0) для запуска многопоточных фоновых исполнителей, которая, кажется, вызывает проблемы с утечкой памяти.

Команда может быть запущена следующим образом:

./manage.py start_job_executer --thread=1

У каждого потока есть время True l oop, которое выбирает задания из таблицы PostgreSQL.

Для того, чтобы поднять задание и атомарно изменить статус, я использовал транзакции:

# atomic transaction to temporary lock the db access and to
# get the most recent job from db with column status = pending
with transaction.atomic():
    job = Job.objects.select_for_update() \
        .filter(status=Job.STATUS['pending']) \
        .order_by('created_at').first()
    if job:
        job.status = Job.STATUS['executing']
        job.save()

Il выглядит как выделенная память этой пользовательской командой Django продолжает расти.

Использование tracemallo c Я попытался выяснить причину утечки памяти, создав фоновый поток, который проверяет распределение памяти:

def check_memory(self):
        while True:
            s1 = tracemalloc.take_snapshot()
            sleep(10)
            s2 = tracemalloc.take_snapshot()
            for alog in s2.compare_to(s1, 'lineno')[:10]:
                log.info(alog)

Поиск следующего журнала:

01.04.20 13:50:06   operations.py:222: size=23.7 KiB (+23.7 KiB), count=66 (+66), average=367 B
01.04.20 13:50:36   operations.py:222: size=127 KiB (+43.7 KiB), count=353 (+122), average=367 B
01.04.20 13:51:04   operations.py:222: size=251 KiB (+66.7 KiB), count=699 (+186), average=367 B
01.04.20 13:51:31   operations.py:222: size=379 KiB (+68.9 KiB), count=1056 (+192), average=367 B
01.04.20 13:51:57   operations.py:222: size=495 KiB (+60.3 KiB), count=1380 (+168), average=367 B

Выглядит как /usr/local/lib/python3.5/dist-packages/django/db/backends/postgresql/operations.py:222 не освобождает память

Утечка медленно для 1 потока, но если я использую 8 потоков, утечка памяти будет хуже:

01.04.20 13:07:51   operations.py:222: size=68.3 KiB (+68.3 KiB), count=191 (+191), average=366 B
01.04.20 13:08:56   operations.py:222: size=770 KiB (+140 KiB), count=2151 (+390), average=367 B
01.04.20 13:10:07   operations.py:222: size=1476 KiB (+138 KiB), count=4122 (+386), average=367 B

01.04.20 13:36:22   operations.py:222: size=17.3 MiB (+138 KiB), count=49506 (+385), average=367 B

01.04.20 13:48:16   operations.py:222: size=24.5 MiB (+136 KiB), count=69993 (+379), average=367 B

Это код в строке 222 в /usr/local/lib/python3.5/dist-packages /django/db/backends/postgresql/operations.py:222:

def last_executed_query(self, cursor, sql, params):
        # http://initd.org/psycopg/docs/cursor.html#cursor.query
        # The query attribute is a Psycopg extension to the DB API 2.0.
        if cursor.query is not None:
            return cursor.query.decode() # this is line 222!
        return None

Понятия не имею, как решить эту проблему. Есть какие-нибудь идеи?

Разместил это здесь также: https://code.djangoproject.com/ticket/31419#ticket

Я думал, возможно, раскошелиться на новый процесс для каждой работы, которая должна быть выполнена, и по окончании память освобождается от смерти самого процесса. Это, вероятно, сработает, но кажется немного излишним.

Заранее спасибо

ОБНОВЛЕНИЕ

Я использовал Django 2.0 и подумал обновите до Django 3.0.5 (последний стабильный выпуск), но, к сожалению, проблема все еще существует.

Ниже новых журналов:

01.04.20 20:15:06   operations.py:235: size=977 KiB (+53.9 KiB), count=2750 (+152), average=364 B
01.04.20 20:15:28   operations.py:235: size=1070 KiB (+50.1 KiB), count=3012 (+141), average=364 B
01.04.20 20:15:53   operations.py:235: size=1156 KiB (+43.7 KiB), count=3255 (+123), average=364 B
01.04.20 20:16:19   operations.py:235: size=1245 KiB (+44.7 KiB), count=3507 (+126), average=364 B

01.04.20 20:20:23   operations.py:235: size=2154 KiB (+44.3 KiB), count=6065 (+125), average=364 B

1 Ответ

2 голосов
/ 02 апреля 2020

Django сохраняет ссылку на все выполненные запросы в кольцевом буфере, когда settings.DEBUG = True

Из DEBUG документации

Это Также важно помнить, что при запуске с включенным DEBUG, Django будет помнить каждый запрос SQL, который он выполняет. Это полезно при отладке, но быстро потребляет память на рабочем сервере.

Установка DEBUG = False должна решить вашу проблему.

...