Высокопараллельный HTTP с Netty и NIO - PullRequest
8 голосов
/ 28 марта 2011

Я работаю на примере примера клиента Netty HTTP Client для выполнения запросов http в параллельной многопоточной среде.

Однако моя система полностью ломается (с множеством исключений) при довольно низкой пропускной способности.

В почти псевдокоде:

ClientBootstrap bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory()) 
bootstrap.setPipelineFactory(new HttpClientPipelineFactory());

ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
Channel channel = future.awaitUninterruptibly().getChannel();

HttpRequest request = new DefaultHttpRequest();
channel.write(request);

В примере, чтобысделать запрос Я создаю ClientBootstrap и оттуда (через несколько обручей) канал для записи HTTPRequest.

Это все работает и хорошо.

Однако в параллельной ситуации каждый запрос должен проходить через одни и те же обручи?Я думаю, что это то, что ломает вещи для меня в данный момент.Должен ли я повторно использовать соединение или структурировать моего клиента совершенно по-другому?

Также: я делаю это в Clojure, если это вообще что-то меняет.

1 Ответ

7 голосов
/ 31 марта 2011

Нет, вы все делаете правильно. Однако вы должны сохранить ссылку на свой экземпляр Channel. Если у вас есть этот канал, пока он открыт, вам не нужно создавать еще один загрузчик. (Если это то, что вы делаете.)

Это то, что я использовал в недавнем проекте:

класс ClientConnection (конструктор)

// Configure the client.
bootstrap = new ClientBootstrap(
    new NioClientSocketChannelFactory(
        Executors.newCachedThreadPool(),
        Executors.newCachedThreadPool()
    )
);

// Set up the pipeline factory.
bootstrap.setPipelineFactory(
    new ChannelPipelineFactory() {
        public ChannelPipeline getPipeline() throws Exception {
            return Channels.pipeline(
                // put your handlers here
            );
        }
    }
);

класс ClientConnection.connect (строковый хост, внутренний порт)

if (isConnected()) {
    throw new IllegalStateException("already connected");
}

// Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));

channel = future.awaitUninterruptibly().getChannel();

// Wait until the connection is closed or the connection attempt fails.
channel.getCloseFuture().addListener(new ChannelFutureListener() {
    @Override
    public void operationComplete(ChannelFuture future) throws Exception {
        new Thread(new Runnable() {
            public void run() {
                // Shut down thread pools to exit
                // (cannot be executed in the same thread pool!
                bootstrap.releaseExternalResources();

                LOG.log(Level.INFO, "Shutting down");
            }
        }).start();
    }
});

Так что, в основном, я сохраняю ссылку только на bootstrap и channel, однако первый в значительной степени не используется вне этих строк кода.

Примечание: вы должны выполнить bootstrap.releaseExternalResources(); только один раз, когда приложение закрывается. В моем случае клиент отправляет некоторые файлы, затем закрывает канал и завершает работу.

Если у вас есть подключенный экземпляр Channel, вам нужно использовать его только до тех пор, пока вы не закроете его снова. После закрытия вы можете вспомнить bootstrap, чтобы снова создать новый Channel.

Лично мне поначалу кажется, что Netty немного сложно понять, но как только вы поймете, как он работает, это просто лучшая инфраструктура NIO в Java. ИМО.

...