为什么 Spring Cloud Gateway 必须用 WebFlux?

引子:为什么Spring Cloud Gateway选择WebFlux?

Spring Cloud Gateway是Spring官方的新一代网关,它彻底抛弃了之前基于Servlet的Zuul 1.x,转而采用WebFlux。

这不是赶时髦,而是网关场景的必然选择。

网关的特殊性

网关的核心工作是什么?转发请求。

css 复制代码
客户端请求
    ↓
网关接收
    ↓
路由到后端服务A、B、C(可能需要调用多个)
    ↓
聚合结果
    ↓
返回给客户端

这个过程中,网关自己几乎不做计算,95%的时间都在:

  • 等待后端服务响应
  • 处理网络I/O

传统Servlet的困境

如果用Servlet容器(Tomcat):

markdown 复制代码
1个请求进来
    ↓
分配1个线程
    ↓
线程发起HTTP调用后端服务
    ↓
线程阻塞等待响应(可能100ms-500ms)
    ↓
收到响应,返回客户端
    ↓
线程释放

问题在哪?

假设网关要承载1万QPS:

  • 每个请求平均耗时200ms
  • 同时在处理的请求 = 10000 * 0.2 = 2000个
  • 需要2000个线程

但Tomcat默认最大线程数是200,即使调到2000:

  • 2000个线程 × 1MB栈空间 = 2GB内存
  • 线程上下文切换开销巨大
  • 大部分线程都在阻塞等待,浪费资源

WebFlux的优势

同样的场景,WebFlux只需要:

  • 8-16个EventLoop线程
  • 内存占用不到200MB
  • 线程永不阻塞,利用率100%

这就是为什么Spring Cloud Gateway必须用WebFlux。

网关不是简单的应用,而是流量枢纽,必须用非阻塞I/O来榨干硬件性能。

第一层:WebFlux的技术栈

先看WebFlux到底由哪些部分组成:

graph TB A[你的Controller代码] --> B[Spring WebFlux框架层] B --> C[Project Reactor响应式库] C --> D[Netty网络I/O框架] D --> E[Java NIO] E --> F[操作系统 epoll/kqueue]

每一层都有明确的职责:

层次 组件 职责 举例
应用层 Spring WebFlux 路由、注解、依赖注入 @GetMapping
编程模型层 Project Reactor 响应式API Mono、Flux、flatMap
网络层 Netty 事件驱动I/O EventLoop、Channel
系统抽象层 Java NIO 非阻塞I/O Selector、ByteBuffer
操作系统层 epoll/kqueue I/O多路复用 系统调用

这些层次环环相扣,缺一不可。

第二层:Reactor到底是什么

很多人第一次接触WebFlux,会被两个"Reactor"搞晕:

  • Netty的Reactor模式
  • Project Reactor库

它们是不同的东西。

Netty的Reactor模式

这是一种设计模式,用于处理并发I/O:

java 复制代码
// Netty的Reactor实现
EventLoopGroup bossGroup = new NioEventLoopGroup(1);     // 主Reactor
EventLoopGroup workerGroup = new NioEventLoopGroup(4);   // 从Reactor

ServerBootstrap bootstrap = new ServerBootstrap()
    .group(bossGroup, workerGroup);

Boss负责接收连接,Worker负责处理I/O,这就是Reactor模式的主从多线程版本。

Project Reactor库

这是Spring生态的响应式编程库,提供Mono和Flux这些API:

java 复制代码
// 纯内存操作,不需要Netty
Mono.just(1)
    .map(i -> i * 2)
    .filter(i -> i > 1)
    .subscribe(System.out::println);

Project Reactor是独立的库,不依赖Netty。它只是提供了响应式编程的抽象,类似Java 8的Stream API。

那为什么总和Netty一起出现?

因为在WebFlux做网络I/O时,底层用Netty实现,上层用Reactor API编程。两者配合工作:

arduino 复制代码
Reactor定义"做什么"(业务逻辑)
Netty负责"怎么做"(网络I/O)

