共计 1307 个字符,预计需要花费 4 分钟才能阅读完成。
背景痛点
在微服务架构中,频繁的单次 API 调用会导致连接数爆炸和响应延迟问题。具体表现为:

- 每次请求都建立新的 HTTP 连接,TCP 三次握手开销大
- 高并发场景下线程池迅速耗尽,引发线程饥饿
- 服务端负载激增,响应时间呈指数级增长
实测数据表明,当 QPS 达到 500+ 时,传统同步调用方式的 99 线延迟会从 50ms 陡增至 800ms 以上。
技术选型
对比两种主流方案:
- 同步阻塞(RestTemplate)
- 每个请求占用 1 个线程
- 线程切换开销大
-
JMH 测试显示:8 核机器最大吞吐约 1200 req/s
-
异步非阻塞(WebClient)
- 基于 Netty 事件循环
- 单线程可处理上万连接
- 相同环境吞吐达 6500+ req/s
测试环境:
– ECS c6.large (2vCPU/4GiB)
– JMH 1.35
– Spring Boot 2.7.0
核心实现
请求合并与拆分
public Flux<Response> batchCall(List<Request> requests) {return WebClient.create()
.post()
.uri("/batch")
.body(BodyInserters.fromValue(requests))
.retrieve()
.bodyToFlux(Response.class);
}
背压控制
// 限制消费速率
batchCall(requests)
.onBackpressureBuffer(1000) // 设置缓冲队列大小
.subscribe(response -> {// 处理逻辑});
线程池配置
Scheduler scheduler = Schedulers.newBoundedElastic(
50, // 最大线程数
1000, // 任务队列容量
"batch-pool" // 线程名前缀
);
生产级考量
熔断配置
resilience4j.circuitbreaker:
instances:
batchApi:
failureRateThreshold: 50
waitDurationInOpenState: 10s
slidingWindowSize: 20
指数退避重试
Retry.backoff(3, Duration.ofMillis(100))
.maxBackoff(Duration.ofSeconds(5))
.doBeforeRetry(retry -> log.warn("Retrying..."));
避坑指南
- 防限流策略
- 添加
X-RateLimit-Burst: 100header -
控制批量请求大小(建议≤50 条 / 次)
-
连接池优化
HttpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) .doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(10)));
延伸思考
未来改进方向:
1. 适配 gRPC 流式调用
2. 添加 Prometheus 指标暴露
3. 实现动态批处理大小调整
经过上述优化,某电商平台订单查询接口的批量调用耗时从 1200ms 降至 450ms,CPU 利用率降低 40%。建议读者根据实际业务特点调整参数,逐步实现性能优化。
正文完
