我reactor-netty用來請求一組 URL。大多數 URL 屬于同一主機。reactor-netty即使已經為前一個 URL 建立了與主機的連接,似乎也為每個 URL 建立了一個全新的 TCP 連接。當建立數百個同時連接時,一些服務器會斷開新連接或開始緩慢響應。代碼示例: Flux.just(...) .groupBy(link -> { String host = ""; try { host = new URL(link).getHost(); } catch (MalformedURLException e) { LOGGER.warn("Cannot determine host {}", link, e); } return host; }) .flatMap(group -> { HttpClient client = HttpClient.create() .keepAlive(true) .tcpConfiguration(tcp -> tcp.host(group.key())); return group.flatMap(link -> client.get() .uri(link) .response((resp, cont) -> resp.status().code() == 200 ? cont.aggregate().asString() : Mono.empty()) .doOnSubscribe(s -> LOGGER.debug("Requesting {}", link)) .timeout(Duration.ofMinutes(1)) .doOnError(e -> LOGGER.warn("Cannot get response from {}", link, e)) .onErrorResume(e -> Flux.empty()) .collect(Collectors.joining()) .filter(s -> StringUtils.isNotBlank(s))); }) .blockLast();在日志中,我看到同一遠程主機的本地端口不同,并且活動和非活動連接的總和遠高于不同主機的數量。這就是為什么我認為這reactor-netty不是重用已經建立的連接。DEBUG [2019-04-29 08:15:18,711] reactor-http-nio-10 r.n.r.PooledConnectionProvider: [id: 0xaed18e87, L:/192.168.1.183:56832 - R:capcp2.naad-adna.pelmorex.com/52.242.33.4:80] Releasing channelDEBUG [2019-04-29 08:15:18,711] reactor-http-nio-10 r.n.r.PooledConnectionProvider: [id: 0xaed18e87, L:/192.168.1.183:56832 - R:capcp2.naad-adna.pelmorex.com/52.242.33.4:80] Channel cleaned, now 1 active connections and 239 inactive connections...DEBUG [2019-04-29 08:15:20,158] reactor-http-nio-10 r.n.r.PooledConnectionProvider: [id: 0xd6c6c5db, L:/192.168.1.183:56965 - R:capcp2.naad-adna.pelmorex.com/52.242.33.4:80] Releasing channelkeep-alive是否可以通過與主機的同一 TCP 連接使用 HTTP 客戶端在同一主機上請求多個 URL ?如果沒有,我如何限制同時連接到同一主機的數量或按順序執行對同一主機的請求(下一個請求只有在收到對前一個響應的響應后)?我使用Californium-SR6發布火車。
1 回答

一只萌萌小番薯
TA貢獻1795條經驗 獲得超7個贊
是的,reactor netty 支持 keep-alive、連接重用和連接池。
請注意,這.flatMap
是一個并行處理內部流的異步操作。因此,當您調用group.flatMap(...
內部請求時,將并行執行。而且由于它們是并行執行的,因此需要建立多個連接。
如果您想按順序執行對同一主機的請求,請將您的示例更改為使用group.concatMap
而不是.flatMap
.
如果您仍想并行執行它們,但限制對單個主機的活動請求的數量,則將您的示例更改為使用.flatMap
帶concurrency
參數的重載版本之一。
此外,由于您使用的是HttpClient.create()
,因此您的示例使用默認的全局 http 連接池。如果您想對連接池進行更多控制,可以指定不同的ConnectionProvider
via HttpClient.create(ConnectionProvider)
。
添加回答
舉報
0/150
提交
取消