云原生时代JAVA语言的求生之路
转自酷家乐技术博客:https://tech.kujiale.com/
作者:酷家乐国际化业务线-橙子
Introduction
云原生(Cloud Native)相信大家已经不再陌生,它已经被媒体和社区认为是 web 技术体系进化的大趋势。而 Java,已经是一门年龄超过20岁,被广泛使用在个人电脑、移动设备上,覆盖互联网、教育、政府、军工等行业的强大语言。
巨大的生态和年龄的积累带来了沉重的包袱,使得 Java 语言面对云原生的趋势,转型缓慢,应对乏力,被一些专家质疑,可参考这篇文章。
我们观察到,自从 Oracle 收购 Sun Microsystems,掌握了 Java 相关的主要产权之后,管理风格偏向保守。2017年,在 JAVA 社区强大的政治压力之下(主要诉求是解决 Oracle 在 JavaEE 上进展太慢的问题),Oracle 终于将 Java EE 捐献给了 Eclipse Foundation,最终,新的 Java EE 在更名为 Jakarta EE 后,转由 Java 社区而不是Oracle公司来主导维护(详情参考:这篇文章 )。而现在,整个转交过程尚未全部完成,预计2019年9月份,第一版 Jakarta EE 会正式发布。
另一方面,Spring Framework 和 Spring-boot 框架背后的主要贡献者 Pivotal 公司, 近期股价也承受了压力,它的CEO声称原因在于客户成单率低于预期以及新技术落地困难带来的成交周期变长。这部分反映了 Pivotal 在应对以 Kubernetes 为核心的云原生体系的激烈竞争中没有交出足够好的结果。
本文是一篇综述型文章,笔者将通过归纳梳理多篇技术博客和文献,帮助读者解答两个问题: 1. Java 语言在云原生时代到底遇到哪些问题? 2.面对这些问题,Java 语言和社区做出了哪些努力,形成了哪些解决方案?
Java语言在云原生转型中的问题
在这篇文章中,原作者直接指出了 Spring 框架下 Java 微服务在云原生世界中的原罪,原文引述如下:
"As companies migrate to microservices, they take their Spring Java services, bundle them into a fat jars, add the JDK and run it in a Linux based container. This solution works but you have to manage heavy weight containers that are 500MB in size and take 10 to 30 seconds to be available; and this is a problem. Many companies after migrating, they slowly move to Python or Java for their backend services; and eventually, to FaaS. Serverless and FaaS are now very popular because allow us to focus on writing functions without worrying about the infrastructure. They still run inside containers but the cloud provider manage its life cycle. The neat thing is that after certain time, the cloud provider will kill completely the container and start it again on the next call, so you only pay for the usage. The first call to a function may take a bit longer, this is the famous cold start. This is happens because the container needs to boot up. With Python or JavaScript this is not a huge problem, but for Java this could be 10–15 seconds which is a deal breaker and the cause of the decline in Java. Now we need code that can run, do its job and then stop. We don’t want multiple threads or long running processes, we want short lived processes that can boot very quickly."
总结起来,是如下这三个方面,影响了 Java 在 Kubernetes, serverless 等技术体系下的应用效果:
1.JVM+OS 需要的硬盘空间较大,最终镜像文件较大,使得镜像拉取和容器创建效率降低,进而使整个容器生命周期拉长(简称为镜像大小问题);
2.JVM 的机制使得它在运行时所需要的内存较大,相较于 JavaScript, Python, Go 等语言,这使得容器运行时资源消耗变大,资源利用率降低(简称为资源利用率问题);
3.Spring这类重型注入框架带来了较长的启动时间,往往有几十秒,这使得冷启动时间变得不可接受,容器生命周期拉长(简称为冷启动时间问题)。
这些现实问题在云原生时代是如此突出和棘手,以至于 JCP 主席 Heather Van Cura 在一篇名为《让JAVA在云和敏捷时代不掉队》的采访中,说一些 Java 上功能和流程需要更新,以使"Java 能够吸引更多可能保有'Java 是老一辈开发者的语言'成见的年轻开发者"。
Java生态如何应对这些问题
根据 TIOBE指数,Java 指数虽然在长期衰退中,但该语言仍然是最广泛使用的编程语言,这代表 Java 背后有无数的开发者和强大的社区生态。面对问题,Java 的开发者和社区没有退缩,他们在各自的领域给出了很多优秀的解决方案,进展如下:
一、镜像大小问题
云原生世界中,Alpine 已经是容器操作系统的事实标准,整个镜像只有 5MB 左右。优化主要聚焦在 JRE 大小的优化上,这方面实际上业界已有较好解法。
- 通过JDK9的模块化功能,减小镜像总体积
- 使用Alpine-Portola项目,得到最小的java运行环境镜像(最小可达40MB左右)
二、资源利用率问题
JVM 以及在 JVM 上跑的应用程序所消耗的内存较大,是造成资源利用率低的最主要原因。
- Project Panama 一个聚焦于增强 JVM 与其他语言特别是 C 语言交互的项目,通过本项目,JVM 可以获取 Native data,以得到更好的内存使用。现状: 草稿状态,未实装。
- Project Valhalla 给 Java 引入 Value Types,以换取不可变数据类型的高性能和低开销。现状: 草稿,预计 JDK14 实装。
- 多项 String 和 G1 垃圾收集器相关优化,最终带来内存减小和性能提升,参考这篇评测。
- Class-Data-Sharing 在 JDK10 中引入,可以减小内存占用和启动时间。
三、冷启动时间问题
面对容器化转型,代码开发的交付物从应用程序变成了镜像,这带来了一个巨大转变: 我们已经不再需要一份代码"write once, run everywhere", 因为我们的 runtime 可以固定在镜像里,放弃兼容性。很多解决方案就是以此为突破点,牺牲平台兼容性换取性能。
- Graalvm Java世界最近的明星项目,该 vm 支持多个编程语言的运行时,并可以使Java代码编译为机器码,实际上这就是 AOT 编译相对 JIT 编译带来的性能优势。该项目目前活跃度和关注度都很高。
- Micronaut.io 一个基于 Graalvm 的轻量级微服务框架,相对于 Spring-boot,大大减少了启动时间和运行时内存消耗,这篇文章声称,以此框架撰写的 Java 服务,启动时间为20毫秒,内存开销为18M。该项目目前每月有更新。
- Helidon.io Oracle 开发的一个轻量级微服务框架,以 Netty 为核心,可以直接对接成熟的云原生组件如 Prometheus,Zipkin/Jeager, Kubernetes 等,特色是启动时间快,目前项目每月更新。
- Jakarta.ee 由 Eclipse 基金会维护的,面向云原生的新版 Java EE,预计于今年九月份发布第一版。根据这份文档,在新版 JakartaEE 标准的指引下所有 EE4J 项目将全面拥抱云原生。
- Quarkus.io 轻量级微服务框架,可以运行在 Graalvm上,通过 AOT 编译获得启动时间优化。参考这篇博客。该项目目前尚未发布1.0正式版。
- Spring-Cloud-Functions Spring自己也没闲着,这个基于 Java Functions 和 Flux的组件可以让 Java 开发者通过 Bean 的形式直接写出一个函数,而不需要启动一个Spring-boot。项目不太活跃。
- Dagger 一个原来服务于安卓的静态注入框架,通过编译前就静态注入代码,而不是运行时动态注入,来加快启动速度。目前被越来越多java服务端开发者关注。项目非常活跃。
结论
“周虽旧邦,其命维新”,通过综述十几个项目的目标和现状,我们看到整个 Java 社区在云原生转型中付出的努力。在镜像文件大小问题上,业界已经有了成熟和有效的方案;在资源利用率问题上,Java 社区一直在通过各种不同的途径来优化;在冷启动时间问题上,我们看到了很多新的解决方案,但并未有响亮的业界实践反馈,且大部分方案牺牲了 Java 的跨平台性,这都有待未来几年市场的检验。
笔者相信,只要 Oracle 在未来的几年中不破坏和干预 Java 生态,Java 语言必将克服在云原生应用中遇到的诸多问题,焕发出新的生命力。
参考文献
- https://itnext.io/introduction-to-quarkus-cloud-native-java-apps-e205ae702762
- http://openjdk.java.net/jeps/0
- https://pivotal.io/cloud-native
- https://hub.packtpub.com/jakarta-ee-past-present-and-future/
- https://www.theserverside.com/feature/Brian-Goetz-Reveals-Valhalla-for-Java-Ten-and-Beyond-at-JavaOne-2015
- https://codeburst.io/microservices-in-java-never-a7f3a2540dbb
- https://github.com/square/dagger/issues/366
- https://dzone.com/articles/java-memory-management