概述
典型的web應用服務處理使用者請求過程中,許多互動本質上是阻塞的,例如涉及資料庫調用以擷取或更新資料的互動,第三方接口調用等。每個線程一次處理一個請求,在多核平台上,在總體響應時間方面具有明顯的優勢。這種并發模型被稱為Thread-Per-Request模型。
該模型并沒有解決在單個線程中的大多數互動仍然是阻塞的這一事實。此外Java實作并發的本機線程在上下文切換方面也需要不少損耗。
随着web應用程式面臨越來越多的請求,Thread-Per-Request模型效果是低于預期的。
是以,我們需要一個并發模型,它可以幫助我們用相對較少的線程數處理越來越多的請求。這是采用響應式程式設計的主要動機之一。
Reactive并發模型
Reactive程式設計帶來的根本差別是異步性,流程運作從一系列同步操作轉換為異步事件流。在異步非阻塞的環境中,可以實作更高的并發性和更好的資源使用率。
例如,從資料庫的讀取資料的操作在訂閱後調用立即傳回,不會阻塞調用線程,訂閱者可以在收到事件通知後進行事件處理。
事件循環模型
響應式異步程式設計模型采用如下事件循環模型實作用更少的線程實作更高的并發性。
如圖所示,事件循環的抽象設計,展示了響應式異步程式設計的思想:
- 事件循環在單個線程中連續運作;
- 事件循環順序處理事件隊列中的事件,并在向平台注冊回調後立即傳回;
- 平台可以觸發操作的完成,如資料庫調用或外部服務調用;
- 事件循環可以在操作完成通知觸發回調,并将結果發送回調用者。
事件循環模型在許多平台中實作,包括Node.js、Netty和Ngnix。它們提供了比傳統平台(如Apache HTTP Server、Tomcat或JBoss)更好的可擴充性。
Spring WebFlux架構
WebFlux是Spring在5.0版中添加的響應式Web架構,與Spring中的傳統web架構是并行關系而不是取代。
- Spring WebFlux通過函數路由擴充了傳統的基于注釋的程式設計模型;
- 使底層HTTP運作時适應Reactive Streams API,使運作時具有互操作性;
- 能夠支援多種Reactive Runtime,包括Servlet 3.1+容器,如Tomcat、Reactor、Netty或Undertow;
- 包括WebClient,用于HTTP請求的響應式非阻塞用戶端。
Reactor Netty
Reactor Netty(https://netty.io/)是Spring Boot WebFlux預設的嵌入式伺服器。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
可以看下Netty預設建立的線程:
除了伺服器的正常線程外,Netty還生成了一組用于請求處理的工作線程,數量通常跟可用的CPU核心相關。讓我們看看Netty是如何利用Java NIO實作事件循環:
EventLoopGroup管理一個或多個EventLoop,它必須持續運作。是以,不建議建立比可用核心數量更多的EventLoops。
EventLoopGroup還為每個新建立的Channel通道配置設定一個EventLoop。是以,在Channel的生命周期内,所有操作都由同一線程執行。
結論
通過Thread-Per-Request模型和Reactive并發模型的對比,涉及開發高效處理高并發請求的Web應用服務時,Spring Webflux是比較合适的選型。