第三层:一个半Netty的架构

这是理解WebFlux的核心。

WebFlux使用了两套Netty线程组,但第二套是"阉割版"。

Server端:完整的Netty

java 复制代码
// 标准的Netty服务端配置
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(4);

ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
    .channel(NioServerSocketChannel.class)
    .childHandler(new HttpServerInitializer());

这是完整的Reactor模式:

  • Boss线程组 :专门负责accept()新的TCP连接
  • Worker线程组:负责处理已建立连接的I/O读写
graph LR A[客户端连接1] --> B[Boss线程] C[客户端连接2] --> B D[客户端连接3] --> B B --> E[Worker线程1] B --> F[Worker线程2] B --> G[Worker线程3] B --> H[Worker线程4]

Boss就像公司老板,只负责接项目(接收连接),然后分配给项目经理(Worker)去执行。

Client端:半个Netty

当WebFlux需要调用外部服务时,用的是WebClient:

java 复制代码
WebClient client = WebClient.builder()
    .baseUrl("http://api.example.com")
    .build();

Mono<User> user = client.get()
    .uri("/user/123")
    .retrieve()
    .bodyToMono(User.class);

WebClient底层用的是Netty的HttpClient:

java 复制代码
// Netty Client的配置
HttpClient httpClient = HttpClient.create()
    .runOn(new NioEventLoopGroup(4));  // 只有EventLoop

注意:这里只有EventLoop,没有Boss线程组。

为什么Client不需要Boss?

这是关键问题。

Boss的职责是什么?

java 复制代码
// Boss线程做的事
while (true) {
    SocketChannel clientSocket = serverSocket.accept();  // 接收新连接
    workerGroup.register(clientSocket);  // 分配给Worker
}

Boss负责监听端口,接收客户端主动发起的连接请求。

Client的工作方式完全不同:

java 复制代码
// Client主动连接服务端
Socket socket = new Socket("api.example.com", 80);
socket.connect();  // 主动发起连接

Client是主动连接别人,不需要监听端口,自然不需要Boss。

类比说明

Server端(完整公司架构)

css 复制代码
老板(Boss)
    ↓
专门负责签约新客户(接收TCP连接)
    ↓
把项目分配给项目经理(Worker)
    ↓
项目经理负责执行(处理I/O)

Client端(外包开发团队)

markdown 复制代码
没有老板
    ↓
开发人员直接接到任务(主动发起连接)
    ↓
自己去对接客户(发送HTTP请求)
    ↓
完成后直接汇报(接收HTTP响应)

外包团队不需要老板来接活,因为活是别人派给他们的。

这就是为什么说"半个Netty":Client端的Netty只有EventLoop,缺少Boss组件。

完整架构图

graph TB subgraph "Server端 - 完整Netty" SB[Boss线程组
1个线程
接收TCP连接] SW[Worker线程组
4个线程
处理HTTP请求] SB --> SW end subgraph "Client端 - 半个Netty" CE[EventLoop线程组
4个线程
发起HTTP请求] end SW -.派发外部调用.-> CE CE -.返回响应数据.-> SW style SB fill:#90EE90 style SW fill:#87CEEB style CE fill:#FFB6C1
  • 绿色:Server Boss(接收连接)
  • 蓝色:Server Worker(处理业务)
  • 粉色:Client EventLoop(调用外部)

Server和Client是两套独立的线程组,通过Reactor的回调机制协作。

第四层:一个请求的完整生命周期

假设有个Controller需要查询用户和订单:

java 复制代码
@RestController
public class OrderController {
    
    @Autowired
    private WebClient webClient;
    
    @GetMapping("/order/{userId}")
    public Mono<OrderDTO> getOrder(@PathVariable int userId) {
        return webClient.get()
            .uri("http://user-service/user/" + userId)
            .retrieve()
            .bodyToMono(User.class)
            .flatMap(user -> webClient.get()
                .uri("http://order-service/order/" + user.getOrderId())
                .retrieve()
                .bodyToMono(Order.class))
            .map(order -> new OrderDTO(order));
    }
}

