2

Ниже приведена часть кода python, работающего в Google App Engine. Он извлекает файл из Google Cloud Storage с помощью клиента cloudstorage.Утечка памяти при чтении файлов из облачного хранилища Google в Google App Engine (python)

Проблема в том, что каждый раз, когда код считывает большой файл (около 10 М), память, используемая в экземпляре, будет увеличиваться линейно. Вскоре процесс прекращается из-за ограничения «Превышение мягкой частной памяти 128 МБ с 134 МБ после обслуживания всего 40 запросов».

class ReadGSFile(webapp2.RequestHandler): 
    def get(self): 
     import cloudstorage as gcs 

     self.response.headers['Content-Type'] = "file type" 
     read_path = "path/to/file" 

     with gcs.open(read_path, 'r') as fp: 
      buf = fp.read(1000000) 
      while buf: 
       self.response.out.write(buf) 
       buf = fp.read(1000000) 
      fp.close() 

Если я прокомментирую следующую строку, то использование памяти в экземпляре изменится. Так что это должна быть проблема webapp2.

self.response.out.write(buf) 

Предполагается, что webapp2 освободит пространство памяти после завершения ответа. Но в моем коде это не так.

+1

Вы можете только один раз написать объект ответа. – user2266449

+0

Исходный поток буферизует весь вывод в памяти, а затем отправляет конечный результат, когда обработчик завершает работу. webapp не поддерживает потоковые данные для клиента. Вам нужен API канала для потоковой передачи. – voscausa

+0

Я попытался написать объект ответа только один раз: "buf = fp.read (20000000); self.response.out.write (buf); fp.close();". Но это не решает проблему –

ответ

2

Предложил комментарий вышеуказанного пользователя voscausa, я изменил схему для загрузки файла, то есть, чтобы служить загрузку файлов с помощью Blobstore. Теперь проблема утечки памяти решена.

Ссылка: https://cloud.google.com/appengine/docs/python/blobstore/#Python_Using_the_Blobstore_API_with_Google_Cloud_Storage

from google.appengine.ext import blobstore 
from google.appengine.ext.webapp import blobstore_handlers 

class GCSServingHandler(blobstore_handlers.BlobstoreDownloadHandler): 
    def get(self): 
    read_path = "/path/to/gcs file/" # The leading chars should not be "/gs/" 
    blob_key = blobstore.create_gs_key("/gs/" + read_path) 

    f_name = "file name" 
    f_type = "file type" # Such as 'text/plain' 

    self.response.headers['Content-Type'] = f_type 
    self.response.headers['Content-Disposition'] = "attachment; filename=\"%s\";"%f_name 
    self.response.headers['Content-Disposition'] += " filename*=utf-8''" + urllib2.quote(f_name.encode("utf8")) 

    self.send_blob(blob_key) 
+0

СПАСИБО - это спасло меня - была та же проблема - утечка памяти на доступ GCS! – Aerodyno

1

Попробуйте очистить кеш в контексте.

from google.appengine.ext import ndb 

context = ndb.get_context() 
context.clear_cache() 

See documentation here

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

Вы также можете попробовать очистить буферы отклика webapp2. Вставьте эту строку коды перед во время цикла

self.response.clear() 

Ответа буферов всех выходных данных в памяти, а затем отправляет окончательный вывод при выходе из обработчика. webapp2 не поддерживает потоковые данные для клиента . Метод clear() стирает содержимое выходного буфера, оставляет его пустым.

Check this link

+0

Я добавляю код кэширования, но он не работает. Кстати, в моем приложении я использую db, а не ndb, чтобы создать модель. Таким образом, кажется, что сама проблема не имеет отношения к кэшированию ndb. –

+0

Я протестировал способ очистки буфера ответа, но не смог решить проблему. То есть вызовите функцию self.response.clear() перед записью данных в буфер во время цикла. Но буфер памяти для ответа не освобождается. Кажется, что механизм кэширования в ответ отличается от буферизации данных. –

0

я испытал подобную проблему. В моем коде я последовательно загружаю несколько файлов размером 1-10 МБ, выполняю обработку на всех из них, а затем публикую результаты в облаке.

Я стал свидетелем серьезных утечек памяти, которые не смогли обработать более 50-100 загрузок подряд.

Будучи неохотно переписать код загрузки в Blobstore я попробовал последний курортный эксперимент, вручную вызывая сбор мусора после каждой загрузки:

import gc 
gc.collect() 

Я теперь работаю код в течение нескольких минут без какого-либо «Превышен мягкого лимит частной памяти "и объем памяти в памяти экземпляра, кажется, растет гораздо медленнее.

Очевидно, что это может быть просто удачей, след по-прежнему постепенно увеличивается, но с некоторыми каплями, и экземпляр уже подал 2000 запросов.

 Смежные вопросы

  • Нет связанных вопросов^_^