openjdk performance comparison - openjdk 性能比较

本文将对 openjdk 的发行版:zulu jdk、JetBrains runtime、Amazon corretto、AdoptOpenJDK 以及 Dragonwell 的性能进行全方位比较,使用 cadvisor 收集 docker 的性能数据,然后存储到 prometheus 最后由 grafana 呈现出来。

首先,需要监控 docker 的性能数据,这部分请参考之前的文章:grafana + prometheus + cadvisor 监控 docker,本文书接上回,在上一篇,我已经说过了 如何监控 docker 的性能数据,并且还给了一个截图,现在,我假设你已经知道如何 监控 docker 的性能数据,接下来要做的 就是 部署多个 应用,然后进行压测,最后查看压测数据以及性能数据。

1、新建一个 spring boot 版的 hello world,我的代码大致如下:

@RestController
@RequestMapping("/test")
public class TestController {

    private int count = 1;

    private static final Logger logger = LoggerFactory.getLogger(TestController.class);

    @RequestMapping("/test")
    public Map<String, Object>test() {
        Map<String, Object> map = new HashMap<>();
        map.put("message", "success");
        map.put("count", count);
        count++;
        logger.info("result is {}", map);
        return map;
    }
}

2、新建 6 个 docker,命令如下:

docker run -m 1024m --name zulujdk -v /home/android/test/zulujdk:/var/apps -p 8100:8080 -itd ubuntu:18.04 /bin/bash /var/apps/startup.sh
docker run -m 1024m --name JetBrains -v /home/android/test/JetBrains:/var/apps -p 8110:8080 -itd ubuntu:18.04 /bin/bash /var/apps/startup.sh
docker run -m 1024m --name awsCorretto -v /home/android/test/awsCorretto:/var/apps -p 8120:8080 -itd ubuntu:18.04 /bin/bash /var/apps/startup.sh
docker run -m 1024m --name aliopenjdk -v /home/android/test/aliopenjdk:/var/apps -p 8130:8080 -itd ubuntu:18.04 /bin/bash /var/apps/startup.sh
docker run -m 1024m --name aliopenjdk2 -v /home/android/test/aliopenjdk2:/var/apps -p 8140:8080 -itd ubuntu:18.04 /bin/bash /var/apps/startup.sh
docker run -m 1024m --name AdoptOpenJDK -v /home/android/test/AdoptOpenJDK:/var/apps -p 8150:8080 -itd ubuntu:18.04 /bin/bash /var/apps/startup.sh

这里,你需要将 /home/android/test 的路径换为你自己的实际路径,在 test 目录下,我有 6个对应工作目录,每个工作目录结构一致,分别为 jdk,startup.sh 以及 jar 包

3、startup.sh 如下:

#!/bin/bash
cd /var/apps/
rm -rf ./nohup.out
rm -rf ./log.txt
./jdk/bin/java -Xms1024m -Xmx1024m -jar ./openjdk-0.0.1-SNAPSHOT.jar >./log.txt 2>&1

4、压测命令:

#!/bin/bash
calledAt=$(date +"%Y-%m-%d %H:%M:%S")
echo 'called at '$calledAt' sleep 10m now...'
sleep 5m
beginAt=$(date +"%Y-%m-%d %H:%M:%S")
echo 'begin at '$beginAt
for i in {0..4}; do
  url='http://openjdk.kpromise.top/test/test'
  wrk -t1000 -c10000 -d2s $url
  sleep 5s
done
echo -e 'warm up finish...\n\n\n'
sleep 30s
now=$(date +"%Y-%m-%d %H:%M:%S")
echo 'begin local test '$now
for port in {0..5}; do
  for index in {0..4}; do
    url='http://localhost:81'$port'0/test/test'
    wrk -t1000 -c10000 -d2s $url
    sleep 5s
  done
done
endAt=$(date +"%Y-%m-%d %H:%M:%S")
echo 'endAt '$endAt

5、你可能已经注意到了,这里 aliopenjdk 有两个,这两个分别为 正常使用(对应 aliopenjdk),以及使用 JWarmup 技术(对应aliopenjdk2),后者是先 JWarmup 了一下,前者没有。

Dragonwell JWarmup spring boot 应用

至于 JWarmup 就是先启动一个 docker 不过,startup.sh 就如下了:

