springBoot3.2 + jdk21 + GraalVM上手体验

SpringBoot2.x官方已经停止维护了,jdk8这次真的得换了

  • 可以参考官方文章进行体验:https://spring.io/blog/2023/09/09/all-together-now-spring-boot-3-2-graalvm-native-images-java-21-and-virtual

  • 通过官方快速得到一个基于jdk21的项目:https://start.spring.io/

快速体验(二进制部署)

@RestController@SpringBootApplicationpublic class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}@GetMapping("/customers")Collection<Customer> customers() {return Set.of(new Customer(1, "A"), new Customer(2, "B"), new Customer(3, "C"));}record Customer(Integer id, String name) {}}

启动非常快,秒启动

压测环境内存占用大概70MB左右,空闲时在20MB左右(由于直接打成二进制文件了,不能再使用jconsole、arthas之类的进行监控了),性能上由于不需要JVM预热,性能启动即巅峰。

$ ab -c 50 -n 10000 http://localhost:8080/customersServer Software:Server Hostname:localhostServer Port:8080Document Path:/customersDocument Length:61 bytesConcurrency Level:50Time taken for tests: 1.413 secondsComplete requests:10000Failed requests:0Total transferred:1660000 bytesHTML transferred: 610000 bytesRequests per second:7076.39 [#/sec] (mean)Time per request: 7.066 [ms] (mean)Time per request: 0.141 [ms] (mean, across all concurrent requests)Transfer rate:1147.15 [Kbytes/sec] receivedConnection Times (ms)minmean[+/-sd] median maxConnect:02 8.02 144Processing: 15 6.74 147Waiting:04 5.63 145Total:1710.46 149

快速体验(jar部署)

jar包占用只有19MB,已经不能算是小胖jar了

内存占用在压测时大概在200MB左右,空闲时在160MB左右。性能显然也不是启动即巅峰,可以看出其实还是需要进行JVM预热才能达到性能巅峰的

$ ab -c 50 -n 10000 http://localhost:8080/customersServer Software:Server Hostname:localhostServer Port:8080Document Path:/customersDocument Length:61 bytesConcurrency Level:50Time taken for tests: 17.930 secondsComplete requests:10000Failed requests:0Total transferred:1660000 bytesHTML transferred: 610000 bytesRequests per second:557.72 [#/sec] (mean)Time per request: 89.651 [ms] (mean)Time per request: 1.793 [ms] (mean, across all concurrent requests)Transfer rate:90.41 [Kbytes/sec] receivedConnection Times (ms)minmean[+/-sd] median maxConnect:0 38 430.227004Processing: 0 1490.481773Waiting:0 1288.761771Total:1 53 439.0 107011

对比golang

package mainimport ("encoding/json""flag""fmt""net/http")var port = flag.String("p", "8080", "please input port")func main() {http.HandleFunc("/customers", func(writer http.ResponseWriter, request *http.Request) {data, _ := json.Marshal(request.URL)writer.Write(data)})e := make(chan error)go func() {e <- fmt.Errorf("error[%v]", http.ListenAndServe(":"+*port, nil))}()fmt.Println("http 服务器启动...")fmt.Println(<-e)}

这里golang没有使用框架,仅使用标准库,所以内存占用较低,仅10MB左右,不过即使使用Gin之类的web框架,内存也不会超过20MB

$ ab -c 50 -n 10000 http://localhost:8080/customersServer Software:Server Hostname:localhostServer Port:8080Document Path:/customersDocument Length:161 bytesConcurrency Level:50Time taken for tests: 1.380 secondsComplete requests:10000Failed requests:0Total transferred:2790000 bytesHTML transferred: 1610000 bytesRequests per second:7247.68 [#/sec] (mean)Time per request: 6.899 [ms] (mean)Time per request: 0.138 [ms] (mean, across all concurrent requests)Transfer rate:1974.71 [Kbytes/sec] receivedConnection Times (ms)minmean[+/-sd] median maxConnect:0216.52 459Processing: 0427.92 460Waiting:0210.52 459Total:1732.34 462

结论

AOT-processed已经相对成熟,效果可以说非常惊艳,解决了JVM启动慢、需要预热、内存占用大等问题。

美中不足的是编译速度非常慢,笔者电脑是2017款mac book pro编译花费大概15分钟左右

Finished generating 'demo' in 14m 33s.[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[INFO] Total time:15:45 min[INFO] Finished at: 2023-12-01T17:00:21+08:00[INFO] ------------------------------------------------------------------------

[INFO] Total time: 15:45 min
[INFO] Finished at: 2023-12-01T17:00:21+08:00
[INFO] ————————————————————————

可以看出java在云原生大环境下已经取得了不错的进步的