速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

云时代,JAVA 何去何从?

  • 2020-09-14
  • 本文字数:3835 字

    阅读完需:约 13 分钟

云时代,JAVA何去何从?

在云原生的世界里,Go 语言凭借语法简单、启动速度快、依赖少、Goroutine 并发等特点,成为了一等公民。而 Java 作为 20 年前的编程语言,那个时代注重的是复杂的 OOP 设计、企业级规范,长期运行下的稳定性和性能。Java 语言似乎与当前云原生环境下的快速交付、微服务等需求格格不入。


阿里巴巴是世界上最大的 Java 用户之一,在拥抱云原生的同时,也要保持现有业务的迭代演进。因此 Alibaba JVM 团队一直致力于让 Java 语言与时俱进,适应云上场景。今天我们就来聊一聊 Java 在云上遇到的挑战以及如何通过 Dragonwell JDK 来克服这些困难。

Java 语言 & 云原生


Java 是一门企业级,高性能,高稳定性的编程语言。企业级简单来说就是适合开发长期运行的大型应用,比如 Linux + OpenJDK 的开发的服务如果没有发布和升级的需求,一般情况下可以保证运行一年以上不用重启。


Java 拥有丰富的生态,大量的高质量第三方类库、框架(比如 Spring、Netty)被维护在 maven 等中心仓库,用户只需声明式地引入包依赖,即可调用实现。举例来说,node 的 npm 生态虽然很完善,但是想要找到一个分布式事务框架就很困难;反观 Java,几乎所有开源软件与工具都会考虑对 Java 平台的支持,我们可以找到多种分布式事务框架的 Java 客户端。因此只要选择了 Java,就是选择了一个资源宝库。


作为 Java 的开发者肯定听说过 Java EE(目前捐给了 Eclipse 社区,更名为 Jakarta EE),Java EE 很大程度上成就了 Java 语言。编程语言本身只是提供控制流、数据结构定义、垃圾回收、并发基础设施、抽象手段等基础能力。而这个编程语言的杀手级场景究竟什么,是取决于语言之上的标准库、规范的。Jakarta EE 定义的 JDBC 规范就引领各大厂商为 Java 提供了接口一致的数据库驱动; Tomcat、JBoss 实现的 Servlet 容器让开发者有机会选择不同的 Servlet 实现。


Java 的跨平台性向开发者屏蔽了底层的硬件和操作系统细节。开发者们可以在 Mac、Windows 的开发环境开发、调试应用,最后到 Linux 的生产环境去部署,这大大降低了研发、调试、运维的工作量。


万物皆有 TradeOff,我们上述的一些设计取向给我们带来的一些麻烦。

代码加载开销高


为了实现跨平台性,Java 定义了自己的字节码,通过字节码描述计算,最后各个平台实现的字节码引擎来执行字节码。我们来看一段程序想要被加载需要经过的流程:


  • new 字节码或者 static 相关字节码触发类加载

  • 从一系列 jar 包中找到感兴趣的 class 文件

  • 将 class 文件的读取到内存里的 byte 数组

  • defineClass,包括了 class 文件的解析、校验、链接

  • 类初始化(static 块,或者静态变量初始化)

  • 开始解释执行

  • 2000 次解释后被 client compiler JIT 编译,随后 15000 次执行后被 server compiler JIT 编译


简单的代码执行却涉及了大量的额外操作,一次类加载基本上是在毫秒级的,因此大型 Java 应用(数万个 class)的启动耗时很长,并需要一段时间来进行 JIT 预热,无法满足快速交付的需求。

内存管理造成内存占用大


我们经常收到到诸如 "明明 heap 只用了几百 M 内存,为啥监控提示内存水位高,进程占用了 5G 的内存"这样的答疑需求。我们结合一个实例来更好地了解 JVM 的内存管理。


  1. 开始 heap 没有对象,只分配了虚拟地址空间

  2. 随着对象分配,发生 page fault,内存被实际分配出来,当 heap 塞满,无法分配对象时,下一次对象分配将触发 gc

  3. gc 只保留了活对象,而死对象回收所空出来的空间可以被后续分配


GC 结束后,虽然有很多空闲内存,但是因为 heap 是 jvm 管理的,jvm 了解这些空间是空闲的,但是操作系统不知情,因此无法把这些空间分配给其他进程使用。JVM 之所以不把内存归还给操作系统的主要原因是这些内存很快就需要被应用使用,如果频繁进行归还,再而触发 page fault 反而带来性能下降。

使用每个请求一个线程的模型


基于上述的 Jakarta EE 规范,大部分 Java 通信组件或者中间件都是基于线程模型的,比如 Servlet 容器使用线程池来处理并发请求。JDBC 访问过程中需要阻塞线程,这也是规范,因此在线程模型下这些组件协作的很好。