#!/bin/bash
cd /var/apps/
rm -rf ./nohup.out
rm -rf ./log.txt
./jdk/bin/java -Xms1024m -Xmx1024m -XX:-ClassUnloading -XX:-CMSClassUnloadingEnabled -XX:-ClassUnloadingWithConcurrentMark -XX:CompilationWarmUpLogfile=./jwarmup.log -XX:+CompilationWarmUpRecording -XX:CompilationWarmUpRecordTime=300 -jar ./openjdk-0.0.1-SNAPSHOT.jar >./log.txt 2>&1

然后对这个 容器 进行压测,大概5分钟后 生成 jwarmup.log 文件,然后删除 docker 容器,并修改 startup.sh 如下:

#!/bin/bash
cd /var/apps/
rm -rf ./nohup.out
rm -rf ./log.txt
./jdk/bin/java -Xms1024m -Xmx1024m -XX:+CompilationWarmUp -XX:-TieredCompilation -XX:CompilationWarmUpLogfile=./jwarmup.log -XX:CompilationWarmUpDeoptTime=0 -jar ./openjdk-0.0.1-SNAPSHOT.jar >./log.txt 2>&1

JWarmup spring boot 应用的流程等于是 先在 测试服 或者预发布环境(如果有)上生成文件,然后在正式环境使用这个文件。生成文件你需要在 java 命令后 添加如下参数:

-XX:-ClassUnloading -XX:-CMSClassUnloadingEnabled -XX:-ClassUnloadingWithConcurrentMark -XX:CompilationWarmUpLogfile=jwarmup.log -XX:+CompilationWarmUpRecording -XX:CompilationWarmUpRecordTime=300

使用这个文件(正式环境),你需要在 java 命令后添加如下参数:

-XX:+CompilationWarmUp -XX:-TieredCompilation -XX:CompilationWarmUpLogfile=jwarmup.log -XX:CompilationWarmUpDeoptTime=0

如果需要自定义 JVM 的编译时机,你需要调用:

com.alibaba.jwarmup.JWarmUp.notifyApplicationStartUpIsDone()

具体请参考:dragonwell8 JWarmup 官方文档

我的测试结果大致如下:

openjdk 各个发行版 性能比较

压测结果大致如下图:

openjdk 各个版本性能评测

第一、二列是每秒能处理的请求数,即 RPS ( requests per second )  ,其中,第一列数据是去掉最大值、最小值后求的平均值,第二列数据是全部数据求的平均值,第三列是 openjdk 发行版名称,第四列是 当前的 内存占用,第五列是平均内存占用,最后一列是平均 cpu 占用。出乎意外的是 Dragonwell 完胜其余 几个,差距较大,而其余几个 openjdk 差距则很小,之所以用出乎意料是因为之前用 ab 压测时 zulu openjdk 完胜,Dragonwell 则占用更多内存但是并发却低,考虑到 ab 压测有点 out,而 wrk 则更加现代化,另外,ab 压测 测试出来的数据偏低,测试期间 cpu 占用也比 wrk 低。鉴于两次结果不一致,我又测试了一次,这次的脚本如下:

#!/bin/bash
beginAt=$(date +"%Y-%m-%d %H:%M:%S")
echo 'begin at '$beginAt
for port in {0..5}; do
  for index in {0..2}; do
    url='http://localhost:81'$port'0/test/test'
    wrk -t1000 -c10000 -d2s $url
    sleep 5s
  done
done
endAt=$(date +"%Y-%m-%d %H:%M:%S")
echo 'endAt '$endAt

cpu、内存占用如下

cpu 占用

并发测试结果请查看:https://cdn.kpromise.top/blog/openjdk1024-result.txt  ,整体而言,Dragonwell 并发性能明显优于其余 四个,其中,使用 JWarmup 后 并发更好,但是 cpu、内存占用 也别指望会更低,可能随着时间会变得更大。当内存已经达到最大值(我限制为1G)后,Dragonwell 的并发性能依旧优于其余四个。

本博客若无特殊说明则由 full-stack-trip 原创发布
转载请点名出处:编程生涯 > openjdk performance comparison - openjdk 性能比较
本文地址:https://www.kpromise.top/openjdk-performance-comparison/

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注