App Engine Deferred: Отслеживание утечек памяти

У нас есть приложение App Engine, которое записывает множество файлов относительно большого размера в Google Cloud Store. Эти файлы являются CSV, которые создаются динамически, поэтому мы используем Python StringIO.StringIO в качестве буфера и csv.writer в качестве интерфейса для записи в этот буфер.

В целом наш процесс выглядит так:

# imports as needed
# (gcs is the Google Cloud Store client)

buffer = StringIO.StringIO()
writer = csv.writer(buffer)

# ...
# write some rows
# ...

data = file_buffer.getdata()
filename = 'someFilename.csv'

try:
    with gcs.open(filename, content_type='text/csv', mode='w') as file_stream:
        file_stream.write(data)
        file_stream.close()

except Exception, e:
    # handle exception
finally:
    file_buffer.close()

Как мы понимаем, csv.writer не нужно закрывать себя. Скорее только buffer выше и file_stream нужно быть закрытым.


Мы запускаем вышеуказанный процесс в deferred, вызываемый из очереди задач App Engine. В конечном счете, мы получаем следующую ошибку после нескольких вызовов нашей задачи:

Превышено мягкое ограничение частной памяти в 128 МБ и 142 МБ после обслуживания всего 11 запросов.

Очевидно, что в нашем приложении произошла утечка памяти. Однако, если приведенный выше код верен (что, как мы допускаем, может и не соответствовать действительности), то наша единственная другая идея заключается в том, что некоторый большой объем памяти удерживается посредством обслуживания наших запросов (как следует из сообщения об ошибке).

Таким образом, нам интересно, хранятся ли некоторые сущности в App Engine во время выполнения deferred, Мы также должны отметить, что наши CSV-файлы в конечном итоге успешно написаны, несмотря на эти сообщения об ошибках.

1 ответ

Решение

Описанный симптом не обязательно указывает на утечку памяти приложения. Потенциальные альтернативные объяснения включают в себя:

  • базовый объем памяти приложения (который для песочниц на языке сценариев, таких как python, может быть больше, чем объем во время запуска экземпляра, см. Использование памяти сильно (и странно) между внешним и внутренним интерфейсом) может быть слишком высоким для настроенного класса экземпляра для приложения / модуля. Чтобы исправить - выберите более высокий класс экземпляра памяти (который, как побочный эффект, также означает более быстрый экземпляр класса). В качестве альтернативы, если скорость уничтожения экземпляров из-за превышения пределов памяти допустима, просто позвольте GAE перезапускать экземпляры:)
  • Пики активности, особенно если включена многопоточная обработка запросов, означает более высокое потребление памяти, а также потенциальную перегрузку сборщика мусора в памяти. Ограничение числа запросов, выполняемых параллельно, добавление (более высоких) задержек при обработке отложенных задач с более низким приоритетом и другие подобные меры, снижающие среднюю скорость обработки запросов на экземпляр, могут помочь сборщику мусора очистить остатки от запросов. Масштабируемость не должна быть повреждена (с динамическим масштабированием), так как другие экземпляры будут запущены, чтобы помочь с пиком активности.

Связанные вопросы и ответы:

Другие вопросы по тегам