Высококонкурентный HTTP с Netty и NIO

Я работаю через пример кода HTTP-клиента Netty, чтобы выполнять 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, а оттуда (через несколько обручей) Channel для записи HTTPRequest.

Все это работает и хорошо.

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

Кроме того: я делаю это в Clojure, если это вообще имеет значение.


person Toby Hede    schedule 28.03.2011    source источник
comment
может быть, вам следует использовать github.com/ztellman/aleph?   -  person PheliX    schedule 28.03.2011
comment
у вас есть опыт работы с алеф? Я попробовал другой асинхронный http-клиент clojure, но он не работает на тех уровнях пропускной способности, которые мне необходимо поддерживать.   -  person Toby Hede    schedule 29.03.2011


Ответы (2)


Нет, ты все делаешь правильно. Однако вы должны сохранить ссылку на свой экземпляр 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(String host, int port)

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. ИМО.

person Yanick Rochon    schedule 31.03.2011
comment
bootstrap также будет полезен, если вы хотите установить другое соединение и использовать существующий механизм (базовые рабочие потоки Netty NIO). - person Piotr Findeisen; 06.04.2011

Netty — лучший подход к написанию высококонкурентных HTTP-сервисов в JVM, но он очень сложен и с ним трудно взаимодействовать напрямую, особенно при использовании Clojure. Взгляните на Donkey, который обеспечивает взаимодействие с Vert.x, использующим Netty в качестве серверной части. Это многоуровневое разделение абстрагирует многие нюансы низкоуровневых деталей, которые, если все сделано неправильно, могут привести к нестабильной работе службы. Donkey относительно новый, поэтому о нем пока не так много документации. Посетите этот блог, в котором представлен проект с открытым исходным кодом, реализующий элементарную новостную ленту. микросервис в Clojure с использованием Donkey. Он подробно описывает архитектуру, дизайн, кодирование и производительность под нагрузкой.

person Glenn    schedule 27.03.2021