拼不过 GO?阿里如何重塑云上的 Java

软件结
• 阅读 322

简介:Java 诞生于20年前,拥有大量优秀的企业级框架,践行 OOP 理念,更多体现的是严谨以及在长时间运行条件下的稳定性和高性能。反观如今,在要求快速迭代交付的云场景下,语言的简单性似乎成了首要的要求,而传统的 Java 语言显得有一些过于重量了。今天,阿里 JVM 团队技术专家郁磊(花名:梁希)分享 JVM 团队是如何面对和处理集团巨大的业务规模和复杂的业务场景的。

作者 | 郁磊

音乐无国界,但是音乐人有国界。

云原生亦如此。虽没有限定的编程语言,但应用所使用的编程语言已经决定了应用部署运行的行为。

ElasticHeap

Java 常因为耗资源而受诟病,其中最显著一点就是 Heap 对内存的占用,即便没有请求在处理也没有对象分配,进程仍然会保留完整的堆内存空间,保障 GC 进行分配内存和操作内存的快速敏捷。

AJDK ZenGC/ElasticHeap 双十一全面支持核心链路上百应用和数十万实例。

拼不过 GO?阿里如何重塑云上的 Java

JDK12 开始支持固定时间的触发 concurrent mark 并在 remark 中收缩 Java 堆归还内存的功能,然而并未解决在 stw 中增加暂停时间的问题,因此无法在每次 young GC 时做内存归还。ElasticHeap 在并发异步线程中完成内存处理反复 map/unmap 以及 page fault 的开销,因此任意一次 young GC 都可以敏捷的及时归还内存,或重新恢复内存使用。

ElasticHeap 阿里巴巴实战

ElasticHeap场景1:可预测的流量高峰

拼不过 GO?阿里如何重塑云上的 Java

拼不过 GO?阿里如何重塑云上的 Java
![1204.jpg]

ElasticHeap 场景 2 :单机运行多个 Java 实例

多个 Java 实例接受的流量任务较为随机,峰值不会重叠,在闲时可以有效降低多个实例整体的内存占用,提高部署密度。

