作者| 易立 阿里云资深技术专家



导读:云原生时代的来临,与Java 开发者到底有什么联系?有人说,云原生压根不是为了 Java 存在的。然而,本文的作者却认为云原生时代,Java 依然可以胜任“巨人”的角色。作者希望通过一系列实验,开拓同学视野,提供有益思考。

在企业软件领域,Java 依然是绝对王者,但它让开发者既爱又恨。一方面因为其丰富的生态和完善的工具支持,可以极大提升了应用开发效率;但在运行时效率方面,Java 也背负着”内存吞噬者“,“CPU 撕裂者“的恶名,持续受到 NodeJS、Python、Golang 等新老语言的挑战。

在技术社区,我们经常看到有人在唱衰 Java 技术,认为其不再符合云原生计算发展的趋势。我们先抛开这些观点,首先思考一下云原生对应用运行时的不同需求。

  • 体积更小 - 对于微服务分布式架构而言,更小的体积意味着更少的下载带宽,更快的分发下载速度。
  • 启动速度更快 - 对于传统单体应用,启动速度与运行效率相比不是一个关键的指标。原因是,这些应用重启和发布频率相对较低。然而对于需要快速迭代、水平扩展的微服务应用而言,更快的的启动速度就意味着更高的交付效率,和更加快速的回滚。尤其当你需要发布一个有数百个副本的应用时,缓慢的启动速度就是时间杀手。对于Serverless 应用而言,端到端的冷启动速度则更为关键,即使底层容器技术可以实现百毫秒资源就绪,如果应用无法在500ms内完成启动,用户就会感知到访问延迟。
  • 占用资源更少 - 运行时更低的资源占用,意味着更高的部署密度和更低的计算成本。同时,在JVM启动时需要消耗大量CPU资源对字节码进行编译,降低启动时资源消耗,可以减少资源争抢,更好保障其他应用SLA。
  • 支持水平扩展 - JVM的内存管理方式导致其对大内存管理的相对低效,一般应用无法通过配置更大的heap size实现性能提升,很少有Java应用能够有效使用16G内存或者更高。另一方面,随着内存成本的下降和虚拟化的流行,大内存配比已经成为趋势。所以我们一般是采用水平扩展的方式,同时部署多个应用副本,在一个计算节点中可能运行一个应用的多个副本来提升资源利用率。

    热身准备

    熟悉Spring框架的开发者大多对 Spring Petclinic 不会陌生。本文将借助这个著名示例应用来演示如何让我们的Java应用变得更小,更快,更轻,更强大!
    file
    我们fork了IBM的Michael Thompson的示例,并做了一些调整。
$ git clone https://github.com/denverdino/adopt-openj9-spring-boot $ cd adopt-openj9-spring-boot

首先,我们会为PetClinic应用构建一个Docker镜像。在Dockerfile中,我们利用OpenJDK作为基础镜像,安装Maven,下载、编译、打包Spring PetClinic应用,最后设置镜像的启动参数完成镜像构建。

$ cat Dockerfile.openjdk FROM adoptopenjdk/openjdk8 RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/' /etc/apt/sources.list RUN apt-get update RUN apt-get install -y \     git \     maven WORKDIR /tmp RUN git clone https://github.com/spring-projects/spring-petclinic.git WORKDIR /tmp/spring-petclinic RUN mvn install WORKDIR /tmp/spring-petclinic/target CMD ["java","-jar","spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar"]

构建镜像并执行

$ docker build -t petclinic-openjdk-hotspot -f Dockerfile.openjdk . $ docker run --name hotspot -p 8080:8080 --rm petclinic-openjdk-hotspot               |\      _,,,--,,_              /,`.-'`'   ._  \-;;,_   _______ __|,4-  ) )_   .;.(__`'-'__     ___ __    _ ___ _______  |       | '---''(_/._)-'(_\_)   |   |   |   |  |  | |   |       |  |    _  |    ___|_     _|       |   |   |   |   |_| |   |       | __ _ _  |   |_| |   |___  |   | |       |   |   |   |       |   |       | \ \ \ \  |    ___|    ___| |   | |      _|   |___|   |  _    |   |      _|  \ \ \ \  |   |   |   |___  |   | |     |_|       |   | | |   |   |     |_    ) ) ) )  |___|   |_______| |___| |_______|_______|___|_|  |__|___|_______|  / / / /  ==================================================================/_/_/_/ ... 2019-09-11 01:58:23.156  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path '' 2019-09-11 01:58:23.158  INFO 1 --- [           main] o.s.s.petclinic.PetClinicApplication     : Started PetClinicApplication in 7.458 seconds (JVM running for 8.187)

可以通过 http://localhost:8080/ 访问应用界面。
检查一下构建出的Docker镜像, ”petclinic-openjdk-openj9“ 的大小为871MB,而基础镜像 ”adoptopenjdk/openjdk8“ 仅有 300MB!这货也太膨胀了!