Netty HTTP-сервер, загрузка больших файлов, OutOfMemoryError - PullRequest
1 голос
/ 27 декабря 2011

Прежде всего, извините за мой кривой английский:)

У меня возникли некоторые проблемы во время записи http-сервера Netty, который отправляет / получает большие файлы (~ 2 ГБ).И я был бы очень признателен, если бы кто-нибудь помог или объяснил.

Мое клиентское приложение (веб-браузер) отправляет файлы через XMLHttpRequest следующим образом:

            var sampleFile = document.getElementById("sampleFile").files[0];  //chosen file by <input type="file" .../>
            var xhr = new XMLHttpRequest();       
            xhr.open("POST","http://127.0.0.1:8091/upload/some_file_name.txt", true);        
            xhr.send(sampleFile);

На стороне сервера:

Класс WebSocketServer:

             ServerBootstrap bootstrapHttp = new ServerBootstrap(
            new NioServerSocketChannelFactory(
                              Executors.newCachedThreadPool(),
                              Executors.newCachedThreadPool()));

    bootstrapHttp.setPipelineFactory(new ChannelPipelineFactory() {
        public ChannelPipeline getPipeline() {
            ChannelPipeline pipeline = pipeline();

              pipeline.addLast("decoder", new HttpRequestDecoder());
              pipeline.addLast("aggregator", new HttpChunkAggregator(1024*1024*1024));
              pipeline.addLast("encoder", new HttpResponseEncoder());          
              pipeline.addLast("deflater", new HttpContentCompressor());               
              pipeline.addLast("handler", new HttpRequestServerHandler());
              return pipeline;
        }
    });     
    bootstrapHttp.bind(new InetSocketAddress(port));

Класс HttpRequestServerHandler:

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception    {

             Object msg = e.getMessage();

    if (msg instanceof HttpRequest) {

        HttpRequest req = (HttpRequest)msg;             

        if (req.getMethod() != POST) {          
            return;             
        }                   

        if (decodedURI.startsWith(UPLOAD_FILE_PATH)) {

            HttpRequest request = (HttpRequest) e.getMessage(); 

            RandomAccessFile raf = new RandomAccessFile("foobar.tmp", "rw");                
            ChannelBuffer buf = request.getContent();                   
            FileChannel fChannel = raf.getChannel();
            Channel msgChannel= e.getChannel();             

            fChannel.write( buf.toByteBuffer() );                               
            raf.close();
            fChannel.close();
            msgChannel.close();
        }
    }

При отправке файла среднего размера все работает замечательно.Проблема с большими файлами (> 300 МБ).После некоторого времени обработки возникает исключение:

java.lang.OutOfMemoryError: пространство кучи Java в org.jboss.netty.buffer.HeapChannelBuffer. (HeapChannelBuffer.java:47) в org.jboss.netty.buffer.BigEndianHeapChannelBuffer. (BigEndianHeapChannelBuffer.java:39) в org.jboss.netty.buffer.ChannelBuffers.buffer (ChannelBuffers.java:139) в org.jboss.netty.buffer (HeffBuber)org.jboss.netty.buffer.DynamicChannelBuffer.ensureWritableBytes (DynamicChannelBuffer.java:84) в org.jboss.netty.buffer.DynamicChannelBuffer.writeBytes (DynamicChannelBuffer.java:2ffss.ffava.b.buy.bu.by.by.by.by.by.bject.bb.bb) orgAbstractChannelBuffer.java:457) в org.jboss.netty.buffer.AbstractChannelBuffer.writeBytes (AbstractChannelBuffer.java:450) в org.jboss.netty.handler.codec.http.HttpChunkAggregator.mett40_harget_RegRegChateRegReader_jtgRegCat.jboss.netty.channel.Channels.fireMessageReceived (Channels.java:302) в org.jboss.netty.handler.codec.replay.ReplayingDecoder.unfoldAndFireMessageReceived (ReplayingDecoder.java:522) в org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode (ReplayingDecoder.java:50j.codec.replay.ReplayingDecoder.messageReceived (ReplayingDecoder.java:443) в org.jboss.netty.channel.Channels.fireMessageReceived (Channels.java:274) в org.jboss.netty.channel.Channels.fireMessageReavad Channels.261) at org.jboss.netty.channel.socket.nio.NioWorker.read (NioWorker.java:351)

Он даже не доходит до моего обработчика сообщений, полученных.Как я могу предположить, некоторый внутренний ChannelBuffer переполнен.Я пытался увеличить параметр HttpChunkAggregator (1024 *1024* 1024).Однако это бы не помогло.Я вижу только одно решение - разделить файл на стороне клиента (используя html5), отправить эти куски и вставить их вместе на сервер.Но это кажется довольно сложным.Есть ли какой-нибудь более простой способ исправить это (в области Netty)?

Спасибо!С наилучшими пожеланиями.

Ответы [ 3 ]

3 голосов
/ 28 декабря 2011

Я думаю, вам следует не использовать HttpChunkAggregator.

Это означает, что вам придется вручную обрабатывать фрагменты HTTP.

См. Нетти Загрузка файлапример для более подробной информации.

1 голос
/ 28 декабря 2011

Да, лучше было бы "проталкивать" куски байта [] на fs до тех пор, пока загрузка не будет завершена. Таким образом, вам не нужно держать все в памяти. Помните, что запись в fs может «блокироваться», поэтому вам следует подумать о добавлении ExecutionHandler перед ним.

0 голосов
/ 28 января 2012

Тот факт, что он находится в чем-то, называемом HeapChannelBuffer, говорит о многом - вы, вероятно, захотите org.jboss.netty.buffer.DirectChannelBufferFactory где-то там, чтобы ваши данные не сохранялись в куче.

...