2015-03-01 32 views
7

Dato questo codice di esempio dalla documentazione Giocare:Play Framework: caricamenti di file - bloccanti o non bloccanti?

def upload = Action(parse.temporaryFile) { request => 
    request.body.moveTo(new File("/tmp/picture/uploaded")) 
    Ok("File uploaded") 
} 
  1. Come verranno gestiti 100 simultanee richieste di upload lento (numero di thread)?
  2. Verrà caricato il file memorizzato nel buffer o trasmesso direttamente sul disco?

risposta

10

Come verranno gestite 100 richieste di caricamento lento simultaneo (numero di thread)?

Dipende. Il numero di thread effettivamente utilizzati non è rilevante. Per impostazione predefinita, Play utilizza un numero di thread uguale al numero di core CPU disponibili. Ma questo non significa che se hai 4 core, sei limitato a 4 processi simultanei contemporaneamente. Le richieste HTTP in Play vengono elaborate in modo asincrono in uno speciale interno ExecutionContext fornito da Akka. I processi in esecuzione in un ExecutionContext possono condividere i thread, a condizione che non siano bloccanti, il che viene rimosso da Akka. Tutto questo può essere configurato in diversi modi. Vedi Understanding Play Thread Pools.

Iteratee Il Iteratee che consuma i dati del client deve eseguire un blocco per scrivere i blocchi di file su disco, ma eseguito in pochi (e veloci) blocchi sufficienti, questo non dovrebbe causare il blocco di altri file caricati.

Ciò di cui sarei più preoccupato è la quantità di I/O del disco che il server può gestire. 100 caricamenti lenti potrebbe essere essere ok, ma non si può davvero dire senza benchmarking. Ad un certo punto si avranno problemi quando l'input del client supera la velocità che il server può scrivere sul disco. Anche questo non funzionerà in un ambiente distribuito. Quasi sempre scelgo di bypassare completamente il server di riproduzione e di caricare direttamente su Amazon S3.

Verrà caricato il file memorizzato nel buffer o trasmesso direttamente sul disco?

Tutti i file temporanei vengono trasmessi su disco. Sotto il cofano, tutti i dati inviati dal client al server vengono letti utilizzando la libreria iteratee in modo asincrono. Per i caricamenti multipart, non è diverso. I dati del cliente sono consumati da un Iteratee, che esegue lo streaming dei blocchi di file su un file temporaneo su disco. Quindi, quando si utilizza parse.temporaryFileBodyParser, request.body è solo un handle per un file temporaneo su disco e non il file archiviato in memoria.


Vale la pena notare che, mentre gioco in grado di gestire tali richieste in modo non-blocking, spostando il file una volta completata sarà blocco. Cioè, request.body.moveTo(...) bloccherà la funzione del controller fino al completamento del movimento. Ciò significa che se diversi dei 100 caricamenti vengono completati all'incirca nello stesso momento, lo ExecutionContext interno di Play per la gestione delle richieste può rapidamente sovraccaricare. Anche l'API sottostante di moveTo è deprecata in Play 2.3, poiché utilizza FileInputStream e FileOutputStream per copiare lo TemporaryFile in una posizione permanente. I documenti consigliano invece di utilizzare l'API del file Java 7, poiché è molto più efficiente.

questo può essere un po 'grezzo, ma qualcosa di più simile a questo dovrebbe farlo:

import java.io.File 
import java.nio.file.Files 

def upload = Action(parse.temporaryFile) { request => 
    Files.copy(request.body.file.toPath, new File("/tmp/picture/uploaded").toPath) 
    Ok("File uploaded") 
} 
+0

grande spiegazione, grazie. Anche il suggerimento S3 è interessante. – user882209

+1

@ user882209 La libreria [play-s3] (https://github.com/Rhinofly/play-s3) è molto buona. Dispone di helper per la creazione di moduli di caricamento firmati per il lato client e fornisce un'API lato server asincrona per la gestione dei file su S3 una volta caricati. –

+0

Non è proprio l'akka la chiave qui, ma il fatto che stia usando Netty e NIO. Soprattutto se il moveto usa zero copy che sono sicuro che lo faccia o lo speri. –

Problemi correlati