Настройка Spring WebFlux WebClient для использования настраиваемого пула потоков

Можно ли настроить WebClient на использование настраиваемого пула потоков, отличного от пула потоков response-http-nio (при использовании Netty)? Если возможно, можем ли мы каким-то образом ограничить выполнение этого настраиваемого пула потоков только на определенном ядре процессора?


person Nipuna Saranga    schedule 26.06.2019    source источник
comment
Не могли бы вы пояснить свою мотивацию?   -  person bsideup    schedule 26.06.2019
comment
@bsideup хм, хорошо, если мы используем Netty и webClient в приложении webFLux, они разделяют ресурсы в соответствии с весенней документацией. Мы хотели бы использовать другой пул потоков для webClient (вместо совместного использования пула потоков Netty Reaction-http-nio). Можно ли это сделать? Если это так, мы также хотели бы выделить одно ядро ​​процессора только для использования webClient, надеясь, что кэширование этого ядра процессора будет оптимизировано исключительно для требований webClient. Надеюсь, это имеет смысл!   -  person Nipuna Saranga    schedule 26.06.2019
comment
ЧБХ, в этом нет большого смысла. На самом деле, это может сделать еще хуже. Если вам нужно запустить операции блокировки после получения ответа от WebClient, вы должны использовать оператор publishOn. Но перемещение WebClient из пула response-http-nio только увеличит количество переключений контекста. Команда Reactor и Reactor Netty уже проделывает замечательную работу, оптимизируя вещи и абстрагируя темы.   -  person bsideup    schedule 26.06.2019
comment
@bsideup Я согласен с тем, что вы говорите! Но, похоже, когда нам еще нужно, мы можем сделать это, настроив bean-компонент ReactorResourceFactory (setGlobalResources = false), а затем использовать его для создания объекта ClientHttpConnector, а затем использовать созданный объект ClientHttpConnector с WebClientBuilder для создания настраиваемого веб-клиента, который использует пул потоков. отличается от Нетти. Хотя не уверен! Если возможно, ваш вклад в это (действительно ли он создает новый пул потоков) очень ценится!   -  person Nipuna Saranga    schedule 04.07.2019
comment
Ссылки @bsideup, которые дали вышеуказанное понимание, docs.spring.io/spring-boot/docs/current/reference/html/, docs.spring.io/spring/docs/5.1.8.RELEASE/   -  person Nipuna Saranga    schedule 04.07.2019


Ответы (1)


да. Вы можете.

  1. Создайте где-нибудь свой собственный пул потоков и EventLoopGroup (или создайте bean-компонент NioEventLoopGroup). Например:

    {
     Intger THREADS = 10;
    
     BasicThreadFactory THREADFACTORY = new BasicThreadFactory.Builder()
            .namingPattern("HttpThread-%d")
            .daemon(true)
            .priority(Thread.MAX_PRIORITY)
            .build();
    
     EXECUTOR = new ThreadPoolExecutor(
            THREADS,
            THREADS,
            0L,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(),
            THREADFACTORY,
            new ThreadPoolExecutor.AbortPolicy());
    
     NioEventLoopGroup RESOURCE= new NioEventLoopGroup(THREADS,EXECUTOR);
    }
    
  2. Зарегистрируйте свой собственный ReactorResourceFactory. И предоставьте свой собственный EventLoopGrooup на основе настраиваемого исполнителя потока

    @Bean
    public ReactorResourceFactory reactorResourceFactory(NioEventLoopGroup RESOURCE) {
        ReactorResourceFactory f= new ReactorResourceFactory();
        f.setLoopResources(new LoopResources() {
            @Override
             public EventLoopGroup onServer(boolean b) {
                 return RESOURCE;
                }
            });
        f.setUseGlobalResources(false);
        return f;
    }
    
  3. Затем зарегистрируйте ReactorClientHttpConnector. В примере ниже используется настраиваемый контекст SSL.

    @Bean
    public ReactorClientHttpConnector reactorClientHttpConnector(ReactorResourceFactory r) throws SSLException {
        SslContext sslContext = SslContextBuilder
            .forClient()
            .trustManager(InsecureTrustManagerFactory.INSTANCE)
            .build();
        return new ReactorClientHttpConnector(r, m -> m.secure(t -> t.sslContext(sslContext)));
    }
    
  4. Наконец, создайте WebClient

    @Bean
    public WebClient webClient(ReactorClientHttpConnector r) {
        return WebClient.builder().clientConnector(r).build();
    }
    

Если вы хотите использовать то же самое для WebServer. Сделайте такую ​​же настройку для ReactiveWebServerFactory.

    @Bean
    public ReactiveWebServerFactory reactiveWebServerFactory(NioEventLoopGroup RESOURCE) {
        NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
        factory.addServerCustomizers(hs->hs.tcpConfiguration(s->s.runOn(RESOURCE)));
        return factory;
    }

Импорт:

    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.handler.ssl.SslContext;
    import io.netty.handler.ssl.SslContextBuilder;
    import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.DependsOn;
    import org.springframework.http.client.reactive.ReactorClientHttpConnector;
    import org.springframework.http.client.reactive.ReactorResourceFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.reactive.function.client.WebClient;
    import reactor.netty.resources.LoopResources;
    import org.apache.commons.lang3.concurrent.BasicThreadFactory;
    import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
    import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
    import java.util.concurrent.*;
person evgrot    schedule 23.01.2020
comment
Немного поздно;) но все равно спасибо! Пробовал некоторое время назад аналогичным образом! - person Nipuna Saranga; 23.01.2020