完整时序图

sequenceDiagram participant Client as 客户端 participant SB as Server Boss
(1个线程) participant SW as Server Worker
(4个线程) participant Code as 业务代码
(Reactor) participant CE as Client EventLoop
(4个线程) participant US as 用户服务 participant OS as 订单服务 Client->>SB: HTTP请求 Note over SB: Boss接收TCP连接 SB->>SW: 分配给Worker线程2 Note over SW: 线程2解析HTTP SW->>Code: 路由到getOrder() Note over Code: 执行webClient.get(user) Code->>CE: 派发给Client EventLoop Note over SW: Worker线程2留下钩子
立即返回,不等待 Note over CE: Client线程5发起HTTP CE->>US: GET /user/123 Note over SW: Worker线程2继续
处理其他请求 US->>CE: 返回User数据 Note over CE: 触发Reactor回调 CE->>Code: 执行flatMap逻辑 Note over Code: 执行webClient.get(order) Code->>CE: 再次派发任务 Note over CE: Client线程6发起HTTP CE->>OS: GET /order/456 OS->>CE: 返回Order数据 Note over CE: 触发最后的map回调 CE->>SW: 返回最终结果 Note over SW: Worker线程2收到结果 SW->>Client: 发送HTTP响应
不经过Boss

详细步骤拆解

第1步:接收连接(Boss的工作)

arduino 复制代码
客户端发起TCP连接
    ↓
Server Boss线程(线程1)执行accept()
    ↓
创建SocketChannel
    ↓
注册到Server Worker线程组
    ↓
Boss线程回到循环,继续accept其他连接

Boss只负责接收连接,立即就交出去了。

第2步:处理HTTP请求(Worker的工作)

scss 复制代码
假设分配给Worker线程2
    ↓
线程2从SocketChannel读取HTTP请求
    ↓
解析HTTP头、路径、参数
    ↓
WebFlux路由:/order/123 -> OrderController.getOrder(123)
    ↓
执行Controller方法

这一步都在线程2上同步执行。

第3步:第一次外部调用(关键转折点)

java 复制代码
// 执行到这一行
return webClient.get()
    .uri("http://user-service/user/123")
    .retrieve()
    .bodyToMono(User.class)

这里发生了什么?

arduino 复制代码
Worker线程2执行webClient.get()
    ↓
创建HTTP请求对象
    ↓
派发给Client EventLoop线程组
    ↓
假设分配给Client线程5
    ↓
Worker线程2注册回调(钩子)
    ↓
立即返回Mono<User>对象(此时还没有数据)
    ↓
Worker线程2的工作完成,可以处理其他请求了

关键:Worker线程2不等待!

它留下一个"钩子"(回调函数),然后立即释放,去处理下一个HTTP请求了。

第4步:Client线程发起实际调用

arduino 复制代码
Client EventLoop线程5拿到任务
    ↓
使用Netty的Channel发起HTTP请求
    ↓
通过NIO的Selector注册OP_CONNECT事件
    ↓
发送HTTP请求数据到用户服务
    ↓
注册OP_READ事件,等待响应
    ↓
线程5不阻塞,继续处理其他任务

Client线程5也不会傻等,它发出请求后,通过Selector注册了"读事件",然后去干别的了。

第5步:接收用户服务响应

arduino 复制代码
用户服务返回数据
    ↓
Selector检测到OP_READ事件
    ↓
Client线程5被唤醒
    ↓
从SocketChannel读取响应数据
    ↓
解析HTTP响应体,得到User对象
    ↓
触发Reactor的回调链

这时,之前注册的"钩子"被触发了。

第6步:执行flatMap(还在Client线程5上)

java 复制代码
.flatMap(user -> webClient.get()
    .uri("http://order-service/order/" + user.getOrderId())
    .retrieve()
    .bodyToMono(Order.class))