但是多线程的抽象下编程简单了,对操作系统的负担却增加了。右图上每个竖块表示一个线程,他们分别处理一个请求,带颜色的区域说明这些线程实际在 CPU 上运行。虽然从线程视角任务是一直在运行的,而实际上是操作系统通过分时机制交替执行他们制造的假象。在高负载下操作系统调度任务的开销不容小视。

Dragonwell 助力云上转型

Dragonwell 产品介绍


要了解 Dragonwell 首先要了解 OpenJDK,OpenJDK 是由 Oracle 开源的 JDK 实现,是目前最广泛使用的实现,类似的实现还有 OpenJ9 等。


针对我们常用的 JDK8、JDK11 LTS 版本,OpenJDK 本身一直维持着活跃的开发,但是社区本身没有持续地提供带有最新更新的发行版本。想要用使用最新的安全的 JDK 版本有两种途径


  1. 使用 Oracle JDK:Oracle 会提供专门支持,但是这是要收费的

  2. 使用三方厂商自己维护的 JDK: 通常云厂商为了让客户们使用到最新的安全的 JDK,都会以 OpenJDK 为上游,推出自己的 JDK 发行版,Amazon Corretto、Alibaba Dragonwell 都是这样一类发行版。这些版本由云厂商维护支持。


Dragonwell 就属于上述的第二种。与 Corretto 等发行版不同的是阿里巴巴针对自己的实践,加入了大量优化特性,特别是针对云场景。我们可以选择性地打开这些优化,如果关闭则表现与 OpenJDK 一致。下面我们针对 Dragonwell 的特性,以及这些特性如何助力 Java 应用上云进行剖析。

Elastic Heap


基于上面描述的 GC 导致 JVM 会占用大量内存这一问题,Elastic Heap 功能会估算应用实际需要使用的内存大小。将内存定期归还给操作系统。


在阿里巴巴的场景下,每个裸金属服务器会部署大量在线业务,当在线业务处于低谷期时,elastic heap 功能会自动地释放内存。此时调度系统就可以在裸金属服务器上创建离线任务,将省出来的内存利用起来。下面看 spring boot demo 一个的例子:



我们使用 wrk 对应用进行压测,不久内存使用(RES)就到达了配置的 1G。且内存不会降下来,即便压测停止也会一直保持在这个水位。



随后我们使用 Elastic Heap 来改善这个状况。使用 Elastic Heap,随着压测停止,内存使用逐渐降低到了 700M。这缓解了 Java 应用占用内存过多的问题。

JWarmup


Java 代码需要经过足够的解释执行次数后才会被 JIT 编译器编译,通过上图的命令可以看到不同编译级别的执行次数阈值。在 Web Server 领域,应用刚刚发布完成时解释代码版本执行就慢,同时随着阈值到达,会触发编译,编译线程本身也会消耗 CPU,这就导致了 Java 服务刚发布完成时性能差。


那么能否让 JIT 编译提前完成呢?JWarmup 就是用来达成这个目的的。如图所示:


  • 在 beta 环境收集代码的 profiling 信息

  • 将收集到的 profiling 数据分 pai 到生产服务器后,进行发布启动

  • Warmup 会提前编译热点方法,保证线上请求开始处理时已经到达一个较高的编译级别了

多租户


多租户是 JVM 层面上提供的虚拟化技术,在 JVM 中引入了一个租户的概念,每个租户的最大资源(通常是 CPU、内存、文件 fd)使用是可以独立控制的。


一种用法是将多个 Java 的微服务部署到同一个 Java 虚拟机中,每个应用可以的资源是隔离的。相比容器隔离的好处是底层数据可以共享,并且应用之间的 RPC 可以被转换成方法调用,大大减少开销。

协程


上文中提到了 Java 使用了线程阻塞模型来处理请求,导致总体效率不够高。


这一点也是业界共识,近年来出现了大量异步处理的框架,在异步的加持下就可以用少量线程来并发处理大量请求了。node.js 是异步编程的典型框架,vertex 和 node 两个单词都是"节点"的意思,Java 的生态中 Vert.X 的流行正是表明了广大开发者对于目前的阻塞模型的现状并不满意。我们来看上图中的 Vert.X 的 JDBC client 的用法,包含了大量的回调函数使用,这对于复杂的应用的接入是一个大的挑战。但是如果我们结合 kotin 协程的支持就可以显著地简化这类异步框架的使用。


右图中对异步的 getConnection 进行了封装,调用后立即切换出协程。当操作完成,回调中会恢复协程执行。这样封装后,上层代码就可以简化了。右图的


conn = client.aGetConnection();
复制代码


本质上是事件驱动的异步操作,但写法上是顺序的。这就是协程带给我们的性能红利。


Dragonwell 的 Wisp 特性就是在 JVM 层面支持了协程,并在所有阻塞调用(如 Socket.connect() )做出了类似 aGetConnection 的封装。因此现有的同步写法的代码都可以被异步调度执行,得到性能提升。


