运行时与 JVM 优化

使用 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 文件内容:

使用 Maven

这是你应该使用的 pom.xml 文件内容:

服务端实现

微服务的核心实现非常小巧,完整代码位于 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 内存占用并构建轻量化容器镜像。