(https://ucc.alicdn.com/pic/developer-ecology/951b1a96e0284df0bac3baee477a697b.jpg))

双11验证核心交易系统使用 ElasticHeap 进行低功耗模式运行,大幅降低 WSS(Working Set Size) 规模的实例。

拼不过 GO?阿里如何重塑云上的 Java

静态编译

很多云上的新应用不约而同地选择了 Go 语言,很大的原因是 Go 应用对运行时没有依赖,静态编译的程序启动速度快,也不需要通过 JIT 来预热。在阿里有大量 Java 代码的前提下,我们是如何为 Java 注入这方面的能力的呢?

Java 静态编译技术是一种激进的 AOT 技术,通过单独的编译阶段将 Java 程序编译为本地代码,在运行时无需传统 Java 虚拟机和运行时环境,只需操作系统类库支持即可。其工作基本原理如下图所示。静态编译技术实现了 Java 语言与原生 native 程序的“合体”,将原本的 Java 程序编译成为了一个自举的具有 Java 行为的原生 native 程序,由此兼有 Java 程序和原生 native 程序的优点。

拼不过 GO?阿里如何重塑云上的 Java

JVM 团队与 SOFAStack 团队密切合作,在中间件应用上率先实现静态编译的落地。将一个应用的启动速度从 60 秒优化到 3.8 秒,双十一期间静态编译的应用运行稳定,没有故障, GC 停顿时间在 100 毫秒,在业务允许范围之内,内存占用和 RT 与传统 Java 应用持平。

综上所述,静态编译的应用在稳定性、资源占用、RT 响应等各方面指标与传统 Java 应用基本持平的状况下,将启动时间降低了 2000% 。

Wisp2

当你用时下最酷炫的 Vert.X 开发一个简单的 Web 服务,准备体验一下最强的性能, QA 同学拿来一台 1C 2G 的容器让你压一下,你却发现你怎么也拼不过别人 Go 应用。研究之后发现,原来协程模型在这样的少核心的情况下性能要好很多。是时代变了, Java 落伍了?

AJDK Wisp2 回答了这个问题:Java 同样可以拥有高性能的协程。今年是 Wisp2 大规模上线的第一年, Wisp2 具有如下特点:

在整个Java runtime中支持了协程调度,线程(比如 Socket.getInputStream().read() )阻塞会变成更轻量的协程切换。
完全兼容 Thread API ,在开启 Wisp2 的 JDK 中,Thread.start() 实际创建的是一个协程(轻量级线程),可以类比 Go 只提供协程关键字 go 而没有暴露线程接口;我们同样只提供创建协程的方式,应用可以透明切换到协程。
支持 work stealing ,调度策略特别适合 web 场景,在高压力下调度开销极小。

在今年双十一, Wisp 支持了上百应用,十万级容器,其中 90% 的容器已经升级到 Wisp2 。

拼不过 GO?阿里如何重塑云上的 Java

我们可以看到峰值附近, Wisp2 机器的 CPU 要低 7%( Wisp1 更低,Wisp2的取向是 RT ,因此 CPU 会高一些)左右,这主要是轻量级调度所节省的 sys CPU 。 0 点的 CPU 是相等的,这也说明一点:Wisp2 解决的是调度开销,当 CPU 低,调度没有压力时是看不出差距的。

拼不过 GO?阿里如何重塑云上的 Java

从 RT 角度看, Wisp2 机器的 RT 要低 20% 左右, RT 减少明显的一个原因是这批机器的 CPU 压力很大,协程的调度优势更容易体现出来。这样的优势可以帮助系统摸高到更高的水位,整体地提高利用率而担心 RT 过高导致系统雪崩。

FDO

双十一正零点相对后面几分钟会有一个明显的 CPU 峰值,根据数据分析,主要原因是双十一零点触发了 JIT 编译。举个例子,程序里有逻辑:

if (is1111(LocalDate.now())) {
   branch1
} else {
   branch2 
}

假设预热时一直在走 branch2 ,那么 JIT 有理由相信后续基本也都会走 branch2 ,而不会对 branch1编译。在零点时,我们进入 branch1 ,此时就需要触发退优化重新编译方法。我们来看 AJDK 如何通过 profiling 解决这个问题。

退优化原理及其危害

JDK 运行代码的时候,采用分层编译的方式对 Java 方法进行动态编译。在最高等级(峰值性能最好)的编译中,出于性能的考虑,编译的时候会根据收集的信息做一些比较乐观的假设,一旦这些假设条件不满足了,就会出现退优化的现象。比如某个热点方法中某段代码仅会在双十一中执行,那么在预热过程中这段代码不会被编译,双十一到来时这段代码一旦被执行,就会触发整个方法的退优化。

发生退优化有两个方面的负面影响,一是需要运行的方法由高效率的编译执行变成了解释执行,运行速度降低百倍以上;二是流量高峰期退优化的方法会很快被重新编译,编译线程会消耗 CPU 。因此在双十一这种流量短时间剧增且与预热流量不太一样的场景下,退优化的危害会特别明显。

通过 FDO 减少退优化

FDO 是 feedback directed optimization 的缩写,即参考以往 JVM 运行时的编译信息,指导本次运行时进行更好的编译。具体的,我们采用了两个层面的方法来减少退优化。

将每次运行时的退优化信息记录到文件中,下次运行时读取这个文件,在决定是否做乐观假设的时候参考文件中的信息做判断,从而减少退优化的概率。
信息显示出现最多的退优化与 if-else 相关,占总数量的一半以上。我们提供了一个方法根据以往出现 if-else 退优化的信息,关闭某个路径上所有相关的乐观假设。

双十一中 FDO 的效果

FDO 今年双十一上线,目标解决两个问题:

阅读原文查看FDO 的实战效果https://developer.aliyun.com/article/738762?utm_content=g_1000095976

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Peter20 Peter20
4年前
mysql中like用法
like的通配符有两种%(百分号):代表零个、一个或者多个字符。\(下划线):代表一个数字或者字符。1\.name以"李"开头wherenamelike'李%'2\.name中包含"云",“云”可以在任何位置wherenamelike'%云%'3\.第二个和第三个字符是0的值wheresalarylike'\00%'4\
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Stella981 Stella981
4年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
4年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这