arduino 复制代码
Client线程5拿到User对象
    ↓
执行flatMap中的lambda
    ↓
再次调用webClient.get()
    ↓
这次可能分配给Client线程6
    ↓
发起第二个HTTP请求到订单服务
    ↓
注册新的回调

第7步:订单服务响应

arduino 复制代码
订单服务返回Order数据
    ↓
Client线程6接收响应
    ↓
触发map回调
    ↓
构造OrderDTO对象
    ↓
调用之前Worker线程2留下的钩子

第8步:返回给客户端(Worker的收尾工作)

javascript 复制代码
Worker线程2(或者其他空闲的Worker)被唤醒
    ↓
拿到最终的OrderDTO对象
    ↓
序列化成JSON
    ↓
通过原来的SocketChannel发送HTTP响应
    ↓
注意:直接发送,不经过Boss

Boss只管接收新连接,响应由Worker直接发送。

时间线对比

传统Servlet模式

makefile 复制代码
T0: 请求到达,分配线程A
T100ms: 线程A调用用户服务,阻塞等待
T200ms: 收到用户服务响应
T200ms: 线程A调用订单服务,阻塞等待
T300ms: 收到订单服务响应
T300ms: 线程A返回结果
总耗时:300ms
线程A利用率:33%(100ms实际工作,200ms等待)

WebFlux模式

makefile 复制代码
T0: 请求到达,Worker线程2处理
T0: Worker线程2派发任务给Client线程5
T0: Worker线程2去处理其他请求了
T50ms: Client线程5同时发起用户和订单服务调用
T100ms: 两个服务同时返回
T100ms: Client线程触发回调,汇总结果
T100ms: 通知Worker线程(可能是线程3)发送响应
总耗时:100ms
Worker线程利用率:接近100%

性能差距:3倍。

而且WebFlux的Worker线程可以同时处理成百上千个请求,Servlet的线程在阻塞等待。

第五层:公司项目的完整类比

用一个更完整的类比来理解整个流程。

角色定义

WebFlux组件 公司角色 职责
Server Boss 公司老板 签约新客户(接收TCP连接)
Server Worker 项目经理 管理项目、协调资源
Client EventLoop 外包开发团队 干具体的活(调用外部API)
Reactor回调 项目钩子/里程碑 通知机制

工作流程

场景:客户要求做一个项目,需要外包部分工作。

第1步:老板接项目

markdown 复制代码
客户上门
    ↓
老板接待(Boss线程accept连接)
    ↓
签订合同
    ↓
分配给项目经理张三(Worker线程2)
    ↓
老板继续接待其他客户

老板只负责拉业务,不管具体执行。

第2步:项目经理启动项目

arduino 复制代码
张三接手项目
    ↓
查看需求文档(解析HTTP请求)
    ↓
发现需要用户数据,这部分要外包
    ↓
联系外包团队李四(Client线程5)
    ↓
在项目管理系统设置里程碑:用户数据完成后通知我
    ↓
张三继续去管理其他项目,不干等

关键:张三不等外包完成,他去忙别的了。

第3步:外包团队干活

markdown 复制代码
李四接到任务
    ↓
去用户服务API拉数据
    ↓
不阻塞等待,同时可以接其他任务
    ↓
用户服务返回数据
    ↓
李四拿到数据,触发里程碑
    ↓
通知张三:用户数据好了

第4步:项目经理继续推进

arduino 复制代码
张三收到通知
    ↓
拿到用户数据,查看订单ID
    ↓
又需要订单数据,再次外包
    ↓
联系外包团队王五(Client线程6)
    ↓
设置新的里程碑:订单数据完成后通知我
    ↓
张三又去干别的了

第5步:再次外包

markdown 复制代码
王五接到任务
    ↓
去订单服务API拉数据
    ↓
订单服务返回数据
    ↓
触发里程碑,通知张三

第6步:项目收尾

