Helidon — 让 Java 微服务用同步代码写出反应式性能
待复核Helidon 是 Oracle 出的 Java 微服务框架,对标 Spring Boot 但走完全不同的路线。它的招牌功能叫 Helidon Nima:第一个用 Java 21 虚拟线程从零写的 web server——不是给老 server 打虚拟线程补丁,而是整个内核重写。
日常类比:以前 Java 高并发就像「每个客户都派一个全职服务员」(OS 线程),人多就吃不消;后来反应式编程让「服务员一边端盘一边记下每个客户位置」(异步回调),人多顶得住但服务员快疯了;虚拟线程是「让酒店随时变出 100 万个临时服务员,每个客户分一个」——酒店(JVM)背后只用几个 OS 线程轮流跑这些临时工。
// Helidon Nima 写一个 GET /helloWebServer.builder() .routing(r -> r.get("/hello", (req, res) -> res.send("hi"))) .build() .start();代码就是普通同步阻塞写法,但能扛住几万并发——因为 server 给每个请求开一根虚拟线程,阻塞 I/O 不占 OS 线程。
- 以前 Java 选型只有两条难走的路:Spring Boot 简单但反应式吃力,Netty/反应式 性能好但代码像天书。Helidon Nima 给了第三条
- 它是 MicroProfile 规范的官方实现之一——/health、/metrics、/openapi、配置注入这些都开箱即用,不用拼一堆 starter
- Oracle 维护;Helidon 4 锚定 JDK 21 虚拟线程,随后版本号改为对齐 OpenJDK 发版节奏,跟虚拟线程演进走在最前面
- 是观察”虚拟线程到底有没有用”的最直接窗口——它整个内核就是为虚拟线程重写的
- 学一个 Helidon 等于看清”JVM 里同步代码 + 高并发”这条新路线长什么样
记 3 件事:
- Nima WebServer = 虚拟线程内核:HTTP 解析 + IO 调度全用虚拟线程实现,不依赖 netty。每个连接、每个请求各一根虚拟线程。
- Helidon SE vs MP 两套 API:SE 是裸 server(更轻、自己接管路由);MP 是 MicroProfile(CDI 注解 + JAX-RS,像轻量版 Spring)。同一份 server 内核,两种写法。
- 同步代码 + 异步性能:开发体验和 fastapi / gin / axum 这种”同步外表”接近,但 JVM 线程模型完全不同——它靠的是 JDK 自己的 carrier thread 调度,不是 async runtime。
案例 1:30 秒起一个 REST 端点(Helidon SE)
Section titled “案例 1:30 秒起一个 REST 端点(Helidon SE)”public static void main(String[] args) { WebServer.builder() .routing(routing -> routing .get("/greet/{name}", (req, res) -> { String name = req.path().pathParameters().value("name"); res.send("Hello, " + name); })) .port(8080) .build() .start();}逐部分解释:
WebServer.builder()起的是 Nima 内核,不是 Tomcat/Netty 外壳。/greet/{name}里每次请求一根虚拟线程;pathParameters()取路径参数后send回写响应。- 没有 Spring 那一堆
@Annotation,纯 Java 调用就能跑起一个能扛高并发的 HTTP server。
案例 2:高并发下游调用——同步代码顶住 1 万 QPS
Section titled “案例 2:高并发下游调用——同步代码顶住 1 万 QPS”res -> { // 同步 HTTP 调下游,看似每个请求会"卡住" String data = httpClient.get("http://downstream/api").body(); res.send(data);}逐部分解释:
httpClient.get(...).body()是同步阻塞:当前虚拟线程在等下游,但 carrier(OS 线程)可以去跑别的虚拟线程。- 传统 Tomcat(约 200 OS 线程池)遇到 1 万并发会把池打满;Nima 可以同时挂大量虚拟线程等 I/O。
- 所以代码看起来像「卡住」,实际卡的是廉价虚拟线程,不是稀缺的 OS 线程。
案例 3:MicroProfile 健康检查(Helidon MP)
Section titled “案例 3:MicroProfile 健康检查(Helidon MP)”@ApplicationScoped@Livenesspublic class CustomCheck implements HealthCheck { public HealthCheckResponse call() { return HealthCheckResponse.up("custom"); }}逐部分解释:
@Liveness声明这是存活探针;CDI 扫描到后挂到/health/live。HealthCheckResponse.up(...)返回「健康」;失败时返回 down,K8s 就会重启 Pod。- 这是 MicroProfile 规范带来的开箱能力:换 Open Liberty 等实现,注解语义仍通。
案例 4:读配置(默认快照,热更新要另开)
Section titled “案例 4:读配置(默认快照,热更新要另开)”Config config = Config.create();String url = config.get("downstream.url").asString().orElse("http://default");逐部分解释:
Config.create()通常读到的是启动时快照;改application.yaml不会自动进已取出的url变量。- 若要热更新,需用可观察/轮询的 Config source,或 MP 的
@ConfigProperty搭配支持刷新的源。 - 写法像 Spring
@Value,底层走 MicroProfile Config;别把「能读配置」误当成「默认热加载」。
- JDK 版本硬约束:Helidon 4 必须 JDK 21+;版本号对齐 OpenJDK 节奏后,Helidon 27 需要 JDK 26。公司还在 JDK 8/11 就得先升 JDK,不能指望旧 LTS 直接跑新内核。
- 3.x → 4.x API 大改:老 Helidon SE 代码(Reactive Server / WebServer 旧 API)几乎要重写。不是平滑升级,是迁移。
- 虚拟线程不是银弹:业务里有
synchronized长持锁、ThreadLocal 误用,会把虚拟线程钉死在 carrier thread 上——并发优势瞬间消失。要换ReentrantLock或者用 ScopedValue。 - 生态比 Spring Boot 小一个数量级:第三方 starter / Stack Overflow 答案 / 中文资料都少很多。选型前要确认”我用的库有 Helidon 集成吗”。
- 冷启动不是 Helidon 强项:JVM 起步比 Quarkus Native 慢得多。Serverless 短任务、按请求计费场景要慎选——还是 Quarkus + GraalVM 更合适。
适用 vs 不适用场景
Section titled “适用 vs 不适用场景”适用:
- 新项目、JDK 21+ 起步、想要高并发同步写法
- 已经在用 MicroProfile 规范(不想全套换 Spring)
- 微服务网关、IO 密集型 BFF、调用链多但每步都阻塞 IO 的场景
不适用:
- 老项目(JDK 8/11,没法升)→ 用 spring-boot 稳
- CPU 密集型计算服务(虚拟线程帮不上忙)→ 选什么框架差别不大
- 团队不熟 Java 生态、想要 Native Image 启动快 → quarkus 更合适
- 全栈一体(不只 backend,要前后端协同)→ 还是 Spring Boot 生态广
| 框架 | 内核 | 主打 | JDK 要求 |
|---|---|---|---|
| Helidon Nima | 自研虚拟线程 | 同步代码 + 高并发 | 21+ |
| spring-boot | Tomcat / Netty | 生态最广 | 17+(多数) |
| quarkus | Vert.x / Netty | Native Image 启动快 | 17+ |
| micronaut | Netty + AOT | 编译期 DI、低内存 | 17+ |
四家在”JDK 21 虚拟线程支持”上都跟进了,但 Helidon Nima 是唯一从零按虚拟线程设计内核的——其它三家是给老内核打补丁。
怎么选:
- 团队全在 Spring 生态、生态优先 → Spring Boot
- 想 Native Image / Serverless 冷启动 → Quarkus
- 编译期 DI、内存敏感(IoT、Lambda)→ Micronaut
- 高并发 IO 同步写法、JDK 21 起步、不要 Native → Helidon Nima
历史小故事(可跳过)
Section titled “历史小故事(可跳过)”- 2018-2019:Oracle 内部要给 Java EE → Jakarta EE 的微服务方向找新框架,启动 Project Helidon
- 2019 年 9 月:Helidon 1.0 发布,分 SE(响应式)和 MP(MicroProfile)两套 API,底层 Netty
- 2022-2023:JDK 19/21 推出虚拟线程预览/正式版,Oracle 决定为虚拟线程重写 web server
- 2023 年:Helidon 4 发布,Nima WebServer 砍掉 Netty,HTTP 全部跑在虚拟线程上——Java 微服务”同步写法 + 高并发”路线第一次有正式答案
- 运行时模型可以重写:Nima 砍掉 Netty 重做底层证明 JVM 上同步语义和高并发不再矛盾——前提是有虚拟线程
- 规范 + 实现要分清:MicroProfile 是规范,Helidon 是实现之一(还有 Open Liberty、Payara)。换框架不等于改业务代码
- API 跨大版本不能怕断:3 → 4 的 API 重写让 Oracle 敢用 Nima 重做内核,老用户痛但路径走对了
- 看代码风格选语言:同样是”同步外表”,Helidon 跟 fastapi / gin / axum / actix-web 是同一类设计哲学,只是 JVM 用虚拟线程实现,其它语言用 async runtime
- 银弹之外要看真实瓶颈:虚拟线程解决 IO 阻塞场景,CPU 密集型/锁竞争重的业务该慢还是慢——选型要看真实负载形态
- 官方文档(Nima 章节最值得看):helidon.io/docs
- JEP 444 虚拟线程正式版:openjdk.org/jeps/444
- 对照阅读:quarkus / micronaut / spring-boot —— 同生态四种取舍
- spring-boot —— 同语言生态,Helidon 是 Spring 之外的轻量选项
- quarkus —— 同样是 MicroProfile 实现,主打 Native Image
- micronaut —— 同生态轻量框架,主打编译期 DI
- fastapi —— Python 里”同步写法 + 高并发”的同思路代表
- axum —— Rust 里同思路(用 async runtime 而非虚拟线程)
- gin —— Go 里”goroutine = 虚拟线程”思想的最早工业落地
- actix-web —— Rust 里另一种异步选型,对照看 JVM/Rust 思路差异
- dropwizard —— Dropwizard — Java 微服务的”开箱即用 12-factor 起步包”