Java 在企业应用中占据主导地位。但在云上,Java 比一些竞争对手的使用成本更高。原生编译降低了在云中使用 Java 的成本:它创建的应用程序启动速度更快,占用的内存更少。
原生编译给 Java 用户带来了许多问题:原生 Java 对开发有什么影响?我们什么时候应该改用原生 Java?什么时候不应该?我们应该使用什么框架来开发原生 Java?这个系列将回答这些问题。
1
Kubernetes Native Java 是什么?
“[它们] 可以运行 3 倍密度的部署,而又不影响服务的可用性和响应时间。”—— Lufthansa Technik
采用 Kubernetes,组织可以更快、更经济有效地交付业务价值。为什么?因为 Kubernetes 简化了一些原本困难的任务:它会在负载增加时自动实现应用程序的水平扩展,并能执行滚动升级。
但是,这种方法与 Java 传统的三层架构模型(大堆、垂直扩展、长时间运行的进程)相冲突。
历史上,Java 通过分配和最大化持有的系统资源,来适应随时间变化的负载,实现卓越的性能。
开发人员非常喜欢长时间运行的、重量级的、JVM 高度动态的 Java 模型,以便在运行多个不同的应用程序时可以支持丰富的声明式编程模型。延迟扫描和运行时类路径分析给我们带来了控制反转,减少了样板代码——以启动时间和内存占用为代价。这些缺点在堆很大的大型单体应用程序中并没有太大影响,因为启动代价只需要支付一次。
但是,在 Kubernetes 中运行这些传统的 Java 应用程序会导致许多胖 JVM,它们承载着需要大量资源的动态运行时,并且会经常重启。重启要一次次分析同样的不可变镜像,每次都会浪费掉相同的 CPU 周期。这个分析还会使用大量的内存,而且在 JVM 生命周期中一直占用。但是在 Kubernetes 中,部署密度很重要:可以运行的应用程序实例越多,Kubernetes 的投资回报率就越高。
Kubernetes Native Java 意味着 Java 应用程序可以利用而不是抗拒 Kubernetes 的能力——启动速度很快的小进程,而不是启动时间很长、内存占用很高的 JVM。
2
Quarkus 背后的动机
“在我们推出 Quarkus 之前,许多客户已经开始关注 Go 和 Node.js 等技术栈,希望可以借此提高性能和效率。对于选择一种新的语言以及雇用新的开发人员,或者重新培训现有的 Java 开发人员,这些客户都倍感疲倦。” —— Arijit Mazumdar,WiPro
组织以及开发人员都在 Java 上有很大的投资。它是一种令人难以置信的高产语言,有许多开发人员熟悉并喜爱的神奇工具和框架。然而,Kubernetes 需要一个新的方向。虽然放弃 Java 的许多好处令人遗憾,但能更有效利用内存、缩短启动时间的运行时,如 Node.js 和 Golang,对 Java 投资发起了挑战。
Quarkus 团队则希望两者兼得:将功能丰富、成熟的 Java 生态系统的优势与 Kubernetes 的操作优势相结合。要实现这一点,Java 应用程序运行时必须更多地采用静态定义,但仍然包含让开发人员可以更快迭代的 Java 动态特性。
组织使用云增加了应用程序部署的速度。同样,现如今的业务需要缩短开发周期,加速业务价值交付。Quarkus 所采用的方法特别注重“开发乐趣(Developer Joy)”,可以支持迭代和部署速度的提升,并且已经证明 Java 可以比脚本语言更具生产力。
当然,生产力并不仅仅与编码速度有关。构建现代云应用程序需要与其他服务交互,而使用复杂 YAML 的配套技术会降低你的速度。我们认为,关乎“开发乐趣”的特性,比如开发服务和零配置开发(稍后会详细介绍),对于 Kubernetes Native Java 来说必不可少。例如,你编写访问数据库的代码,Quarkus 会在你输入的时候神奇地启动并连接后台的所有一切。
同样,向 Kubernetes 部署时也不需要阅读 Kubernetes 管理方面的书籍以及编写数百行的 YAML 文件。我们认为,对于 Quarkus,很重要的一点是你只需要了解 Java。在构建时添加“-Dquarkus.kubernetes.deploy”标志,Quarkus 就会将应用程序部署到 Kubernetes 上(不要忘记登录!)如果你愿意,可以使用集成的 Quarkus Dev UI,直接从浏览器触发部署。
简而言之,Quarkus 是从头开始构建的,它将 Java 变成了构建本地二进制文件和 Kubernetes 应用程序的理想语言