我们继续看一个案例:


我们使用了一个 Spring Boot 以 undertow 作为 Servlet 容器的 Http Server hello world 程序作为实例:



在关闭协程时可以看到有大量的 worker 线程在处理请求,通过多次执行、预热,throughput 最终锁定在 37193。


添加一个参数 -XX:+UseWisp2 后继续测试:



添加一个参数 -XX:+UseWisp2 后继续测试:



可以看到 2 个内核级 pthread 处理了所有请求。默认名字是 Wisp-Root-Worker



吞吐量最终锁定在了 51129,我们免费获得了(51129 - 37193) / 37193 = 37%的性能提升。

总结

  • Dragonwell 是 OpenJDK 在生产环境的可靠免费替代品

  • Dragonwell 已经推出了 JDK11 的版本,阿里云是国内第一个官方支持 JDK11 的厂商


Alibaba Dragonwell 有大量适合应用上云的特性:


  • Elastic Heap:减少微服务的内存消耗,内存分时复用

  • JWarmup: 减少预热过程,提高交付效率

  • 多租户: 支撑微服务合并部署,提高部署密度和 RPC 效率

  • Wisp 协程: 提高微服务的吞吐量


更多 Alibaba Dragonwell 的信息可以在 Dragonwell 官网 http://dragonwell-jdk.io/ 看到。


2020-09-14 10:002867

评论

发布
暂无评论
发现更多内容

第五届“强网”拟态防御国际精英挑战赛在南京举行

科技热闻

专科非科班怎么选择培训机构

小谷哥

北京哪家web前端开发机构比较好?

小谷哥

5分钟带你彻底掌握async底层实现原理!

千锋IT教育

AH协议

穿过生命散发芬芳

12月月更 AH协议

socket是并发安全的吗

C++后台开发

网络编程 socket 多线程 TCP/IP Linux服务器开发

极光笔记 | 以静制动:行为触发营销助力用户转化

极光JIGUANG

营销 运营 消息推送 用户运营

零基础学web前端,哪些培训机构比较好

小谷哥

通过WSL2运行GUI程序

吴脑的键客

WSL2 GUI

聊聊产品中的状态机设计

产品海豚湾

产品经理 产品设计 产品开发 需求分析 主业务流程梳理

2022-12-15:寻找用户推荐人。写一个查询语句,返回一个客户列表,列表中客户的推荐人的编号都 不是 2。 对于示例数据,结果为: +------+ | name | +------+ | Wil

福大大架构师每日一题

数据库· 福大大

ToB业务迎来连续增长,腾讯云的华丽转身

ToB行业头条

漏洞挖掘之命令注入漏洞

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 漏洞挖掘

当打造一款极速湖分析产品时,我们在想些什么

StarRocks

数据湖 湖仓一体

java软件培训班毕业后找工作吗

小谷哥

chatGPT的爆火,是计算机行业这次真的“饱和”了?

千锋IT教育

openEuler 倡议建立 eBPF 软件发布标准

openEuler

开源 云原生 操作系统 内核 ebpf

2021最新百度Java岗四轮面试题,(三轮技术面+一轮HR面)

钟奕礼

Java 程序员 java面试 java编程

2021最强网易Java岗面试题,(实战篇)进大厂必备~不看后悔

钟奕礼

Java 程序员 java面试 java编程

互联网时代,云计算的 6 大特征

Finovy Cloud

云计算 云渲染

行业分析| 智慧头盔在快对讲上的应用与实践

anyRTC开发者

音视频 智能设备 视频通话 快对讲 智慧头盔

瓴羊Quick BI 填报组件让数据分析和可视化呈现轻而易举

对不起该用户已成仙‖

节能降耗 | AIRIOT智慧电力综合管理解决方案

AIRIOT

物联网 智慧电力

mysql转国产数据库Gbase 8s 常见函数脚本

@下一站

数据库 12月日更 12月月更 Gbase8s 国产软件

可视化:数据可视化发展史

Data 探险实验室

数据分析 可视化 数据可视化

最新2021快手面试Java岗面经,成功手拿offer,开心到飞

钟奕礼

Java 程序员 Java 面试 java编程

跬智信息(Kyligence)荣登「甲子20」中国数据智能领域最具商业潜力科技企业榜

Kyligence

大数据 数据分析 数据智能 指标中台

学习大数据该怎么选择培训机构?

小谷哥

从vivo的创新方法论中,读懂高端突破的“因果”

脑极体

阿里三面,讲讲不同场景下并发Map容器最优使用。凉凉送给自己

钟奕礼

Java 程序员 Java 面试 java编程

低代码实现探索(五十四)低代码的描述文本

零道云-混合式低代码平台

云时代,JAVA何去何从?_云原生_梁希_InfoQ精选文章