markdown 复制代码
张三收到订单数据
    ↓
汇总用户数据和订单数据
    ↓
生成最终报告
    ↓
直接交付给客户(发送HTTP响应)
    ↓
不需要再找老板审批

老板只管接项目,交付由项目经理完成。

关键点总结

  1. 老板(Boss)只接活,不干活

    • Boss线程只负责accept连接
    • 立即分配给Worker,自己继续接新连接
  2. 项目经理(Worker)不傻等

    • 遇到需要外部资源的地方,立即外包
    • 留下"钩子"(回调),去管理其他项目
    • 一个项目经理可以同时管理几百个项目
  3. 外包团队(Client EventLoop)并发干活

    • 同时可以处理多个外包任务
    • 不阻塞,用事件驱动
    • 干完了触发钩子通知项目经理
  4. 交付不经过老板

    • 项目完成后,项目经理直接交付
    • Boss不参与项目执行和交付

为什么这么高效?

传统Servlet模式(每个项目配一个专职经理)

markdown 复制代码
100个项目同时进行
    ↓
需要100个项目经理
    ↓
每个经理只盯自己的项目
    ↓
大部分时间在等外包完成(阻塞)
    ↓
人力浪费严重

WebFlux模式(少数经理管理大量项目)

markdown 复制代码
100个项目同时进行
    ↓
只需要4个项目经理
    ↓
每个经理同时管理25个项目
    ↓
利用等待时间处理其他项目
    ↓
人力利用率接近100%

第六层:为什么必须全链路响应式

有些开发会这么写:

java 复制代码
@GetMapping("/user")
public Mono<User> getUser() {
    // 用了Mono,但还是阻塞操作
    User user = jdbcTemplate.queryForObject(
        "SELECT * FROM users WHERE id = 1",
        new BeanPropertyRowMapper<>(User.class)
    );
    return Mono.just(user);
}

表面上返回了Mono,实际上还是阻塞的。

会发生什么

scss 复制代码
Worker线程2执行这个方法
    ↓
执行jdbcTemplate.queryForObject()
    ↓
这是JDBC,会阻塞等待数据库返回(可能50ms)
    ↓
Worker线程2被阻塞,啥也干不了
    ↓
50ms后数据库返回
    ↓
包装成Mono.just(user)返回

线程2被阻塞了50ms!

假设只有4个Worker线程,如果同时来4个这样的请求:

ini 复制代码
4个Worker线程全部阻塞
    ↓
第5个请求进来,没有空闲线程
    ↓
请求排队等待
    ↓
QPS = 4个线程 / 0.05秒 = 80

还不如Tomcat的200个线程!

正确的做法

java 复制代码
@GetMapping("/user")
public Mono<User> getUser() {
    // 使用R2DBC,真正的响应式数据库驱动
    return r2dbcTemplate
        .select(User.class)
        .matching(query(where("id").is(1)))
        .one();
}

这样Worker线程不会阻塞:

sql 复制代码
Worker线程2执行这个方法
    ↓
调用r2dbcTemplate.select()
    ↓
通过R2DBC发起异步查询(类似WebClient)
    ↓
立即返回Mono<User>(还没有数据)
    ↓
Worker线程2去处理其他请求
    ↓
数据库返回数据时,触发回调
    ↓
Mono发出User对象

响应式技术栈对照

场景 阻塞方式 响应式方式
HTTP客户端 RestTemplate WebClient
数据库 JDBC (JdbcTemplate) R2DBC
Redis Jedis (同步) Lettuce Reactive
MongoDB MongoTemplate ReactiveMongoTemplate
Kafka KafkaTemplate ReactiveKafkaTemplate

任何一个环节用阻塞API,整个链路的响应式优势都会丧失。

第七层:性能数据对比

测试场景

模拟网关场景:每个请求需要调用3个后端服务,每个服务耗时100ms。

环境

  • 机器:4核CPU、8GB内存
  • 并发请求:1000

Spring MVC + Tomcat

