标签: reactor-netty

使用Springboot 2.0.3-RELEASE版本提前关闭连接

在调用下游RESTful服务时,我们看到太多"连接过早关闭并由同行重置"错误,即使在将Springboot版本升级到最新的专家建议之后也是如此.

我们试图重现它,但无法在dev中重现.它发生在负载测试中,当应用程序负载过重时.

堆栈跟踪:

Suppressed: java.io.IOException: Connection closed prematurely
    at reactor.ipc.netty.http.client.HttpClientOperations.onInboundClose(HttpClientOperations.java:269)
    at reactor.ipc.netty.channel.ChannelOperationsHandler.channelInactive(ChannelOperationsHandler.java:113)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:245)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:231)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:224)
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelInactive(CombinedChannelDuplexHandler.java:420)
    at io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:377)
    at io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:342)
    at io.netty.handler.codec.http.HttpClientCodec$Decoder.channelInactive(HttpClientCodec.java:282)
    at io.netty.channel.CombinedChannelDuplexHandler.channelInactive(CombinedChannelDuplexHandler.java:223)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:245)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:231)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:224)
    at io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:377)
    at io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:342)
    at io.netty.handler.ssl.SslHandler.channelInactive(SslHandler.java:1028)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:245)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:231)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:224)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1429)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:245)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:231)
    at io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:947)
    at io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:822)
    at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:465)
    at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884)
    ... 1 common frames omitted
Run Code Online (Sandbox Code Playgroud)

任何帮助和建议表示赞赏,提前谢谢.

spring-boot reactor-netty

5
推荐指数
0
解决办法
1697
查看次数

Reactive Redis (Lettuce) 总是发布到单线程

我使用 Spring Webflux(带有 spring-reactor-netty)2.1.0.RC1 和 Lettuce 5.1.1.RELEASE。

当我使用 Reactive Lettuce API 调用任何 Redis 操作时,执行总是切换到同一个单独的线程 (lettuce-nioEventLoop-4-1)。

这导致性能不佳,因为所有执行都在该单个线程中遇到瓶颈。

我知道publishOn每次调用 Redis 时我都可以使用它来切换到另一个线程,但这很容易出错并且仍然不是最佳的。

有什么办法可以改善吗?我看到 Lettuce 提供了 ClientResources 类来自定义线程分配,但我找不到任何方法将其与 Spring webflux 集成。

此外,对于粗心的开发人员来说,当前的行为会不会很危险?也许默认值应该稍微调整一下。我想理想的情况是 Lettuce 可以重用来自 webflux 的相同事件循环。

我正在添加这个 spring boot 单类片段,可用于重现我所描述的内容:

@SpringBootApplication
public class ReactiveApplication {
    public static void main(String[] args) {
        SpringApplication.run(ReactiveApplication.class, args);
    }
}

@Controller
class TestController {

    private final RedisReactiveCommands<String, String> redis = RedisClient.create("redis://localhost:6379").connect().reactive();

