在使用Graviton处理器的ARM架构的EC2构建JAVA应用

一、背景

AWS Graviton是AWS推出的ARM架构处理器,目前已经在AWS中国区域、全球区域大规模可用。使用Graviton处理器的EC2机型,以及基于Graviton处理器的托管服务包括RDS、Redis、OpenSearch,可获得比同配置的Intel处理器机型更高的性能,且同配置对比成本更低。

更多信息可参考:

https://aws.amazon.com/cn/ec2/graviton/
https://aws.amazon.com/cn/campaigns/graviton/

本文将展示Java的跨平台特性,即可以在ARM架构的EC2上构建Java应用,也可以在Intel处理器上构建好JAR包后,直接复制到ARM架构上运行。

二、在使用Graviton处理器的ARM架构EC2上构建Java应用

1、使用Amazon Linux 2023操作系统创建EC2

创建一台规格为t4g.medium对应2vCPU/4GB的EC2机型,操作系统选择Amazon Linux 2023系统。选择Amazon Linux 2023作为操作系统而不是选择Amazon Linux 2(兼容CentOS7)和Ubuntu(ARM64版)等其他系统的原因是:Amazon Linux 2023为ARM架构处理器做了深度优化,可获得比其他OS的ARM发型版更好的性能。

创建完毕后,通过SSH登陆到这个Linux上。

执行如下命令:

yum update -y
yum install -y git tmux

为了防止网络导致SSH断线使得程序失败,可执行tmux命令启动虚拟终端。这样即便SSH断开,也可以通过tmux ls命令查询之前后台运行的会话,并通过tmux attach命令来恢复之前断线的SSH会话。如果之前有多个tmux会话,还可以通过tmux attach-session -t 0这样的命令选择连接到特定编号的会话。

2、准备Java环境安装JDK和Maven

执行如下命令:

yum search java-1

这样将返回所有Java版本包括Java 1.8/11/18。返回清单如下:

Last metadata expiration check: 1:43:23 ago on Fri Jun 16 05:43:42 2023.
===================================================================================================== Name Matched: java-1 ======================================================================================================
java-1.8.0-amazon-corretto.aarch64 : Amazon Corretto runtime environment
java-1.8.0-amazon-corretto-devel.aarch64 : Amazon Corretto development environment
java-11-amazon-corretto.aarch64 : Amazon Corretto development environment
java-11-amazon-corretto-devel.aarch64 : Amazon Corretto 11 development tools
java-11-amazon-corretto-headless.aarch64 : Amazon Corretto headless development environment
java-11-amazon-corretto-javadoc.aarch64 : Amazon Corretto 11 API documentation
java-11-amazon-corretto-jmods.aarch64 : Amazon Corretto 11 jmods
java-17-amazon-corretto.aarch64 : Amazon Corretto development environment
java-17-amazon-corretto-devel.aarch64 : Amazon Corretto 17 development tools
java-17-amazon-corretto-headless.aarch64 : Amazon Corretto headless development environment
java-17-amazon-corretto-javadoc.aarch64 : Amazon Corretto 17 API documentation
java-17-amazon-corretto-jmods.aarch64 : Amazon Corretto 17 jmods

Amazon Corretto 是开放 Java 开发工具包 (OpenJDK) 的免费、多平台、生产就绪型发行版。Corretto 提供长期支持,其中包括性能增强和安全修复。亚马逊在内部的数千种生产服务上运行 Corretto,并且 Corretto 已被证明能够兼容 Java SE 标准。借助 Corretto,您可以在常用操作系统(包括 Linux、Windows 和 macOS)上开发和运行 Java 应用程序。

执行如下命令搜索可用的Maven版本:

yum search maven-amazon

返回结果如下:

Last metadata expiration check: 1:44:56 ago on Fri Jun 16 05:43:42 2023.
================================================================================================== Name Matched: maven-amazon ===================================================================================================
maven-amazon-corretto11.noarch : Amazon Corretto 11 binding for Maven
maven-amazon-corretto17.noarch : Amazon Corretto 17 binding for Maven
maven-amazon-corretto8.noarch : Amazon Corretto 8 binding for Maven

本文以Java11为例,执行如下命令安装JDK和Maven:

yum install -y java-11-amazon-corretto maven-amazon-corretto11 

3、构建测试应用