diff 复制代码
配置:
- Tomcat线程池:200
- 每个请求耗时:100ms + 100ms + 100ms = 300ms(串行)

结果:
- QPS:666(200线程 / 0.3秒)
- 平均响应时间:1500ms
- P99响应时间:3000ms
- CPU使用率:85%
- 内存占用:1.2GB(200个线程栈)

Spring WebFlux + Netty

diff 复制代码
配置:
- Server Worker线程:4
- Client EventLoop线程:4
- 每个请求耗时:max(100ms, 100ms, 100ms) = 100ms(并发)

结果:
- QPS:10000+
- 平均响应时间:120ms
- P99响应时间:200ms
- CPU使用率:60%
- 内存占用:512MB

性能差距

指标 Spring MVC WebFlux 提升
QPS 666 10000 15倍
响应时间 1500ms 120ms 12倍
内存 1.2GB 512MB 减少60%
线程数 200 8 减少96%

为什么差距这么大?

  1. 外部调用并发执行:WebFlux可以同时发起3个请求,MVC必须串行
  2. 线程不阻塞:WebFlux的8个线程永远在工作,MVC的200个线程大部分在等待
  3. 内存占用小:少量线程意味着更少的栈空间

第八层:底层技术原理

WebFlux的性能来自底层技术的层层支撑。

Linux的epoll

这是一切的基础:

c 复制代码
// 创建epoll实例
int epoll_fd = epoll_create(1024);

// 注册多个socket
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket1, &event1);
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket2, &event2);
// ... 注册1000个socket

// 等待事件
while (1) {
    int n = epoll_wait(epoll_fd, events, 1024, -1);
    for (int i = 0; i < n; i++) {
        // 处理有数据的socket
        handle_event(events[i]);
    }
}

关键:一个线程可以监听1000个socket,哪个有数据就处理哪个。

传统阻塞I/O需要1000个线程,每个线程盯一个socket。

Java NIO的Selector

Java把epoll封装成了Selector:

java 复制代码
Selector selector = Selector.open();

// 注册多个Channel
channel1.register(selector, SelectionKey.OP_READ);
channel2.register(selector, SelectionKey.OP_READ);
// ... 注册更多

while (true) {
    selector.select();  // 等待事件,底层调用epoll_wait
    
    Set<SelectionKey> keys = selector.selectedKeys();
    for (SelectionKey key : keys) {
        if (key.isReadable()) {
            // 有数据可读
            SocketChannel channel = (SocketChannel) key.channel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            channel.read(buffer);
        }
    }
}

Netty的EventLoop

Netty把Selector封装成了EventLoop:

java 复制代码
// EventLoop = 一个线程 + 一个Selector + 一个任务队列
EventLoopGroup group = new NioEventLoopGroup(4);

// 4个EventLoop,每个都是:
while (true) {
    selector.select(timeout);  // 等待I/O事件
    processSelectedKeys();     // 处理I/O
    runAllTasks();            // 执行任务队列中的任务
}

EventLoop做三件事

  1. 等待I/O事件(通过Selector)
  2. 处理I/O事件(读写数据)
  3. 执行异步任务(业务逻辑)

Reactor的异步编排

Reactor把回调地狱变成了链式调用:

java 复制代码
// 回调地狱
webClient.get("/user/1", user -> {
    webClient.get("/order/" + user.getOrderId(), order -> {
        webClient.get("/product/" + order.getProductId(), product -> {
            // 三层嵌套
            return result;
        });
    });
});

// Reactor链式调用
webClient.get("/user/1")
    .flatMap(user -> webClient.get("/order/" + user.getOrderId()))
    .flatMap(order -> webClient.get("/product/" + order.getProductId()));

代码更清晰,但本质都是异步回调。

第九层:适用场景分析

适合用WebFlux

网关系统

diff 复制代码
Gateway的核心工作:
- 接收请求(I/O)
- 路由(CPU极少)
- 调用后端(I/O)
- 聚合响应(CPU极少)
- 返回(I/O)

