阿里技术专家:进击的 Java ,云原生时代的蜕变
导读:云原生时代的来临,与Java 开发者到底有什么联系?有人说,云原生压根不是为了 Java 存在的。然而,本文的作者却认为云原生时代,Java 依然可以胜任“巨人”的角色。作者希望通过一系列实验,开拓同学视野,提供有益思考。
在企业软件领域,Java 依然是绝对王者,但它让开发者既爱又恨。一方面因为其丰富的生态和完善的工具支持,可以极大提升了应用开发效率;但在运行时效率方面,Java 也背负着”内存吞噬者“,“CPU 撕裂者“的恶名,持续受到 NodeJS、Python、Golang 等新老语言的挑战。
- 体积更小:对于微服务分布式架构而言,更小的体积意味着更少的下载带宽,更快的分发下载速度。
- 启动速度更快:对于传统单体应用,启动速度与运行效率相比不是一个关键的指标。原因是,这些应用重启和发布频率相对较低。然而对于需要快速迭代、水平扩展的微服务应用而言,更快的的启动速度就意味着更高的交付效率,和更加快速的回滚。尤其当你需要发布一个有数百个副本的应用时,缓慢的启动速度就是时间杀手。对于Serverless 应用而言,端到端的冷启动速度则更为关键,即使底层容器技术可以实现百毫秒资源就绪,如果应用无法在 500ms 内完成启动,用户就会感知到访问延迟。
- 占用资源更少:运行时更低的资源占用,意味着更高的部署密度和更低的计算成本。同时,在 JVM 启动时需要消耗大量 CPU资源对字节码进行编译,降低启动时资源消耗,可以减少资源争抢,更好保障其他应用 SLA。
- 支持水平扩展:JVM 的内存管理方式导致其对大内存管理的相对低效,一般应用无法通过配置更大的 heap size 实现性能提升,很少有 Java 应用能够有效使用 16G 内存或者更高。另一方面,随着内存成本的下降和虚拟化的流行,大内存配比已经成为趋势。所以我们一般是采用水平扩展的方式,同时部署多个应用副本,在一个计算节点中可能运行一个应用的多个副本来提升资源利用率。
热身准备
熟悉 Spring 框架的开发者大多对 Spring Petclinic 不会陌生。本文将借助这个著名示例应用来演示如何让我们的 Java 应用变得更小、更快、更轻、更强大!
我们 fork 了 IBM 的 Michael Thompson 的示例,并做了一些调整。
$ git clone https://github.com/denverdino/adopt-openj9-spring-boot
$ cd adopt-openj9-spring-boot
$ 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)
$ docker images petclinic-openjdk-hotspot
REPOSITORY TAG IMAGE ID CREATED SIZE
petclinic-openjdk-hotspot latest 469f73967d03 26 hours ago 871MB
镜像瘦身
原图
我们将镜像构建分成两个阶段:
- 在 ”build“ 阶段依然采用 JDK 作为基础镜像,并利用 Maven 进行应用构建;
- 在最终发布的镜像中,我们会采用 JRE 版本作为基础镜像,并从”build“ 镜像中直接拷贝出生成的 jar 文件。这意味着在最终发布的镜像中,只包含运行时所需必要内容,不包含任何编译时依赖,大大减少了镜像体积。
$ cat Dockerfile.openjdk-slim
FROM adoptopenjdk/openjdk8 AS build
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
FROM adoptopenjdk/openjdk8:jre8u222-b10-alpine-jre
COPY --from=build /tmp/spring-petclinic/target/spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar
CMD ["java","-jar","spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar"]
查看一下新镜像大小,从 871MB 减少到 167MB!
$ docker build -t petclinic-openjdk-hotspot-slim -f Dockerfile.openjdk-slim .
...
$ docker images petclinic-openjdk-hotspot-slim
REPOSITORY TAG IMAGE ID CREATED SIZE
petclinic-openjdk-hotspot-slim latest d1f1ca316ec0 26 hours ago 167MB
从 JIT 到 AOT —启动提速
$cat Dockerfile.openj9.warmed
FROM adoptopenjdk/openjdk8-openj9 AS build
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
FROM adoptopenjdk/openjdk8-openj9:jre8u222-b10_openj9-0.15.1-alpine
COPY --from=build /tmp/spring-petclinic/target/spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar
# Start and stop the JVM to pre-warm the class cache
RUN /bin/sh -c 'java -Xscmx50M -Xshareclasses -Xquickstart -jar spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar &' ; sleep 20 ; ps aux | grep java | grep petclinic | awk '{print $1}' | xargs kill -1
CMD ["java","-Xscmx50M","-Xshareclasses","-Xquickstart", "-jar","spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar"]
-Xshareclasses
开启SCC,-Xquickstart
开启AOT。
$ docker build -t petclinic-openjdk-openj9-warmed-slim -f Dockerfile.openj9.warmed-slim .
$ docker run --name hotspot -p 8080:8080 --rm petclinic-openjdk-openj9-warmed-slim
...
2019-09-11 03:35:20.192 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-09-11 03:35:20.193 INFO 1 --- [ main] o.s.s.petclinic.PetClinicApplication : Started PetClinicApplication in 3.691 seconds (JVM running for 3.952)
...
可以看到,启动时间已经从之前的 8.2s 减少到 4s,提升近50%。
docker stats
查看资源消耗。
$ ./run-hotspot-4.sh
...
Wait a while ...
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
0fa58df1a291 instance4 0.15% 597.1MiB / 5.811GiB 10.03% 726B / 0B 0B / 0B 33
48f021d728bb instance3 0.13% 648.6MiB / 5.811GiB 10.90% 726B / 0B 0B / 0B 33
a3abb10078ef instance2 0.26% 549MiB / 5.811GiB 9.23% 726B / 0B 0B / 0B 33
6a65cb1e0fe5 instance1 0.15% 641.6MiB / 5.811GiB 10.78% 906B / 0B 0B / 0B 33
...
$ ./run-openj9-warmed-4.sh
...
Wait a while ...
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
3a0ba6103425 instance4 0.09% 119.5MiB / 5.811GiB 2.01% 1.19kB / 0B 0B / 446MB 39
c07ca769c3e7 instance3 0.19% 119.7MiB / 5.811GiB 2.01% 1.19kB / 0B 16.4kB / 120MB 39
0c19b0cf9fc2 instance2 0.15% 112.1MiB / 5.811GiB 1.88% 1.2kB / 0B 22.8MB / 23.8MB 39
95a9c4dec3d6 instance1 0.15% 108.6MiB / 5.811GiB 1.83% 1.45kB / 0B 102MB / 414MB 39
...
- https://www.ibm.com/developerworks/cn/java/j-class...
- https://www.ibm.com/developerworks/cn/java/j-optim...
- HotSpot 在 Class Data Sharing (CDS) 和 AOT 方面也有了很大进展,但是 IBM J9 在这方面更加成熟。期待阿里的
原生代码编译
$ git clone https://github.com/denverdino/micronaut-petclinic
$ cd micronaut-petclinic
$ cat Dockerfile
FROM maven:3.6.1-jdk-8 as build
COPY ./ /micronaut-petclinic/
WORKDIR /micronaut-petclinic
RUN mvn package
FROM oracle/graalvm-ce:19.2.0 as graalvm
RUN gu install native-image
WORKDIR /work
COPY --from=build /micronaut-petclinic/target/micronaut-petclinic-*.jar .
RUN native-image --no-server -cp micronaut-petclinic-*.jar
FROM frolvlad/alpine-glibc
EXPOSE 8080
WORKDIR /app
COPY --from=graalvm /work/petclinic .
CMD ["/app/petclinic"]
- 在 "build" 阶段,利用Maven构建 Micronaut 版本的 PetClinic 应用,
- 在 "graalvm" 阶段,我们通过
native-image
将 PetClinic jar 文件转化成可执行文件。 - 在最终阶段,将本地可执行文件加入一个 Alpine Linux 基础镜像
$ docker-compose build
$ docker-compose up db
$ docker-compose up app
micronaut-petclinic_db_1 is up-to-date
Starting micronaut-petclinic_app_1 ... done
Attaching to micronaut-petclinic_app_1
app_1 | 04:57:47.571 [main] INFO org.hibernate.dialect.Dialect - HHH000400: Using dialect: org.hibernate.dialect.PostgreSQL95Dialect
app_1 | 04:57:47.649 [main] INFO org.hibernate.type.BasicTypeRegistry - HHH000270: Type registration [java.util.UUID] overrides previous : org.hibernate.type.UUIDBinaryType@5f4e0f0
app_1 | 04:57:47.653 [main] INFO o.h.tuple.entity.EntityMetamodel - HHH000157: Lazy property fetching available for: com.example.micronaut.petclinic.owner.Owner
app_1 | 04:57:47.656 [main] INFO o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
app_1 | 04:57:47.672 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 159ms. Server Running: http://1285c42bfcd5:8080
https://docs.micronaut.io/latest/guide/index.html#...
https://www.exoscale.com/syslog/how-to-integrate-s...
总结与后记
扫描下方二维码添加小助手,与 8000 位云原生爱好者讨论技术趋势,实战进阶!
阿里技术专家:进击的 Java ,云原生时代的蜕变相关推荐
- 进击的.NET 在云原生时代的蜕变
你一定看过这篇文章 <进击的 Java ,云原生时代的蜕变>, 本篇文章的灵感来自于这篇文章.北京时间9.24 就将正式发布.NET Core 3.0, 所以写下这篇文章让大家全面认识. ...
- 进击的 Java ,云原生时代的蜕变
点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 作者 | 易立 来源 | 公众号「阿里巴巴云原生」 导读:云原生时代的来临,与Java 开发 ...
- 阿里高工流生 | 云原生时代的 DevOps 之道
作者 | 郝树伟(流生)阿里云高级研发工程师 导读:DevOps 是一种软件开发人员和 IT人员之间的合作过程,目标是高效地自动执行软件交付和基础架构更改流程.在云原生时代,企业又如何借助 DevOp ...
- 蚂蚁金服资深技术专家经国:云原生时代微服务的高可用架构设计
经国 蚂蚁金服数字金融线担任技术风险架构师 读完需要 15 分钟 速读仅需 5 分钟 经国,蚂蚁金服资深技术专家,毕业于浙江大学. 2014 年加入蚂蚁金服,先后负责过支付宝的单元化.弹性.去 ORA ...
- 云原生时代 给予.NET的机会
.NET诞生于与Java的竞争,微软当年被罚款20亿美元.Java绝不仅仅是一种语言,它是COM的替代者!而COM恰恰是Windows的编程模型.而Java编程很多时候比C++编程要容易的多,更致命的 ...
- 带你深入探究云原生时代的分布式操作系统 Kubernetes
过去几年,以 docker.kubernetes 为代表的容器技术已发展为一项通用技术,BAT.滴滴.京东.头条等大厂,都争相把容器和 k8s 项目作为技术重心,试图"放长线钓大鱼" ...
- 什么是云效,云原生时代新 DevOps 平台
什么是云效,云原生时代新 DevOps 平台,阿里云云效,云原生时代新 DevOps 平台,支持公共云.专有云和混合云多种部署形态,通过云原生新技术和研发新模式,助力创新创业和数字化转型企业快速实现研 ...
- 什么是云效,云原生时代一站式DevOps平台
什么是云效?使用云效体验一站式研发实现10 倍效能提升,阿里云云效,云原生时代新 DevOps 平台,支持公共云.专有云和混合云多种部署形态,云效通过云原生新技术和研发新模式,助力创新创业和数字化转型 ...
- DTCC 2020 | 阿里云程实:云原生时代的数据库管理
简介:随着云原生技术的不断发展,数据库也逐渐进入了云原生时代.在云原生时代,如何高效.安全且稳定地管理云上与云下的数据库成为摆在企业面前的一大难题.在第十一届中国数据库技术大会(DTCC2020)上, ...
最新文章
- Reids实战(7)数据类型五sorted sets
- 部署分布式文件系统(DFS)
- python怎么备份列表_python实例:backup 备份
- mupdf不支持x64_Delphi xe2使用x64编译器编译ASM代码时出错 . 不支持的语言功能:'ASM'...
- 在你迷茫时不如学好一门语言(送给大一的学弟学妹)
- java解压zip文件程序_java 解压zip文件
- linux之ext、ext1、ext2、ext3、ext4文件系统的区别及常用命令
- 使用jad反编译Java文件
- Google式用户体验的十大内在原则
- esp_wifi_repeater, 全功能WiFi中继器
- 如何采用SMW0存储模板和OLED操作Excel的方式生成Excel单据
- 多商家点餐小程序源码
- 知识传输革命即将到来
- 蔡凯龙:跨界是一种寻求人生宽度的方式
- 攻防世界题库logmein
- php doctrine,php – Doctrine上的复杂SQL查询
- android 摇晃工具箱
- Clippper模拟量输出设置
- php从照片中抠出人脸,PS怎样将一张图片上的人脸抠取五官下来到另一张图片
- 《虎虎圆桌派》第一期全程回顾
热门文章
- 面试题 gety() getTop() TranslationY关系
- python文本内容怎么转换成字典_怎么把照片上的文字转换成文本?照片转换文字神器来了...
- loadrunner之socket协议脚本编写
- QT 线程池 + TCP 小试(三)实现最终功能
- 【精辟】socket阻塞与非阻塞,同步与异步,select,pool,epool
- linux常用命令(精)
- 基于Given变换的QR分解辨析
- 人生实苦,可这就是人生
- 集群、RAC和MAA
- Software Construction Series(1)