Django Rest Framework'e büyük dosya yükleme

Oct 09 2020

DRF görünüm setine PUT ile büyük bir dosya (4GB) yüklemeye çalışıyorum.

Yükleme sırasında hafızam sabit. % 100'de, python çalıştırma sunucusu işlemi gittikçe daha fazla RAM alır ve çekirdek tarafından öldürülür. Bunun putyönteminde bir günlük satırım var APIViewancak işlem bu yöntem çağrısından önce öldürüldü.

Bu ayarı dosya kullanımını zorlamak için kullanıyorum FILE_UPLOAD_HANDLERS = ["django.core.files.uploadhandler.TemporaryFileUploadHandler"]

Bu hafıza zirvesi nereden geliyor? Sanırım dosya içeriğini belleğe yüklemeye çalışıyor ama neden (ve nerede)?

Daha fazla bilgi:

  • Doğru ve yanlış hata ayıklamayı denedim
  • Çalıştırma sunucusu, bir traefik'in arkasındaki bir pencerede, ancak traefik AFAIK'te herhangi bir sınırlama yoktur ve yükleme% 100'e ulaşır.
  • daphneRunserver yerine aynı davranışı alır mıyım henüz bilmiyorum
  • DÜZENLEME: ön kullanım a Content-Type multipart/form-data
  • DÜZENLEME: Denedim FileUploadParserve (FormParser, MultiPartParser)ayrıştırıcı sınıflarım içinAPIView

Yanıtlar

3 Wonskcalb Oct 14 2020 at 19:51

TL; DR:

Ne DRF ne de Django sorunu, 2,5 yıldır bilinen bir Daphne sorunu . Çözüm, şu an için uvicorn, hypercorn veya başka bir şey kullanmaktır.

Açıklamalar

Burada gördüğünüz şey Django Rest Framework'ten şu şekilde gelmiyor:

  • FileUploadParser, dosya yığınlarını parçalar halinde okurken , büyük dosya yüklemelerini işlemek içindir ;
  • Görünümünüzün yürütülmemesi ,request.FILES özelliğe erişene kadar yürütülmeyen ayrıştırıcıları ortadan kaldırır

Daphne'den bahsettiğiniz gerçeği, bana benzer bir sorundan bahseden ve Daphne'nin tüm gövdeyi RAM'e yüklemeden önce tüm gövdeyi RAM'e yüklerken büyük dosya yüklemelerini işlemediği bir koda işaret eden bu SO yanıtını hatırlatıyor . (Kod, yazım sırasında ana şubesinde hala mevcuttur)

Aynı davranışı görüyorsunuz runserverçünkü yüklendiğinde, Daphne geliştirici amaçları için WebSockets desteği sağlamak için ilk çalıştırma sunucusu komutunu kendisiyle değiştirir.

Bunun gerçek suçlu olduğundan emin olmak için, Kanalları devre dışı bırakmayı / varsayılan Django çalıştırma sunucusunu çalıştırmayı deneyin ve uygulamanızın OOM Killer tarafından öldürülüp öldürülmediğini kendiniz görün.

CaioKretzer Oct 09 2020 at 03:20

Django rest ile çalışıp çalışmadığını bilmiyorum, ancak dosyayı parçalamayı deneyebilirsiniz.

        [...]
        anexo_files = request.FILES.getlist('anexo_file_'+str(k))
        index = 0
        for file in anexo_files:
            index = index + 1
            extension = os.path.splitext(str(file))[1]
            nome_arquivo_anexo = 'media/uploads/' + os.path.splitext(str(file))[0] + "_" + str(index) + datetime.datetime.now().strftime("%m%d%Y%H%M%S") + extension
            handle_uploaded_file(file, nome_arquivo_anexo)
            
            AnexoProjeto.objects.create(
                projeto=projeto,
                arquivo_anexo = nome_arquivo_anexo 
            )
        [...]

Handle_uploaded_file nerede

def handle_uploaded_file(f, nome_arquivo):
    with open(nome_arquivo, 'wb+') as destination:
        for chunk in f.chunks():
            destination.write(chunk)