95%都是I/O等待,WebFlux完美匹配

微服务聚合层

scss 复制代码
一个请求调用5-10个微服务
    ↓
WebFlux可以并发调用
    ↓
响应时间 = max(服务耗时),不是sum(服务耗时)

实时通信

markdown 复制代码
WebSocket长连接
    ↓
1万个连接 = 1万个用户在线
    ↓
WebFlux只需8个线程
    ↓
Tomcat需要1万个线程(根本不现实)

不适合用WebFlux

简单CRUD应用

rust 复制代码
读数据库 -> 返回
写数据库 -> 返回

并发不高(QPS < 1000)
响应式优势体现不出来
反而增加代码复杂度

CPU密集型任务

css 复制代码
图像处理、算法计算、加密解密

这些任务的瓶颈是CPU,不是I/O
响应式无法提升性能

团队不熟悉

复制代码
响应式编程学习曲线陡
调试困难
如果团队没经验,反而降低开发效率

总结

核心要点

  1. 架构:一个半Netty

    • Server端:完整的Boss-Worker
    • Client端:只有EventLoop,没有Boss
    • Boss只管接连接,Worker处理业务,Client调外部
  2. 工作原理:事件驱动

    • 操作系统的epoll:一个线程监听多个连接
    • Java NIO的Selector:封装epoll
    • Netty的EventLoop:事件循环 + 任务队列
    • Reactor的API:优雅的异步编排
  3. 性能关键:线程不阻塞

    • Worker派发任务后立即返回
    • Client并发调用外部服务
    • 少量线程处理大量并发
    • 资源利用率接近100%
  4. 适用场景:高并发I/O

    • 网关系统
    • 微服务聚合
    • 实时通信
    • 高并发API

一句话总结

WebFlux用一个半Netty(Server完整 + Client阉割)的架构,通过事件驱动和异步回调,让少量EventLoop线程处理大量并发I/O,从而实现在网关等I/O密集场景下的高性能。

学习建议

循序渐进

markdown 复制代码
1. 理解Java NIO(Selector原理)
2. 学习Netty(EventLoop模型)
3. 掌握Reactor(Mono/Flux/操作符)
4. 实战WebFlux项目
5. 性能调优

避免误区

  • 不是所有项目都要用WebFlux
  • 不是加个Mono就是响应式
  • 必须全链路响应式才有效果
  • 调试难度确实比MVC高

合理选型

根据实际场景决定,不要为了技术而技术。简单的CRUD用Spring MVC就够了,真正的高并发场景才考虑WebFlux。


参考资料

  • Spring WebFlux官方文档
  • Project Reactor文档
  • Netty权威指南
  • Spring Cloud Gateway源码
  • Apache ShenYu架构设计
相关推荐
思通数据2 小时前
AI智能预警系统:矿山、工厂与油气站安全管理架构浅析
人工智能·深度学习·安全·目标检测·机器学习·计算机视觉·架构
G_H_S_3_2 小时前
【网络运维】容器、容器架构与docker部署
运维·网络·docker·架构
LYFlied2 小时前
前端工程化核心面试题与详解
前端·面试·工程化
码匠君3 小时前
Dante Cloud 升级 Spring Boot 4 经验分享
经验分享·spring boot·后端
秋邱3 小时前
Java面向对象进阶:封装、继承、多态的实现逻辑与实战案例
java·开发语言·后端·spring cloud·ar·restful
Coder_Boy_3 小时前
基于MQ实现秒杀订单系统的异步化架构
java·开发语言·架构
隐语SecretFlow3 小时前
TrustFlow 可信执行环境之 Intel TDX TEE 方案
架构·开源
架构精进之路3 小时前
一文搞懂什么是 Vibe Coding?
人工智能·后端
IT 行者3 小时前
Spring Boot 4 升级指南:告别RestTemplate,拥抱现代HTTP客户端
spring boot·后端·http