接下来从Graviton University Workshops下载代码:

git clone https://github.com/nwcd-samples/GravitonDemo.git
cd GravitonDemo/graviton-demo-springboot

这个测试应用的作用是在WEB页面上打印当前运行环境所在EC2的规格、机型、操作系统版本和所在Region和可用区。执行如下命令构建(请注意当前执行目录必须是graviton-demo-springboot):

mvn package

注意:如果您的实验环境在中国区,可使用中国区特定Maven镜像提高下载速度。请参考下一小节。

构建完毕后,在当前目录下的target目录中,graviton2-demo-0.0.1-SNAPSHOT.jar文件。

4、在中国区域构建时候使用Maven镜像加速(可选)

如果是在AWS海外环境构建,不需要考虑网络因素。如果在国内构建,那么从Apache的Maven官方下载速度可能收到跨国网络限制。此时建议使用Maven镜像。

执行如下命令编辑Maven配置文件。

vim /etc/maven/settings.xml

找到<mirros>章节的配置,加入如下一段:

    <mirror>
        <id>aliyun_nexus</id>
        <mirrorOf>*</mirrorOf>
        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    </mirror>

添加后的整个mirrors章节的配置格式如下:

  <mirrors>
    <!-- mirror
     | Specifies a repository mirror site to use instead of a given repository. The repository that
     | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used
     | for inheritance and direct lookup purposes, and must be unique across the set of mirrors.
     |
    <mirror>
      <id>mirrorId</id>
      <mirrorOf>repositoryId</mirrorOf>
      <name>Human Readable Name for this Mirror.</name>
      <url>http://my.repository.com/repo/path</url>
    </mirror>
     -->
    <mirror>
      <id>maven-default-http-blocker</id>
      <mirrorOf>external:http:*</mirrorOf>
      <name>Pseudo repository to mirror external repositories initially using HTTP.</name>
      <url>http://0.0.0.0/</url>
      <blocked>true</blocked>
    </mirror>
    <mirror>
        <id>aliyun_nexus</id>
        <mirrorOf>*</mirrorOf>
        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    </mirror>
  </mirrors>

保存退出窗口。如果之前有构建过,执行如下命令可清除缓存。

mvn dependency:purge-local-repository

然后正常构建应用(请注意当前执行目录必须是graviton-demo-springboot):

mvn package

构建完毕后,在当前目录下的target目录中,graviton2-demo-0.0.1-SNAPSHOT.jar文件。

5、在本机上测试Java应用运行

在当前目录下,执行如下命令即可启动应用。

java -jar target/graviton2-demo-0.0.1-SNAPSHOT.jar

启动成功后,返回如下。服务监听在8080端口。

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.7.8)

2023-06-16 07:31:55.473  INFO 49273 --- [           main] c.e.g.Graviton2DemoApplication           : Starting Graviton2DemoApplication v0.0.1-SNAPSHOT using Java 17.0.7 on ip-172-31-14-80.cn-northwest-1.compute.internal withPID 49273 (/root/GravitonDemo/graviton-demo-springboot/target/graviton2-demo-0.0.1-SNAPSHOT.jar started by root in /root/GravitonDemo/graviton-demo-springboot)
2023-06-16 07:31:55.477  INFO 49273 --- [           main] c.e.g.Graviton2DemoApplication           : No active profile set, falling back to 1 default profile: "default"
2023-06-16 07:31:56.934  INFO 49273 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2023-06-16 07:31:56.946  INFO 49273 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-06-16 07:31:56.947  INFO 49273 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.71]
2023-06-16 07:31:57.048  INFO 49273 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-06-16 07:31:57.048  INFO 49273 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1465 ms
2023-06-16 07:31:57.618  WARN 49273 --- [           main] ion$DefaultTemplateResolverConfiguration : Cannot find template location: classpath:/templates/ (please add some templates, check your Thymeleaf configuration, or setspring.thymeleaf.check-template-location=false)
2023-06-16 07:31:57.693  INFO 49273 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-06-16 07:31:57.710  INFO 49273 --- [           main] c.e.g.Graviton2DemoApplication           : Started Graviton2DemoApplication in 2.98 seconds (JVM running for 3.565)

现在使用浏览器访问http://本机公网IP:8080端口,即可正常打开应用。

