配置項:java
# 設置IO線程數, 它主要執行非阻塞的任務,它們會負責多個鏈接, 默認設置每一個CPU核心一個線程 # 不要設置過大,若是過大,啓動項目會報錯:打開文件數過多 server.undertow.io-threads=16 # 阻塞任務線程池, 當執行相似servlet請求阻塞IO操做, undertow會從這個線程池中取得線程 # 它的值設置取決於系統線程執行任務的阻塞係數,默認值是IO線程數*8 server.undertow.worker-threads=256 # 如下的配置會影響buffer,這些buffer會用於服務器鏈接的IO操做,有點相似netty的池化內存管理 # 每塊buffer的空間大小,越小的空間被利用越充分,不要設置太大,以避免影響其餘應用,合適便可 server.undertow.buffer-size=1024 # 每一個區分配的buffer數量 , 因此pool的大小是buffer-size * buffers-per-region server.undertow.buffers-per-region=1024 # 是否分配的直接內存(NIO直接分配的堆外內存) server.undertow.direct-buffers=true
來看看源代碼:git
https://github.com/undertow-io/undertow/blob/master/core/src/main/java/io/undertow/Undertow.javagithub
ioThreads = Math.max(Runtime.getRuntime().availableProcessors(), 2); workerThreads = ioThreads * 8; //smaller than 64mb of ram we use 512b buffers if (maxMemory < 64 * 1024 * 1024) { //use 512b buffers directBuffers = false; bufferSize = 512; } else if (maxMemory < 128 * 1024 * 1024) { //use 1k buffers directBuffers = true; bufferSize = 1024; } else { //use 16k buffers for best performance //as 16k is generally the max amount of data that can be sent in a single write() call directBuffers = true; bufferSize = 1024 * 16 - 20; //the 20 is to allow some space for protocol headers, see UNDERTOW-1209 }
很顯然,Undertow認爲它的運用場景是在IO密集型的系統應用中,而且認爲多核機器是一個比較容易知足的點,Undertow初始化假想應用的阻塞係數在0.8~0.9之間,因此阻塞線程數直接乘了個8,固然,若是對應用較精確的估測阻塞係數,能夠配置上去。web
Spring Boot內嵌容器支持Tomcat、Jetty、Undertow。爲何選擇Undertow?spring
這裏有一篇文章,時間 2017年1月26日發佈的:
Tomcat vs. Jetty vs. Undertow: Comparison of Spring Boot Embedded Servlet Containersapache
We will use Maven to setup a new project in Eclipse with the appropriate dependencies. We will use the starter parent for this example but the dependencies in a production application will likely be altered to streamline, optimize or customize.json
The default embedded servlet container is Tomcat. This version of Spring Web 1.4.3 brings in Tomcat version 8.5.6.tomcat
pom.xml服務器
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.3.RELEASE</version> </parent> <dependencies> <!-- TOMCAT --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
To setup the Spring Boot application you include the @SpringBootApplication
annotation in your Main class. The @SpringBootApplication
annotation brings in @SpringBootConfiguration
, @EnableAutoConfiguration
and @ComponentScan
annotations.websocket
Application.java
@SpringBootApplication @ConfigurationProperties public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }
You may choose to eliminate this annotation and add the @SpringBootConfiguration
alone or to another class that allows you to customize the configuration. The @ComponentScan
will scan your application for items like the @Controller
you will need to setup a RESTful service. The following controller will return a simple 「Hello World」 string from a HTTP GET request. We have also included in the bundled example another endpoint mapping that returns a complex object type.
SampleController.java
@Controller public class SampleController { @Autowired private ResourceLoader resourceLoader; @RequestMapping("/") @ResponseBody public String home() { return "Hello World!"; }
The default properties for all the embedded servlet containers are the same. Some of the most important properties to consider are the properties for configuring startup information like ports and application name, TSL, access logs, compression and many more.
For example, to configure SSL add the following to key value pairs to the application.properties.
application.properties
server.port=8443 server.ssl.key-store=classpath:keystore.jks server.ssl.key-store-password=secret server.ssl.key-password=another-secret
To explore the parameters for Spring boot applications you can add the Spring actuator dependency and the @ConfigurationProperties
annotation to your Main class. You then visit the /configprops
endpoint on your application to get a list of the available properties.
Application.java
@SpringBootApplication @ConfigurationProperties public class Application {
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
The embedded servlet container versions are defined in the following parent dependency from the pom. You can change the version of the embedded servlet container by explicitly including the dependency and identifying a new version in the pom. We will show you how in the examples below.
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.3.7.RELEASE</version> </dependency>
As Tomcat is the default embedded servlet container there is nothing you need to do to the default implementation to use Tomcat. You can change the version of Tomcat you are using or change properties in the pom.xml
or application.properties
files.
pom.xml
<properties> <tomcat.version>8.5.6</tomcat.version></properties> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-el</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-websocket</artifactId> <version>${tomcat.version}</version> </dependency>
To change the embedded servlet container to Jetty you need to edit the pom file to remove the Tomcat dependency and add Jetty.
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
To change the embedded servlet container to Undertow you need to edit the pom file to remove the Tomcat dependency and add Undertow.
Notice the undertow version included in the spring boot starter is incorrect, referring to 1.3.25. You’ll need to change it to 1.3.24.Final for this to work at the time of this article.
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency> <dependency> <groupId>io.undertow</groupId> <artifactId>undertow-core</artifactId> <version>1.3.24.Final</version> </dependency> <dependency> <groupId>io.undertow</groupId> <artifactId>undertow-servlet</artifactId> <version>1.3.24.Final</version> </dependency>
In this example, we will analyze both the peformance of HTTP requests and the memory footprint at startup of all three embedded servlet containers. We used JMeter to measure performance by simulating load and JVisualVM to look at the memory footprint.
In this example, we will analyze both the peformance of simple RESTFul GET requests that return a string and more complex GET requests that return complex JSON objects. JMeter is the tool used to measure the performance of the the three different types of containers. The key to setting up this test was establishing thread groups with the appropriate load, a counter to dynamically update the input to the API and report viewers to display or aggregate the results. For the simple string examples, we used a thread group with 1000 threads that would loop 3 times through the sequence. It also used a ramp up time of 10 seconds. For the complex object examples, we used the same parameters but did not loop.
Label | # Samples | Average | Min | Max | Std. Dev. | Error % | Throughput | Received KB/sec | Sent KB/sec | Avg. Bytes |
---|---|---|---|---|---|---|---|---|---|---|
Startup | 3000 | 7 | 1 | 549 | 35.78374361 | 0 | 293.8583603 | 55.95935572 | 55.67238466 | 195 |
Others | 3000 | 1 | 0 | 45 | 1.359661682 | 0 | 287.8802418 | 54.82094449 | 54.53981144 | 195 |
Others | 3000 | 1 | 0 | 24 | 1.155032275 | 0 | 292.1129503 | 55.62697785 | 55.3417113 | 195 |
Label | # Samples | Average | Min | Max | Std. Dev. | Error % | Throughput | Received KB/sec | Sent KB/sec | Avg. Bytes |
---|---|---|---|---|---|---|---|---|---|---|
Startup | 1000 | 114 | 3 | 1601 | 322.8671905 | 0 | 97.68486861 | 202.3335999 | 19.93763432 | 2121 |
Others | 1000 | 3 | 2 | 17 | 1.328216473 | 0 | 97.88566954 | 202.7495167 | 19.9786181 | 2121 |
Others | 1000 | 2 | 1 | 16 | 1.110529603 | 0 | 98.52216749 | 204.0678879 | 20.10852833 | 2121 |
Others | 1000 | 2 | 1 | 21 | 1.344498419 | 0 | 98.53187506 | 204.0879951 | 20.11050966 | 2121 |
Label | # Samples | Average | Min | Max | Std. Dev. | Error % | Throughput | Received KB/sec | Sent KB/sec | Avg. Bytes |
---|---|---|---|---|---|---|---|---|---|---|
Startup | 3000 | 7 | 0 | 561 | 40.13705065 | 0 | 291.5168594 | 56.0828333 | 55.22878 | 197 |
Others | 3000 | 1 | 0 | 21 | 1.058925031 | 0 | 293.5995302 | 56.48350338 | 55.6233485 | 197 |
Others | 3000 | 1 | 0 | 21 | 0.926034317 | 0 | 294.3485086 | 56.62759395 | 55.7652448 | 197 |
Label | # Samples | Average | Min | Max | Std. Dev. | Error % | Throughput | Received KB/sec | Sent KB/sec | Avg. Bytes |
---|---|---|---|---|---|---|---|---|---|---|
Startup | 1000 | 110 | 3 | 1397 | 278.7961107 | 0 | 98.13542689 | 203.3626717 | 19.93375859 | 2122 |
Others | 1000 | 3 | 2 | 20 | 1.500210319 | 0 | 98.48335631 | 204.0836739 | 20.00443175 | 2122 |
Others | 1000 | 3 | 2 | 45 | 2.729377218 | 0 | 98.29942003 | 203.7025091 | 19.96706969 | 2122 |
Label | # Samples | Average | Min | Max | Std. Dev. | Error % | Throughput | Received KB/sec | Sent KB/sec | Avg. Bytes |
---|---|---|---|---|---|---|---|---|---|---|
Startup | 3000 | 6 | 0 | 451 | 31.6188702 | 0 | 295.6830278 | 63.81440346 | 56.01807363 | 221 |
Others | 3000 | 1 | 0 | 22 | 1.255447862 | 0 | 292.7400468 | 63.17924839 | 55.46051669 | 221 |
Others | 3000 | 1 | 0 | 18 | 1.559477975 | 0 | 294.3773918 | 63.53262069 | 55.77071681 | 221 |
Label | # Samples | Average | Min | Max | Std. Dev. | Error % | Throughput | Received KB/sec | Sent KB/sec | Avg. Bytes |
---|---|---|---|---|---|---|---|---|---|---|
Startup | 1000 | 70 | 3 | 1114 | 197.1333241 | 0 | 97.059109 | 203.3969361 | 19.62044201 | 2145.893 |
Startup | 1000 | 42 | 3 | 852 | 132.6443576 | 0 | 98.02960494 | 205.6324135 | 20.00799554 | 2148 |
Others | 1000 | 3 | 2 | 19 | 1.293570253 | 0 | 98.55129595 | 206.6305004 | 20.01823199 | 2147 |
Others | 1000 | 2 | 2 | 27 | 1.659250132 | 0 | 98.74592673 | 207.0385788 | 20.05776637 | 2147 |
Others | 1000 | 2 | 1 | 17 | 1.260904041 | 0 | 98.28975821 | 206.0821395 | 19.96510714 | 2147 |
To measure the memory of each embedded servlet container we looked at the memory usage on startup. JVisualVM is a tool provided with the Java Development Kit for visualizing the memory and footprint of java applications. We used this tool to show the initial startup impact of each of the three embedded servlet containers. The heap size and thread counts are key in analyzing this initial footprint. The ten threads that are common to all three containers include: JMX server connection timeout, RMI Scheduler, RMI TCP Connection (2), RMI TCP Accept, Attach Listener, DestroyJavaVM, Signal Dispatcher, Finalizer and Reference Handler.
Heap Size: 697,827,328 B
Used: 124,260,976 B
Max: 2,147,483,648 B
Threads: 17 Live, 22 Started
Heap Size: 628,621,312 B
Used: 311,476,776 B
Max: 2,147,483,648 B
Threads: 19 Live, 22 Started
Heap Size: 630,718,464 B
Used: 114,599,536 B
Max: 2,147,483,648 B
Threads: 17 Live, 20 Started
壓測結果:從上面的6張壓力測試報告中,能夠看到3個容器在相同的用例及併發請求下,Undertow稍微比Tomcat和Jetty好一點。
資源消耗:JETY啓動時內存佔用最大,使用311 MB。Tomcat和Undertow的初始腳印類似,在120 MB左右,Undertow出如今114 MB的最低水平。響應頭中的關鍵差別在於默認狀況下默認狀況下包括HTTP持久鏈接。該頭將在支持持久鏈接的客戶端中使用,以經過重用鏈接細節來優化性能。
Content-Type →application/json;charset=UTF-8
Date →Mon, 09 Jan 2017 02:23:26 GMT
Transfer-Encoding →chunked
X-Application-Context →JcgSpringBootContainers:# Application index.
Content-Type →application/json;charset=UTF-8
Date →Mon, 09 Jan 2017 02:29:21 GMT
Transfer-Encoding →chunked
X-Application-Context →JcgSpringBootContainers:# Application index.
Connection →keep-alive
Content-Type →application/json;charset=UTF-8
Date →Mon, 09 Jan 2017 02:20:25 GMT
Transfer-Encoding →chunked
X-Application-Context →JcgSpringBootContainers:# Application index.
這些數字代表Undertow在性能和內存使用方面是最好的。使人鼓舞的是,Undertow 正在接受最新的能力,並默認爲持久的鏈接。這些數字並不表示在這個例子中使用的負載有顯著的性能差別,但我想它們會縮放,若是性能是最重要的因素,則Undertow 是應用程序的正確匹配。認爲一個組織可能由於熟悉它的能力而喜歡嵌入的servlet容器也是合理的。不少時候默認設置將不得不改變,由於應用程序要求包括性能、內存使用和功能。
=========================分割線=================================================================================
一、Maven示例:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency>
二、配置Undertow,application.yml示例:
server.undertow.accesslog.dir= # Undertow access log directory.
server.undertow.accesslog.enabled=false # Enable access log.
server.undertow.accesslog.pattern=common # Format pattern for access logs.
server.undertow.accesslog.prefix=access_log. # Log file name prefix.
server.undertow.accesslog.rotate=true # Enable access log rotation.
server.undertow.accesslog.suffix=log # Log file name suffix.
server.undertow.buffer-size= # Size of each buffer in bytes.
server.undertow.buffers-per-region= # Number of buffer per region.
server.undertow.direct-buffers= # Allocate buffers outside the Java heap.
server.undertow.io-threads= # Number of I/O threads to create for the worker.
server.undertow.max-http-post-size=0 # Maximum size in bytes of the HTTP post content.
server.undertow.worker-threads= # Number of worker threads.
三、使用 Undertow 監聽多個端口示例:
@Bean public UndertowEmbeddedServletContainerFactory embeddedServletContainerFactory() { UndertowEmbeddedServletContainerFactory factory = new UndertowEmbeddedServletContainerFactory(); factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { @Override public void customize(Builder builder) { builder.addHttpListener(8080, "0.0.0.0"); } }); return factory; }