我们在使用 Spring Boot 2.0、Webflux 5.0.7 和 Netty 4.1.25 时遇到网络传输问题。我们希望将 100000 个序列化为 JSON(大约 10Mb 的网络流量)的项目传输到 1 个客户端。

NIO 和传统 IO 之间的网络传输性能有很大的不同。
测试结果如下:

Start reading 100000 from server in 5 iterations
Avg HTTP 283 ms
Avg stream 8130 ms

目前每秒 请求的数量不是问题 ,但网络传输速度是。我们已经读到,在网络速度方面,NIO 可能会慢 30% 左右,但 1/30 倍是过大的。

在客户端和服务器端采样时,我们观察到原因主要在于服务器端实现。从下面的截图可以看出,服务器大部分时间都花在方法 select()doWrite() 上。

java - Webflux + Netty NIO 性能比传统 IO 降低约 30 倍-LMLPHP

端点代码本身:
@RestController
@RequestMapping(produces = {APPLICATION_JSON_VALUE, APPLICATION_STREAM_JSON_VALUE})
@Validated
public class StreamingController {

    @GetMapping("/instruments/{eodDate}")
    public Flux<TestItem> getInstruments(
            @PathVariable @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate eodDate,
            @RequestParam(required = false) Instant asOfTimestamp) {
        //Generate test data in memory
        List<TestItem> collect = IntStream.range(0, 100000)
             .mapToObj(i -> new TestItem.Builder().build())
             .collect(Collectors.toList());
        return Flux.fromIterable(collect);
    }
}

我们正在为 Netty 使用 Spring Boot 配置,我们怀疑默认情况下 Netty 配置错误。
我们正在寻求您的帮助。我会根据您的要求添加任何其他详细信息。

更新:
目标是批量读取整个响应以避免将所有响应放入内存中,因为预期的数据量很大(几 Gb)。在客户端消费一批数据而不是一个元素是可以接受的。

最佳答案

您实际上并不是在测试 NIO 与 IO。 Spring WebFlux 应用程序始终在服务器级别使用非阻塞 IO(使用 Netty、Undertow 或任何 Servlet 3.1+ 异步 IO 兼容服务器)。

在这种情况下,您正在比较:

  • 使用 Spring WebFlux 一次性提供 "application/json" 有效负载
  • 使用 Spring WebFlux 提供流 "application/stream+json" 响应

  • 在第一种情况下,Spring WebFlux 以 react 方式生成响应主体,但将缓冲和刷新决策留给服务器本身。写入网络是有成本的,缓冲 a 但是写入更大的块是有效的。

    在第二种情况下,您要求 Spring WebFlux 为 Flux 的每个元素编写和刷新 。当客户端正在监听(可能是无限的)事件流并且两个不同的事件之间可能存在一些时间时,这很有用。该方法消耗更多资源并解释了性能差异。

    所以这个基准测试不是显示 IO 与 NIO,而是流式与非流式。

    如果您想对响应写入/刷新进行细粒度控制,您可以下降到 ServerHttpResponse 级别并使用 writeAndFlushWith(Flux<Flux<DataBuffer>>) ,但这是相当低的级别,因为您直接处理 DataBuffer 实例。

    另一种方法是创建包含 TestItem 列表的中间 JSON 对象,例如:
    public Flux<TestItemBatch> batch() {
        Flux<TestItem> items= //...;
        Flux<List<TestItem>> itemsLists = items.buffer(100);
        return itemsLists.map(list -> new TestItemBatch(list));
    }
    

    关于java - Webflux + Netty NIO 性能比传统 IO 降低约 30 倍,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52837041/

    10-09 13:49