Java 处理业务复杂度,Rust 承担运行时关键性。不同的微服务可以拥有不同的领域模型,但工程团队仍然可以拥有一致的开发体验。
Rust 的优点已经不需要反复证明。
内存安全、零成本抽象、可预测的运行时表现、优秀的工具链,以及对并发错误更强的编译期约束,使它非常适合构建基础设施、高性能网络服务和可靠性要求较高的软件。Rust 也长期保持着很高的开发者认可度。
但如果把视线从开源项目和基础设施软件转向金融、支付、供应链、制造、保险等大型商业系统,就会看到另一个现实:
Rust 的实际覆盖面仍然远小于 Java。
这并不意味着 Rust 不适合企业软件,也不意味着企业技术负责人没有看到 Rust 的优势。更重要的原因是,大型商业系统选择技术时,考虑的从来不只是语言本身。
他们还需要考虑:
- 已经运行多年的 Java 系统;
- Spring、数据库、消息队列、工作流和第三方 SDK 生态;
- 数十人甚至数百人的现有工程团队;
- 招聘、培训、运维和故障排查体系;
- 监管、审计和长期维护要求;
- 无数已经被生产事故验证过的异常路径。
因此,我逐渐形成了一个判断:
Rust 进入大型商业软件的最好方式,可能不是替代 Java,而是进入 Java 已经建立起来的生态。
不是要求企业先建立一个完整的 Rust 世界,而是在现有系统中找到真正适合 Rust 的边界,让它逐步成为系统中不可替代的一部分。
一、Rust 面对的主要障碍,不一定是技术能力
讨论 Rust 的企业落地时,我们经常从语言优点开始:
- Rust 没有 GC;
- 内存占用更低;
- 性能更可预测;
- 编译器可以发现更多错误;
- 容器镜像可以更小;
- 启动速度更快。
这些都很重要,但它们并不能自动转化为企业采用。
大型商业系统的真实决策公式更接近:
技术收益
- 迁移成本
- 人才成本
- 生态缺口
- 组织认知成本
- 生产风险
= 是否值得采用
一项技术即使在局部指标上更优秀,只要进入成本过高,企业仍然会选择继续优化现有系统。
Java 的优势也不仅仅是“历史悠久”。它已经形成了一整套企业级生产能力:
- Spring Boot 与 Spring Cloud;
- 成熟的 ORM、事务、消息和缓存生态;
- 数据库、支付、身份认证和企业中间件 SDK;
- 大规模团队协作经验;
- 监控、诊断、性能分析和运维体系;
- 大量理解 Java 的架构师、工程师和服务商。
所以,对 Rust 社区而言,真正值得回答的问题不是:
Rust 是否比 Java 更先进?
而是:
如何让企业在不放弃现有 Java 资产的情况下,低风险地获得 Rust 的价值?
二、最困难的路线:先说服企业重写
一种常见的技术叙事是:
现有 Java 系统
↓
发现性能或可靠性问题
↓
用 Rust 重写核心系统
↓
获得更高性能和更低资源占用
这条路线在少数边界清晰的基础设施组件上可能成立,但对大型商业系统往往并不现实。
一个运行多年的支付或金融系统,其价值不仅存在于设计文档中,还存在于大量看似不优雅的代码里:
- 某个银行接口偶发返回的特殊状态;
- 某个国家节假日造成的清算例外;
- 某类商户需要额外的合规审核;
- 某个历史版本遗留下来的兼容逻辑;
- 某次事故后增加的保护分支;
- 某项监管要求形成的审计流程。
这些知识很难通过一次重写完整迁移。
重写还会带来新的风险:
- 原有异常场景是否被完整覆盖?
- 新旧系统并行期间如何对账?
- Rust 团队是否理解全部业务语义?
- 原有运维工具能否继续使用?
- 出现事故时,组织是否有足够的人能够排查?
因此,Rust 的企业落地不应该建立在“推倒重来”之上。
企业真正需要的不是一次语言革命,而是一条可以逐步验证的采用路径。
三、更现实的入口:从微服务边界进入
微服务提供了一个非常现实的机会。
只要服务边界足够清晰,企业就不必为整个系统选择唯一语言。不同微服务可以根据自己的工作负载、变化速度和运行时要求选择不同技术。
以一个支付平台为例,它可能同时包含两类性质差异很大的服务。
1. 业务与集成复杂度较高的服务
例如:
Java Services
├── Merchant Onboarding
├── KYC / KYB
├── Compliance Workflow
├── Account Maintenance
├── Document Processing
├── Partner Integration
├── Reconciliation Investigation
└── Operations & Administration
这类服务的主要难点通常是:
- 流程长;
- 状态多;
- 外部集成多;
- 异常分支复杂;
- 业务变化频繁;
- 需要运营人员介入;
- 需要大量企业级组件。
Java 的成熟生态在这里非常有价值。
我们可以把这一类复杂度称为:
Business Complexity:业务复杂度。
2. 运行时关键性较高的服务
例如:
Rust Services
├── Client-facing Payment API
├── Payment Execution
├── Payment Routing
├── Real-time Pricing
├── Transaction Validation
├── Idempotency Control
├── Gateway Callback Processing
└── High-volume Event Processing
这类服务往往具有不同特征:
- 面向最终用户;
- 请求量大或者流量波动明显;
- 延迟直接影响支付体验;
- 需要快速横向扩容;
- 对单实例内存和部署密度敏感;
- 服务边界相对清晰;
- 关注 P99、P99.9 等尾延迟指标。
我们可以把这一类问题称为:
Runtime Criticality:运行时关键性。
这不是按照“重要”和“不重要”来划分系统。
商户入驻和 KYC 并不比支付执行不重要;合规流程甚至可能决定企业能否继续经营。两者只是面对不同类型的复杂度。
因此,更准确的表达是:
Java 吸收业务与集成复杂度,Rust 承担运行时关键性。
四、Rust 的价值不应被简化为“比 Java 快”
在这种架构中使用 Rust,不能只依赖一句“Rust 性能更好”。
现代 JVM 已经非常成熟。经过良好设计和调优的 Java 服务,同样可以获得优秀的吞吐和延迟表现。许多所谓的性能问题,真正的瓶颈也可能位于:
- 数据库;
- 网络调用;
- 锁竞争;
- 消息系统;
- 不合理的数据模型;
- 过多的服务跳转;
- 缺乏缓存;
- 错误的容量规划。
把这些问题简单归因于 GC,通常是不严谨的。
Rust 更适合作为候选方案的情况是:
- 服务边界已经比较稳定;
- 运行时成本确实是主要矛盾;
- 已经完成数据库、网络和架构层面的基本优化;
- 对尾延迟、内存密度、冷启动或弹性扩容有明确目标;
- 能通过基准测试和生产指标验证收益。
例如,一个面向用户的支付执行服务,在活动期间可能需要迅速从少量实例扩容到大量实例。此时,Rust 的潜在收益可能不只是平均响应时间,而是:
- 更低的单实例资源需求;
- 更高的容器部署密度;
- 更快的启动速度;
- 更可预测的运行时行为;
- 在高并发下更稳定的尾延迟;
- 编译期内存安全带来的可靠性收益。
但这些收益必须通过真实工作负载验证,而不能只通过一个脱离业务的 Hello World benchmark 宣布。
Rust 应该通过可测量的运行时价值进入系统,而不是通过语言偏好进入系统。
五、不要为了双栈而共享一个“超级领域模型”
当 Java 和 Rust 同时出现在一个系统中时,一个很自然的想法是:
能否让两边共享完全相同的业务模型?
在单体系统、SDK 或跨平台客户端中,这种方式可能有价值。但在微服务场景下,强行共享完整领域模型往往不是好主意。
例如,商户服务可能拥有:
Merchant
BeneficialOwner
KycCase
ComplianceReview
MerchantDocument
支付执行服务可能拥有:
PaymentIntent
Quote
PaymentRoute
Execution
GatewayCallback
PaymentStatus
它们属于不同的 bounded context,拥有独立的:
- 数据库;
- 生命周期;
- 部署节奏;
- 内部状态;
- 领域约束。
为了追求“Java 和 Rust 一致”而合并这些模型,反而可能重新制造强耦合。
在微服务边界上,真正需要共享的是有限且稳定的契约,例如:
MerchantApproved
MerchantSuspended
PaymentRequested
PaymentAccepted
PaymentCompleted
PaymentFailed
因此,更合适的原则是:
不同微服务各自建模,只在 API 与事件边界共享必要语义。
也就是说:
Different service models.
Clear interface contracts.
六、双技术栈真正的风险,是工程方式碎片化
即使服务边界设计合理,引入 Rust 仍然会产生一个组织问题。
传统情况下,Java 团队和 Rust 团队很容易分别形成两套体系:
Java Team
├── 一套查询方式
├── 一套审计方案
├── 一套错误模型
├── 一套测试规范
├── 一套项目结构
└── 一套 AI Coding 指南
Rust Team
├── 另一套查询方式
├── 另一套审计方案
├── 另一套错误模型
├── 另一套测试规范
├── 另一套项目结构
└── 另一套 AI Coding 指南
局部性能可能提高了,但整个组织的认知成本也提高了:
- Java 工程师很难阅读 Rust 服务;
- Rust 工程师需要重新理解 Java 项目的工程约定;
- 架构规范在两个团队中逐渐分叉;
- 审计和可观测性语义不一致;
- AI Agent 需要学习两套完全不同的开发方式;
- 一项跨服务需求更容易在交接处丢失语义。
因此,多语言架构真正需要解决的,不只是“服务之间如何通信”,还包括:
如何在保留语言选择的同时,避免工程体验和组织认知被撕裂?
我认为这里应该追求的不是:
One shared domain model.
而是:
One shared way of building.
七、TeaQL 的尝试:不同模型,相同的工程语法
TeaQL 同时提供 Java 和 Rust 实现。
我们的目标不是让 Java 服务和 Rust 服务共享一个巨大的模型,也不是让所有代码逐行一致,而是让两边拥有相似的工程表达方式。
例如,在 Java 中,一个带业务目的的查询可能是:
Q.payments()
.comment("Find payments requiring reconciliation")
.withStatusIsCompleted()
.withReconciliationStatusIsPending()
.purpose("prepare reconciliation batch")
.executeForList(ctx);
在 Rust 中,可以采用相似的表达:
Q::payments()
.comment("Find payments requiring reconciliation")
.with_status_is_completed()
.with_reconciliation_status_is_pending()
.purpose("prepare reconciliation batch")
.execute_for_list(ctx)
.await?;
这两段代码:
- 不一定属于同一个微服务;
- 不一定使用相同的领域模型;
- 不一定访问相同的数据库;
- 不需要共享同一个运行时。
但工程师和 AI 看到的是相似的结构:
选择业务对象
→ 表达业务条件
→ 说明操作目的
→ 在上下文中执行
→ 形成审计与追踪信息
TeaQL 希望统一的是:
- 业务意图的表达;
- 查询和数据访问的基本形态;
purpose、comment、audit等工程语义;- 状态与约束的类型化表达;
- 代码生成方式;
- 测试与质量门禁;
- AI Coding 所需的指南和上下文;
- 服务开发的整体工作模式。
这可以概括为:
不同的运行时,相同的工程体验。
或者:
TeaQL 不统一微服务内部模型,而是统一开发微服务的方式。
八、一个可运行的 Java + Rust 支付参考实现
为了验证这种思路,我们实现了一个小型参考项目:
polyglot-payment-with-teaql
项目地址:
https://github.com/teaql/polyglot-payment-with-teaql
它包含两个独立微服务。
Java Merchant Service
基于 Spring Cloud 与 TeaQL Java,负责:
- 商户注册;
- KYC 信息;
- 审批与暂停;
- 商户状态变更;
- Transactional Outbox;
- 服务发现和状态同步。
Rust Payment Service
基于 Axum 与 TeaQL Rust,负责:
- 面向用户的支付创建;
- 支付回调;
- 状态查询;
- 商户状态本地缓存;
- 高并发请求处理;
- 独立扩容与部署。
整体结构如下:
+---------------------------------------------------+
| Java Merchant Service |
| Merchant Registry / KYC / Approval / Integration |
+-------------------------+-------------------------+
|
Merchant status contract
|
v
+-------------------------+-------------------------+
| Rust Payment Service |
| Checkout / Payment / Callback / High Concurrency |
+-------------------------+-------------------------+
两个服务:
- 各自拥有领域模型;
- 各自拥有数据库;
- 各自决定部署生命周期;
- 只在服务边界交换必要信息;
- 使用相似的 TeaQL 工程方式。
Java 侧使用 merchant_db,Rust 侧使用 payment_db。Rust 支付服务会维护本地的商户可用状态,避免每一次支付请求都同步调用 Java 服务,从而减少用户请求关键路径上的跨服务依赖。
这个项目并不是一个完整的支付产品,也不是要证明所有支付服务都应该使用 Rust。
它想验证的是一个更有限、也更现实的命题:
Java 和 Rust 可以根据不同工作负载共同构建大型商业系统,而不必让工程组织陷入完全割裂的双技术栈。
九、Rust 进入 Java 企业系统的四步路径
基于这个思路,我认为更稳妥的落地方式可以分成四步。
第一步:寻找运行时价值明确的边界
不要从“哪个 Java 服务看起来最旧”开始,而要从指标开始:
- 哪条链路的 P99/P99.9 最重要?
- 哪个服务的流量波动最大?
- 哪个服务扩容最频繁?
- 哪个服务的内存成本最高?
- 哪个服务的边界最清晰?
- 哪个服务失败后最容易隔离和回滚?
理想的第一个 Rust 服务应该:
- 边界清晰;
- 业务变化相对可控;
- 能够独立部署;
- 可以逐步切流;
- 收益可以量化。
第二步:先统一契约,不急于统一实现
在编码之前,先定义:
- API schema;
- 事件格式;
- 幂等语义;
- 错误码;
- 超时和重试规则;
- 版本兼容策略;
- 审计字段;
- 可观测性要求。
Java 与 Rust 不需要共享内部对象,但必须对边界语义形成一致理解。
第三步:建立统一的工程约定
至少需要统一:
- Trace ID 和业务上下文;
- 日志字段;
- 审计语义;
- 错误分类;
- 指标命名;
- 测试分层;
- 安全检查;
- API 兼容策略;
- 发布和回滚流程。
只有这样,Rust 才是现有工程体系中的新成员,而不是一个孤立的技术岛。
第四步:用生产指标决定是否扩大
可以比较:
- P50、P95、P99、P99.9 延迟;
- 单实例吞吐;
- CPU 与内存消耗;
- 容器启动时间;
- 扩容响应时间;
- 错误率;
- 事故恢复时间;
- 开发周期;
- 缺陷密度;
- 团队维护成本。
只有当综合收益成立,才继续把 Rust 扩展到更多服务。
十、哪些情况下不应该使用 Rust?
主张 Java + Rust 混合,并不意味着应该主动增加技术栈。
以下场景通常不适合作为 Rust 的第一入口:
1. 业务规则每天变化
如果一个服务的主要问题是产品需求频繁变化、第三方 SDK 很多、流程持续调整,那么迁移到 Rust 不一定能改善核心矛盾。
2. 性能瓶颈主要在数据库
如果请求的大部分时间都花在慢 SQL 或远程服务上,更换语言通常不会带来预期收益。
3. 团队缺乏维护能力
如果只有一名工程师能理解 Rust 服务,那么它可能成为新的组织风险。
4. 服务边界尚未稳定
在领域边界仍然剧烈变化时过早拆分,可能同时承担微服务复杂度和新语言复杂度。
5. 只是为了“技术先进”
缺少可衡量目标的 Rust 项目,很容易在内部变成昂贵的技术展示。
因此,我更倾向于一个克制的原则:
Java by default, Rust by justification.
Java 可以继续作为大量企业业务服务的默认选择;Rust 在存在明确运行时价值的地方进入。
十一、AI 编程让统一工程方式变得更重要
在 AI Coding 时代,多语言开发的门槛似乎正在降低。
AI 可以帮助工程师:
- 生成 Rust 代码;
- 理解所有权和生命周期错误;
- 编写 Java 与 Rust 之间的接口;
- 生成测试;
- 完成重复性迁移。
但 AI 同样会放大工程碎片化。
如果每个服务都有不同的:
- API 风格;
- 数据访问方式;
- 审计方法;
- 错误约定;
- 目录结构;
- 验收标准;
AI 就必须反复阅读大量上下文,并且更容易产生局部正确、整体不一致的代码。
因此,统一工程体验的价值在 AI 时代反而更大:
Language choice remains flexible
+
Engineering grammar remains stable
=
Lower cognitive cost for humans and AI
多语言并不可怕。
真正危险的是:
每增加一种语言,就增加一套完全不同的软件工程体系。
结语
Rust 要进入金融和大型商业软件,未必需要先证明自己能够取代 Java。
更现实的路径,是承认 Java 已经建立起来的企业生态,在其中找到真正适合 Rust 的服务边界:
- 面向最终用户;
- 性能与资源效率敏感;
- 需要快速弹性扩容;
- 运行时可预测性很重要;
- 边界足够清晰;
- 收益能够被验证。
Java 和 Rust 不需要共享一个代码库,也不需要共享一个巨大的领域模型。
它们需要的是:
- 清晰的服务契约;
- 一致的业务语义;
- 相近的工程表达;
- 统一的审计与可观测性;
- 可重复的开发、测试和交付方式。
最终,我们希望实现的不是:
Java or Rust
而是:
Java for business complexity.
Rust for runtime criticality.
One consistent engineering experience.
Rust 不必推倒 Java 的世界。它可以先成为这个世界里不可替代的一部分。
参考资料
-
TeaQL Java + Rust 支付微服务参考实现
https://github.com/teaql/polyglot-payment-with-teaql -
2025 Stack Overflow Developer Survey — Technology
https://survey.stackoverflow.co/2025/technology -
2025 State of Rust Survey Results
https://blog.rust-lang.org/2026/03/02/2025-State-Of-Rust-Survey-results/ -
GitHub Octoverse 2025
https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/
评论区
写评论还没有评论