请注意,请事先做好如下准备,才能从互联网使用浏览器访问本机8080端口:

  • 本EC2位于Public Subnet,具有公网IP或者弹性EIP
  • 本机的安全规则组允许来自互联网的请求访问本机TCP协议8080端口
  • 中国区账号已经通过ICP备案(或者通过ICP白名单),海外区域账号不需要此步骤

在满足以上准备的情况下,浏览器访问成功。如下截图。

由此可以看到在使用Graviton处理器的ARM架构EC2上正常使用Java应用。当应用运行在ARM架构上时候,会显示Instance Type一项为当前正在使用的机型是使用Graviton处理器的t4g.medium

三、将X86_64架构上构建的Java应用部署到ARM架构

1、在X86_64环境上完成构建

创建一台规格为t3.medium的EC2。然后按照以上流程,在X86_64架构上运行构建,并在target目录中获得名为graviton2-demo-0.0.1-SNAPSHOT.jar的JAR包。此JAR包文件名叫做graviton2-demo-0.0.1-SNAPSHOT.jar但其实是在X86_64平台构建的。因此可将其改名为intel.jar。然后还会将其从X86_64架构的EC2上复制出来。

2、在X86_64环境上运行刚构建的应用

按照相同的流程,测试构建好的JAR包可以在X86_64平台上运行。执行如下命令:

java -jar intel.jar

注意此时应用会显示Instance Type一项为当前正在使用的机型是使用Intel处理器的t3.medium。如下截图。

在确认应用正常后,将intel.jar从X86_64架构的EC2上复制出来,并上传到ARM架构的EC2上。

3、在ARM平台上运行X86_64平台上构建的JAR包

登陆到前文构建Java应用使用的t4g.medium这台EC2,前文已经安装好Amazon Corretto(OpenJDK)的环境上,因此可运行从X86_64平台复制过来的JAR包。

java -jar intel.jar

返回结果中可看到应用正常启动。

root@ip-172-31-14-80 ~]# aws s3 cp s3://lxy-sa-software/intel.jar .
download: s3://lxy-sa-software/intel.jar to ./intel.jar
[root@ip-172-31-14-80 ~]# java -jar intel.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.7.8)

2023-06-16 07:45:46.042  INFO 49750 --- [           main] c.e.g.Graviton2DemoApplication           : Starting Graviton2DemoApplication v0.0.1-SNAPSHOT using Java 17.0.7 on ip-172-31-14-80.cn-northwest-1.compute.internal withPID 49750 (/root/intel.jar started by root in /root)
2023-06-16 07:45:46.045  INFO 49750 --- [           main] c.e.g.Graviton2DemoApplication           : No active profile set, falling back to 1 default profile: "default"
2023-06-16 07:45:47.567  INFO 49750 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2023-06-16 07:45:47.579  INFO 49750 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-06-16 07:45:47.579  INFO 49750 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.71]
2023-06-16 07:45:47.664  INFO 49750 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-06-16 07:45:47.664  INFO 49750 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1501 ms
2023-06-16 07:45:48.206  WARN 49750 --- [           main] ion$DefaultTemplateResolverConfiguration : Cannot find template location: classpath:/templates/ (please add some templates, check your Thymeleaf configuration, or setspring.thymeleaf.check-template-location=false)
2023-06-16 07:45:48.297  INFO 49750 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-06-16 07:45:48.316  INFO 49750 --- [           main] c.e.g.Graviton2DemoApplication           : Started Graviton2DemoApplication in 2.954 seconds (JVM running for 3.603)

然后通过浏览器测试,可看到其访问正常。当应用运行在ARM架构上时候,会显示Instance Type一项为当前正在使用的机型是使用Graviton处理器的t4g.medium

由此可看到,在X86_64平台上构建的Java应用可直接部署在使用Graviton处理器的ARM架构的EC2上。

四、参考文档

Amazon Corretto介绍

https://aws.amazon.com/cn/corretto/

Amazon Corretto 下载(OpenJDK发行版)

https://docs.aws.amazon.com/corretto/latest/corretto-17-ug/downloads-list.html

使用网易Maven镜像

https://mirrors.163.com/.help/maven.html

Graviton University Workshops

https://catalog.us-east-1.prod.workshops.aws/workshops/238ba0d4-8abe-4d35-8740-0e3218cb5844/zh-CN/