吊打 Tomcat ,Undertow 效能很炸!!

Java技術棧發表於2020-08-24

在 Java Web 容器的世界裡,Tomcat 和 Jetty 是大名鼎鼎的、用的最多的開源專案,也是大眾熟知的。

今天再介紹另外一款能和 Tomcat 媲美的神器:Undertow,據說效能方面還要吊打 Tomcat,如果你還不知道它,那你就 OUT 了。

我們來看下 Spring Boot 預設支援的三種 Servlet 容器:

Name Servlet Version
Tomcat 9.0 4.0
Jetty 9.4 3.1
Undertow 2.0 4.0

以上來源於 Spring Boot 2.3.2 官方文件,更多資訊請點選這裡參考這篇文章。

Undertow 它能成為 Spring Boot 預設整合的三大容器之一,就憑這點,我想就足以說明它的地位。

Undertow 什麼鬼?

Undertow 是 RedHat(紅帽公司)的開源產品,採用 Java 開發,是一款靈活、高效能的 Web 伺服器,提供了基於 NIO 的阻塞/非阻塞 APIs,也是 Wildfly 的預設 Web 容器。

搜尋 Undertow:

頁面顯示的是 JBoss Community,因為 2006 年 RedHat 收購了 JBoss,那也就不足為怪了。

Undertow 它是一個基於組合的體系結構,可以通過組合一系列小型處理器來構建一個 Web 伺服器。這就讓我們可以靈活的在 Java EE servlet 4.0 容器和底層非阻塞處理器或者其他更多之間進行選擇。

Undertow 被設計成完全可嵌入式的,所以也叫嵌入式容器,具有易於使用的流暢構建 API,另外,Undertow 的生命週期也完全由所嵌入的應用程式所控制。

這也是為什麼 Spring Boot 可以直接嵌入 Undertow 的原因,Undertow 它就是為了嵌入而發燒的。Spring Boot 基礎知識就不介紹了,關注公眾號Java技術棧在後臺回覆boot獲取我寫的系列教程。

官方網站:

https://undertow.io/

原始碼託管在 Github:

https://github.com/undertow-io/undertow

Undertow 有啥特性?

1)HTTP/2 Support

Undertow 支援 HTTP/2 開箱即用,不需要重寫引導類路徑。

2)支援 HTTP 升級

支援 HTTP 升級,允許多個協議通過 HTTP 埠上進行復用。

3)支援 Web Socket

Undertow 提供對 Web 套接字的全面支援,包括對 JSR-356 的支援。

4)支援 Servlet 4.0

Undertow 提供了對 Servlet 4.0 的支援,包括對嵌入式 Servlet 的支援,還可以混合部署 Servlet 和原生 Undertow 非阻塞處理程式。

5)可嵌入式

Undertow 可以嵌入到應用程式中,也可以通過幾行程式碼獨立執行。

6)高靈活性

一個 Undertow 伺服器是通過鏈式處理器來配置的,可以根據需要新增功能,因此可以避免新增沒有必要的功能。

Undertow 效能如何?

國外有篇帖子做了 Tomcat vs. Jetty vs. Undertow 三者的效能比較:

https://examples.javacodegeeks.com/enterprise-java/spring/tomcat-vs-jetty-vs-undertow-comparison-of-spring-boot-embedded-servlet-containers/

從測試結果看,這三個 Servlet 容器都具有不錯的效能,但 Undertow 效能更好,Tomcat 和 Jetty 緊隨其後。

Jetty 在啟動時的記憶體佔用最大,為:311 MB, Tomcat 和 Undertow 的初始記憶體佔用都很低,大約為:120 MB,而 Undertow 的初始記憶體佔用最低,為:114 MB。

最後,關鍵的區別在於,Undertow 響應頭引數預設包含 HTTP 持久連線資訊,這個頭引數在支援持久連線的客戶端時,可以通過重用連線來優化效能。

Show me the code

Undertow 目前有兩個主要版本:

  • 2.1:當前支援 Servlet 4.0, JDK8+ 的穩定版本;
  • 1.4:當前支援 Servlet 3.1, JDK7 的穩定版本;

