公司新项目用上了 JDK 17 + Spring 2.6.6 。发现 Spring 5 新增了 WebClient 类,使用非阻塞 IO 、支持函数式编程等等一大堆优点。但是使用时,很多跟 Apache HttpClient 那一套有太多不同。
想问问各位大佬,有没有关于 WebClient 的最佳实践?
另外,如果要使用 WebClient 封装一个通用的 HttpClient 类,要注意什么?
1
zartouch 2022-04-16 11:30:02 +08:00 1
webclient 用的是响应式编程那套设计的, 如果不是吞吐量太大 (而且 IO 占比不高的也不好说,具体数据请自行 google ,既然你问了大概率不需要), 最佳实践就是没有必要别用,还是 spring MVC blocking IO 那套好写好维护。
|
2
monkeyWie 2022-04-16 11:34:40 +08:00 1
如果你没用 spring webflux ,就没必要用 webclient
|
3
fox0001 OP |
4
yazinnnn 2022-04-16 12:00:25 +08:00 1
https://projectreactor.io/
https://www.baeldung.com/spring-5-webclient 就是用 reactor 包了一下呗,这有啥最佳实践的..... 配合 webflux 一路 compose/flatmap 下去就得了,如果有数据库事物操作的话不要乱用 recover/resume 操作符 貌似 reactive transaction 和 kotlin 的 suspend 函数集成还在 wip 阶段,感兴趣可以自己看看 |
5
fox0001 OP @yazinnnn #4
就是看了太多文章,有太多困惑。 比如: 1 )有文章说不要用 create 方法创建 WebClient 对象,要用 build 方法。但是官方文档没提及这个。 2 ) exchange 方法过时了,想获取更多响应结果的原始信息,不知道怎么处理。 3 )领导说要撸一个通用的 HttpClient 类,屏蔽各种底层实现。但是 WebClient 的函数式编程太爽了,撸个通用的,还不如直接使用。况且各种 http 服务有各种要求… |
6
zartouch 2022-04-16 12:22:17 +08:00
@fox0001 嗯随便找个顺手的就行。 说实话我觉得你对响应式编程和它的应用场景,基本概念还很模糊,最好先看看这部分知识,看点例子。 除非你处理流程都是非阻塞的,否则单独用 webclient 最后你还得 call block 拿结果,等于是阻塞模型,而且 webclient 底层是 netty 非阻塞的那套,线程设置的很少,你用阻塞来玩,性能反而更差,流量大点甚至导致线程用尽。
|
7
chendy 2022-04-16 12:33:12 +08:00 1
WebClient 是 web flux 的,响应式那套东西,怎么说呢,没必要就别用,写起来还是累
另外既然 spring 了就 RestTemplate 呗,底层适配多种 http 库,配合 Spring boot 的 RestTemplateBuilder 用,也是个“通用”的 HttpClient 了 |
8
Kyle18Tang 2022-04-16 12:37:16 +08:00 1
推荐 WebClient ,RestTemplate 已经没有新功能增加了,我记得 Spring 官方文档也有写推荐使用 WebClient ,Spring MVC 项目也可以使用 WebClient 。
|
9
Kyle18Tang 2022-04-16 12:39:15 +08:00
As of 5.0 the RestTemplate is in maintenance mode, with only minor requests for changes and bugs to be accepted going forward. Please, consider using the WebClient which offers a more modern API and supports sync, async, and streaming scenarios.
|
10
cheng6563 2022-04-16 12:56:27 +08:00 1
没事别用 aio ,会变的不幸。我完全理解不了函数式编程有什么爽的。
让我用 aio 我不如直接重新用 go 写。 |
11
yazinnnn 2022-04-16 12:59:42 +08:00
配合 mvc 用那就简单了,直接 block()就行
exchangeToMono/exchangeToFlux 方法里可以传一个类型为(ClientResponse)->Mono/Flux 的 lambda,想要啥都在那里面 |
12
yazinnnn 2022-04-16 13:03:45 +08:00
go boy 能接受 if err!=null ,却不能接受泛型,看不上函数式不是很正常吗
|
13
MakHoCheung 2022-04-16 13:51:17 +08:00 1
WebClient 可以让你在一次处理请求的时候发超多的异步 RPC 调用,如果用普通的 HTTP Client 的话同时发起的异步 RPC 就受线程池数量限制了,记得最新的 Apache HttpClient 底层也是 NIO 了吧,效果应该跟 WebClient 差不多
|
14
fox0001 OP @Kyle18Tang 8
@yazinnnn #11 @MakHoCheung #13 对于怎样使用 WebClient ,我有太多疑问 1 )是否可以整个系统,所有 restful 客户端使用同一个 webClient 对象?或者是否要改为每个 restful 客户端都各自 builder 一个 webClient ?还是每次请求都 build 一个? 2 ) webClient 的 baseUrl 之类的统一设置,会不会提高性能? 3 )关于 Timeout 配置,build 的时候统一配置的 connectTimeout 、readTimeout 、writeTimeout ,跟 Mono 和 Flux 的 timeout ,两个有什么不同。 4 )写 restful 客户端时,有例子把 webClient 作为私用属性,加上 @Autowired ,让 Spring 初始化后装配进去,也有例子设置 WebClient.Builder 参数。两种方式,哪个更佳? 等等…… 所以想问问有没有最佳实践,或者有哪些开源项目的代码可以直接参考? |
15
cnhongwei 2022-04-16 16:43:40 +08:00 1
|
16
byte10 2022-04-16 18:02:35 +08:00 1
@zartouch 完全正确。
@fox0001 你可以看看这个 https://www.bilibili.com/video/BV1Gq4y1e752 ,这有用到你说的那个响应式编程 httpclient 。#6 楼 说的是非常正确的。如果你的整个项目都是同步编程开发,那么最好不要用响应式编程的工具,不然会很麻烦,除非你很清楚这个使用方式。 这个讲 NIO 的为啥那么强,最好看下这个,https://www.bilibili.com/video/BV1Gq4y1e752 |
17
V2Q 2022-04-16 18:08:04 +08:00 1
最近刚好在用这个,也找了很多,最佳实践是否需要根据自己的场景来呢?可能也有不足的地方,希望懂的大佬提出。
我这边需要对接不同厂家,每个厂家的服务会部署在多个机器上,以下是我的配置 这是 WebClient.Builder 以下配置根据自己情况修改 ```java @Configuration @EnableWebFlux @Slf4j public class WebFluxConfig { @Bean public WebClient.Builder getWebClientBuilder() { //配置固定大小连接池 ConnectionProvider connectionProvider = ConnectionProvider.create("DS-connection", 20); //设置 ssl 信任客户端 SslContext sslContext = null; try { sslContext = SslContextBuilder.forClient() .trustManager(InsecureTrustManagerFactory.INSTANCE).build(); } catch (SSLException e) { e.printStackTrace(); } SslContext finalSslContext = sslContext; HttpClient httpClient = HttpClient.create(connectionProvider).secure(t -> t.sslContext(finalSslContext)) .tcpConfiguration(tcpClient -> tcpClient.doOnConnect(conn -> //读超时 30 秒 conn.handler(new ReadTimeoutHandler(30, TimeUnit.SECONDS)) //写超时 30 秒 .handler(new WriteTimeoutHandler(30, TimeUnit.SECONDS)) ) //连接超时 60 秒 .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000) .option(ChannelOption.TCP_NODELAY, true)); return WebClient.builder().clientConnector(new ReactorClientHttpConnector( httpClient)); } } ``` 不同的厂商 参数 如果是固定的 可以通过读取配置完成 ```java @Component public class Test { @Autowired private WebClient.Builder webClientBuilder; /** * @param uri * @param parameter * @return */ public Mono<HashMap> get(String url, String token, String uri, Object... parameter) throws Exception { return null; } /** * @param uri * @return */ public Mono<HashMap> get(String url, String token, String uri) throws Exception { return null; } /** * @param uri * @param parameter * @return */ public Mono<HashMap> post(String url, String token, String uri, Object parameter) throws Exception { return null; } } ``` 异常我是抛出在同一个地方统一处理 最后我觉得 还是需要根据你的实际场景来,我也是第一次用这个,RestTemplate 就向上面说的没有新增加了,推荐使用 webclient ,所以才想尝试一下用的这个,项目主要还是 springmvc ,希望能帮助到你。 |
18
lmshl 2022-04-16 18:22:08 +08:00 1
我用过 > 9 种 AIO Http Client
Scala: http4s / tapir / akka-http / play ws client Python: aio-http Kotlin: ktor on CIO Rust: reqwest Javascript: axios / fetch 说实话使用体验非常流畅,Spring 新版的 WebClient 因为还是受到 Java 语言不灵活的限制,使用体验大概率是要比以上 9 种都要差一些的。 Reactive Stream 的使用体验就是,>100 TPS 的服务才占用 0.2 个 CPU 核心,以至于我开发的服务在公司里没什么存在感。而且错误处理和理论模型也比 Go 要强好多倍。 既然 Spring 新加了这功能,我觉得你不妨体验一下,至于封装嘛,建议抄一下 Axios 之类的设计,让同事们更好上手。不要固步自封,不然升级了和没升级有什么区别呢。 |
19
git00ll 2022-04-16 22:00:18 +08:00 1
除非你的项目中 http 占用大量资源,否则不如用老牌 apache httpclient 想要 nio 可以用 apache async client 。不推荐用,
|
20
git00ll 2022-04-16 22:07:08 +08:00
毕竟大多数项目的耗时大头都在数据库层面,使用堵塞 io 只是比 nio 多占几十个个线程,还不至于影响到问题的核心。
我曾将公司项目从 apache httpclient 改为 webclient ,从压测上看对 tps 提升十分有限。因为 tps 上升之后下游服务瓶颈在数据库,导致堵塞本服务,所以本服务是否用 nio 都不会对 tps 带来本质提升。 但却带来挺多坏处,比如偶尔发生的 io 异常,连接中断之类的。使用 apache httpclient 后再也没有遇到这种情况。 还有就是堵塞式的天生是线程隔离的,输出日志携带 mdc 查日志要方便很多。 |
21
jeesk 2022-04-18 01:05:02 +08:00 via Android 1
我直接告诉你吧。webflux 提高性能并不明显。,但是可以可以提高并发量指标。servlet 的方式访问并发不高, 请求时间有长有短。wenflux 并发上去了,时间很稳定。 如果追求高并发,和接口时间稳定。 可以考虑上 webflux ,我们业务有一块是日志统计,用的就是 webflux. 感觉不错。 我做过压力测试 https://www.jianshu.com/p/77e8b64ab710
|