plugins {
java
application
id("com.github.johnrengelman.shadow") version "8.1.1"
}
repositories {
mavenCentral()
}
dependencies {
val vertxVersion = "5.0.0.CR2"
implementation("io.vertx:vertx-web:${vertxVersion}")
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
application {
mainClass = "io.vertx.howtos.openj9.Main"
}
使用 Eclipse OpenJ9 虚拟机运行 Vert.x 应用
本实战指南提供在 Eclipse OpenJ9 虚拟机上运行 Vert.x 应用程序的实用技巧与性能调优指南。OpenJ9 是基于 OpenJDK 构建的开源替代 JVM,其最大的特点在于对内存占用极为友好且冷启动敏捷。
Vert.x 本身是一个极致节约系统资源、专为构建现代分布式系统而生的响应式开发套件,而 OpenJ9 同样以极高资源利用率见长,两者结合非常契合虚拟化容器与云原生部署场景。
你将构建与运行什么
-
你将构建一个提供 HTTP JSON 接口、计算两数相加的微服务;
-
探索在 OpenJ9 上优化启动时间的调优选项;
-
在压力负载下测量并对比 OpenJ9 的实际物理内存常驻集大小(https://en.wikipedia.org/wiki/Resident_set_size[Resident Set Size, RSS]);
-
为该微服务与 OpenJ9 构建轻量 Docker 容器镜像;
-
讨论如何改善 Docker 容器冷启动耗时以及容器环境下的 OpenJ9 专属优化参数。
前置要求
-
文本编辑器或 IDE
-
Java 21 环境
-
OpenJ9 运行时
-
Maven 或 Gradle 构建工具
-
Docker
-
Locust 负载压测工具
|
Eclipse 基金会项目不允许分发或推广未通过 Oracle 授权 Java SE TCK 兼容性测试套件的 JDK 二进制。你可以自行源码编译 Eclipse OpenJ9,或者直接下载开箱即用的 IBM Semeru Runtime。 |
创建工程项目
本项目同时提供功能完全对等的 Maven 与 Gradle 构建配置。
使用 Gradle
这是你应该使用的 build.gradle.kts 文件内容:
build.gradle.kts使用 Maven
这是你应该使用的 pom.xml 文件内容:
pom.xml<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.vertx.howtos</groupId>
<artifactId>openj9-howto</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<vertx.version>5.0.0.CR2</vertx.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-stack-depchain</artifactId>
<version>${vertx.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>21</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>io.vertx.howtos.openj9.Main</Main-Class>
</manifestEntries>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
服务端实现
微服务的核心实现非常小巧,完整代码位于 io.vertx.howtos.openj9.Main:
package io.vertx.howtos.openj9;
import io.vertx.core.Future;
import io.vertx.core.VerticleBase;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
public class Main extends VerticleBase {
@Override
public Future<?> start() {
Router router = Router.router(vertx);
router.post().handler(BodyHandler.create());
router.post("/sum").handler(this::sum);
return vertx.createHttpServer()
.requestHandler(router)
.listen(8080);
}
private void sum(RoutingContext context) {
JsonObject input = context.body().asJsonObject();
Integer a = input.getInteger("a", 0);
Integer b = input.getInteger("b", 0);
JsonObject response = new JsonObject().put("sum", a + b);
context.response()
.putHeader("Content-Type", "application/json")
.end(response.encode());
}
public static void main(String[] args) {
long startTime = System.nanoTime();
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new Main()).await();
long duration = MILLISECONDS.convert(System.nanoTime() - startTime, NANOSECONDS);
System.out.println("Started in " + duration + "ms");
}
}
调优与压测
优化启动速度:开启共享类缓存 (SCC)
OpenJ9 最强大的特性之一是共享类缓存(Shared Class Cache, SCC) 与提前编译(AOT)。通过将解析后的类元数据与 JIT 编译产物持久化至共享缓存,后续启动可直接复用:
java -Xshareclasses:name=vertx_scc,cacheDir=/tmp -jar target/openj9-howto-1.0.0-SNAPSHOT-fat.jar
第二次及之后的启动速度将获得显著缩短,通常可减少 40%~60% 的冷启动开销。
物理内存常驻集 (RSS) 压测
启动压测脚本 locustfile.py 对服务端施加并发压力:
locust -f locustfile.py --headless -u 100 -r 10 -t 1m --host http://localhost:8080
在压测过程中监控进程实际物理内存:相比传统 HotSpot JVM,OpenJ9 的 RSS 表现尤为克制和平缓,能有效防止云原生容器因为 OOMKilled 被宿主机内核强行终结。
总结
本文档展示了:
-
Vert.x 与 Eclipse OpenJ9 虚拟机的协同优势;
-
利用共享类缓存(SCC)技术大幅加速冷启动;
-
测量高并发负载下的 RSS 内存占用并构建轻量化容器镜像。