獨立使用 Undertow 需要新增以下依賴:

<dependency>
    <groupId>io.undertow</groupId>
    <artifactId>undertow-core</artifactId>
    <version>2.1.0.Final</version>
</dependency>

<dependency>
    <groupId>io.undertow</groupId>
    <artifactId>undertow-servlet</artifactId>
    <version>2.1.0.Final</version>
</dependency>

<dependency>
    <groupId>io.undertow</groupId>
    <artifactId>undertow-websockets-jsr</artifactId>
    <version>2.1.0.Final</version>
</dependency>

以下示例來源官網:

public class HelloWorldServer {

    public static void main(final String[] args) {
        Undertow server = Undertow.builder()
                .addHttpListener(8080, "localhost")
                .setHandler(new HttpHandler() {
                    @Override
                    public void handleRequest(final HttpServerExchange exchange) throws Exception {
                        exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
                        exchange.getResponseSender().send("Hello World");
                    }
                }).build();
            server.start();
    }
}

這是一個使用了異常 IO 的簡單 Hello World 示例。

Spring Boot & Undertow

上面講到,Undertow 是為嵌入式而生的 Web 容器,又是 Spring Boot 預設整合的容器之一,下面棧長帶大家來看下如何在 Spring Boot 中使用 Undertow。

因為在 spring-boot-starter-web 啟動器中,Tomcat 是 Spring Boot 預設的嵌入式容器,即:spring-boot-starter-tomcat

Spring Boot 還提供了其他兩個啟動器以方便進行代替:

  • spring-boot-starter-jetty
  • spring-boot-starter-undertow

下面來簡單實戰下,如何在 Spring Boot 中使用 Undertow。Spring Boot 基礎知識就不介紹了,不熟悉的可以關注公眾號Java技術棧在後臺回覆boot獲取我寫的系列教程。

排除 Tomcat 依賴,然後加入 Undertow 依賴:

<dependencies>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <!-- Exclude the Tomcat dependency -->
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!-- Use Undertow instead -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-undertow</artifactId>
    </dependency>

</dependencies>

一步就完成整合了,當然實際情況還需要在 application 配置檔案中加入 Undertow 的更多自定義或者優化配置引數。

Undertow容器的具體配置可以看這兩個類:

  • org.springframework.boot.autoconfigure.web.ServerProperties
  • org.springframework.boot.autoconfigure.web.ServerProperties.Undertow

也可以看 Spring Boot 官方文件:

https://docs.spring.io/spring-boot/docs/2.3.2.RELEASE/reference/htmlsingle/#server-properties

上面有所有 Server 配置引數和說明。

再寫一個測試方法測試下:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 微信公眾號:Java技術棧
 */
@RestController
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }

    @GetMapping(value = "/undertow/test")
    public String undertow() {
        return "hello undertow";
    }

}

啟動 Application:

如上所示,可以看到 Undertow 的啟動日誌。

訪問測試方法:

http://localhost:8080/undertow/test

輸出成功,測試完成。

總結

本文對 Undertow 作了一個介紹和整合實戰,雖然 Undertow 效能很炸,但你可以去網上找一圈,根本沒啥學習資料。

所以,對於學習和一般應用來說,Tomcat 足矣,一方面 Tomcat 學習資料多,另一方面 Tomcat 用的更廣泛,很多坑別人幫你踩了,很多漏洞也已經暴露出來了。

那於那些一定要追求極致效能的又不想優化 Tomcat 的,可以考慮使用 Undertow,但同時你要有能力 Hold 住它,需要一定的積累經驗,不然出一個問題你線上卡半天顯然是不願意看到的。

最後,網上很多文章說幹掉 Tomcat 而要使用 Undertow 的,這就有點誇張,我只能呵呵了,持有保留意見,用啥都行,關鍵能不能用好。

推薦去我的部落格閱讀更多:

1.Java JVM、集合、多執行緒、新特性系列教程

2.Spring MVC、Spring Boot、Spring Cloud 系列教程

3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程

4.Java、後端、架構、阿里巴巴等大廠最新面試題

覺得不錯,別忘了點贊+轉發哦!

相關文章