    @RequestMapping("/test")
    public Mono<Void> test() {
        return redis.exists("key")
            .doOnSubscribe(subscription -> System.out.println("\nonSubscribe called on thread " + Thread.currentThread().getName())) …
Run Code Online (Sandbox Code Playgroud)

lettuce reactor-netty spring-webflux

5
推荐指数
1
解决办法
1695
查看次数

如何为 Spring WebFlux 配置 netty 连接超时

我在 AWS 负载均衡器后面运行 spring cloud gateway(我理解它是在 Spring Webflux 上构建的),并且我收到间歇性 502 错误。经过调查,问题似乎与负载均衡器和我的节点之间的连接超时有关。从一些调查来看,底层 netty 服务器的默认超时时间为 10 秒。我使用以下命令确定了这一点...

time nc -vv 10.10.xx.xxx 5100
Connection to 10.10.xx.xxx 5100 port [tcp/*] succeeded!

real    0m10.009s
user    0m0.000s
sys     0m0.000s
Run Code Online (Sandbox Code Playgroud)

虽然我可以将负载均衡器上的 idleTimeout 设置在 10 秒以内,但这感觉非常低效。如果可能,我想将其保持在 30 秒以上。相反,我想增加 netty 服务器上的连接超时。我试图在我的 application.yml 中设置 server.connection-timeout 属性...

server:
  connection-timeout: 75000
Run Code Online (Sandbox Code Playgroud)

也通过指定秒...

server:
  connection-timeout: 75s
Run Code Online (Sandbox Code Playgroud)

但是当我运行 time 命令以查看我的连接持续多长时间时,超时没有变化,它仍然以 10 秒结束......

time nc -vv 10.10.xx.xxx 5100
Connection to 10.10.xx.xxx 5100 port [tcp/*] succeeded!

real    0m10.009s
user    0m0.000s
sys     0m0.000s
Run Code Online (Sandbox Code Playgroud)

我在这里缺少什么?

reactor-netty spring-webflux spring-cloud-gateway

5
推荐指数
1
解决办法
6980
查看次数

WebClient 第一次请求缓慢的解决方法

我在 Spring Boot MVC 2.1 项目中使用 WebClient,发现客户端发出的第一个请求最多需要 6 秒。后续请求速度更快(~30 毫秒)。

Spring 的 JIRA中有一个已解决的问题,建议使用 Jetty 作为 WebClient Http 连接器。我已经尝试过这种方法,以大约 800 毫秒的第一个请求改进了数字。这次是一个改进,但距离通常需要 < 200 毫秒的 RestTemplate 还很远

Netty 方法(5s 第一个请求):

会议:

@Bean
public WebClient webClient() {
    return WebClient.create();
}
Run Code Online (Sandbox Code Playgroud)

用法:

private final WebClient webClient;

@GetMapping(value="/wc", produces = APPLICATION_JSON_UTF8_VALUE)
public Mono<String> findWc() throws URISyntaxException {
    URI uri = new URI("http://xxx");
    final Mono<String> response = webClient.get().uri(uri).retrieve().bodyToMono(String.class);
    return response;
}
Run Code Online (Sandbox Code Playgroud)

码头方法(800ms 第一个请求):

会议:

@Bean
public JettyResourceFactory resourceFactory() {
    return …
Run Code Online (Sandbox Code Playgroud)

jetty spring-boot reactor-netty spring-webflux

5
推荐指数
1
解决办法
1791
查看次数

如何在新的 Springboot 2.1.4.Release 中禁用 Webclient 中的连接池?

我正在使用 springboot webclient 从远程服务器调用 rest api。第一个请求工作正常。如果我在一段时间后发出后续请求,服务器会抛出 500 服务器错误。我得到的错误是“onError(java.io.IOException:一个现有的连接被远程主机强行关闭)”。

我想通过禁用连接池来测试行为,因为我相信它使用以前的连接。你能帮我在创建 webclient 时如何禁用连接池吗?

TcpClient tcpClient = TcpClient.create()
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000)
        .option(ChannelOption.SO_KEEPALIVE, false)
        .doOnConnected(connection ->
                connection.addHandlerLast(new ReadTimeoutHandler(30))
                        .addHandlerLast(new WriteTimeoutHandler(30))
        );

ReactorClientHttpConnector httpConnector = new ReactorClientHttpConnector(HttpClient.from(tcpClient));

final WebClient webClient = WebClient
        .builder()
        .clientConnector(httpConnector)
        .baseUrl("http://customer.service.api.internal.cloud.qa.intranet.pagseguro.uol")
        .exchangeStrategies(strategies)
        .build()
Run Code Online (Sandbox Code Playgroud)

spring-boot reactor-netty

5
推荐指数
1
解决办法
3863
查看次数

Springboot Webclient 抛出“一个现有连接被远程主机强行关闭”。

Springboot Webclient 在尝试调用远程服务器中的 rest api 时抛出“一个现有连接被远程主机强行关闭”错误。

当服务器加载时,第一个服务器请求加载正常。当我在一段时间后(比如 5 分钟)发送第二个请求时,出现错误。

网页客户端创建代码:

WebClient webClient() {
           TcpClient tcpClient = TcpClient.create()
               .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000)
               .option(ChannelOption.SO_KEEPALIVE, false)
               .doOnConnected { connection ->
               connection.addHandlerLast(new LoggingHandler(LogLevel.TRACE))
           connection.addHandlerLast(new ReadTimeoutHandler(30))
                   .addHandlerLast(new WriteTimeoutHandler(30))
               .addHandlerLast(new IdleStateHandler(30,30,30))

       }

       ReactorClientHttpConnector httpConnector = new ReactorClientHttpConnector(HttpClient.from(tcpClient))

       return WebClient.builder()
               .clientConnector(httpConnector)
               .build()

   }
Run Code Online (Sandbox Code Playgroud)

请在下面找到日志。看起来连接没有正确关闭。

你能告诉我如何解决吗?

2019-04-10 15:26:31.534  INFO 235344 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-04-10 15:26:31.534  INFO 235344 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2019-04-10 15:26:31.544  INFO 235344 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Completed initialization in …
Run Code Online (Sandbox Code Playgroud)

netty spring-boot reactor-netty spring-webflux

5
推荐指数
0
解决办法
2698
查看次数

Webclient(连接池和SSL握手)

在Spring 5中,我们使用webclient通过SSL调用其他REST端点。当我们在wireshark上记录日志时,我们看到对于每个请求,SSL握手都在发生,并且花费大量时间。

这些是我的查询。

查询1:Webclient执行内部连接池。连接失效之前的到期时间是多少?

我们是否可以设置打开连接的时间,以便在已经定义的连接上发送新请求以避免SSL握手?

是否存在避免每个请求进行SSL握手的设置?

查询2:我们正在创建Webclient的bean,并在整个应用程序中使用它。我们需要做一些设置来启用连接池和重用现有连接以发送新请求。还有避免每次都进行SSL握手的任何设置。

    @Bean(name="productDefWebClient")
    public WebClient productDefWebClient() {
        ConnectionProvider elasticPool = ConnectionProvider.elastic("productDef-pool");
        HttpClient httpClient = HttpClient.create(elasticPool).wiretap(true);
        return WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .defaultHeader("Accept","application/json")
                .baseUrl("https://test-qa.test.com")
                .build();
    }

Run Code Online (Sandbox Code Playgroud)

java spring spring-boot reactor-netty spring-webflux

5
推荐指数
0
解决办法
127
查看次数

Reactor Flux 和 Java Fiber 的区别

我一直在阅读有关 Java Fibers 作为映射到线程的小工作单元的内容。如果发生阻塞调用,不同的纤程将被映射到同一个线程。由于 Java 中的线程是内核级线程,因此这可以防止线程耗尽。

我一直在使用Spring Web-Flux,所以只是想了解当Netty服务器每秒接收100个请求时内部会发生什么,每个请求都包括反应式数据库访问,这些请求如何映射到Netty服务器默认生成的40个线程?

通量与光纤有何不同?Flux 如何保证线程数量有限的异步行为?

java fibers project-reactor reactor-netty spring-webflux

4
推荐指数
1
解决办法
1139
查看次数

SQL查询的Spring Data R2DBC参数条件绑定

我在使用 Spring Data R2DBC DatabaseClient 将条件参数绑定到 SQL 查询时遇到困难。两个参数可以为空。由于DatabaseClient需要明确指定参数为空,因此我尝试了以下语法,但条件参数未附加到现有参数中:

public Mono<Void> createAddress(Address address) {
    DatabaseClient.GenericExecuteSpec bindings = databaseClient.execute(addressesQueries.getProperty("addresses.insert"))
            .bind("line1", address.getLine1())
            .bind("zipCode", address.getZipCode())
            .bind("city", address.getCity())
            .bind("countryId", address.getCountry())
            .bind("id", address.getId()); // UUID

            if(address.getLine2() == null) {
                bindings.bindNull("line2", String.class);
            } else {
                bindings.bind("line2", address.getLine2());
            }
            if(address.getState() == null) {
                bindings.bindNull("state", String.class);
            } else {
                bindings.bind("state", address.getState());
            }

    return bindings.fetch().rowsUpdated().then();
}
Run Code Online (Sandbox Code Playgroud)

SQL查询:

INSERT INTO addresses(id,line1,line2,zip_code,city,state,country) VALUES(:id,:line1,:line2,:zipCode,:city,:state,:countryId)
Run Code Online (Sandbox Code Playgroud)

我知道我可以拆分 SQL 查询来处理带/不带空参数的情况,但如果我有多个条件参数,就会有点复杂。

你知道一种解决方案可以帮助我保留一个 SQL 查询并在 Java 代码中处理条件参数吗?

sql postgresql reactor-netty spring-webflux spring-data-r2dbc

4
推荐指数
1
解决办法
8282
查看次数

如何在Reactor Netty HTTP客户端中设置TCP Keepalive?

我看到了

HttpClient.from(TcpClient.create().option(ChannelOption.SO_KEEPALIVE, true)) 
Run Code Online (Sandbox Code Playgroud)

from方法已被弃用。

目前我应该如何设置SO_KEEPALIVE使用HttpClient.create()

netty kotlin reactor-netty spring-webflux spring-webclient

4
推荐指数
1
解决办法
1902
查看次数