构建适用于 Amazon Graviton 的 Rust 应用程序

了解如何将 Rust 应用程序从基于 x86 的 Amazon EC2 实例迁移至基于 ARM64 的 Graviton EC2 实例,以提高应用程序可持续性并降低成本
发布时间:2023 年 7 月 20 日
Graviton
Rust
可持续性
成本优化
部署
迁移
ARM64
EC2
教程
亚马逊云科技
Olawale Olaleye
亚马逊云科技使用经验
200 - 中级
完成所需时间
30 分钟
前提条件

注册 / 登录 亚马逊云科技账户

示例代码

本教程中使用的示例代码来自 GitHub

上次更新时间
2023 年 7 月 20 日

如今,各类企业都在将可持续发展作为其业务发展的关键目标,目的是提高运营效率并降低成本,同时减少碳排放。实现这些可持续发展目标意味着业务各个层面都要进行变革,在此过程中中应用程序和软件开发是重点。对于 Rust 应用程序,实现可持续发展目标的一个简单方法是采用 Amazon Graviton 实例。Amazon Graviton 处理器由亚马逊云科技设计,旨在为 Amazon EC2 中运行的云工作负载提供极具性价比的选择。
在本教程中,我将逐步介绍如何将当前在 x86 实例上运行的现有应用程序迁移至 Amazon Graviton 驱动的实例,以提高 Rust 应用程序的可持续性。本指南包括创建亚马逊云科技的计费资源。

学习内容

  • 如何构建基于 Amazon Graviton 的 Rust 应用程序
  • 如何将现有 Rust 应用程序迁移至 Amazon Graviton

设置开发环境

IAM 和 DynamoDB 设置

本教程将利用 DynamoDB 表作为数据存储。要在 DynamoDB 中进行身份验证,必须使用 IAM 凭证。在本教程中,我们将使用附加到 EC2 实例的 IAM 角色获取 DynamoDB 的有效凭证。为了简化设置,我提供了 Terraform、CloudFormation 和 Amazon CLI 脚本供您使用。这些脚本都可以在 git 存储库的 infrastructure 目录中找到,我们将在本教程中使用这些脚本。您可以选择您的常用工具来部署相应的脚本。这些脚本将创建以下资源:

  • IAM 角色,名称为 rust-link-shortener-ec2-role
  • 允许 DynamoDB 操作的 IAM 策略
  • DynamoDB 表,名称为 url_shortener

EC2 设置

为了演示如何将 Rust 应用程序迁移至基于 Amazon Graviton 的实例,我使用 Rust 构建了一个简单的短链接转换器应用程序。我并非前端开发人员,因此我将依靠 cURL 来与应用程序的 API 进行交互。该应用程序是用撰写本文时新发布的 Rust 版本和 Rocket 0.5.0-rc3 编写的。该应用程序为缩短的每个 URL 生成一个包含 8 个字符的唯一字符串,并将原始 URL 和这个包含 8 个字符的字符串存储在 Amazon DynamoDB 表中。该代码不适用于生产环境,仅作为示例提供。

在本演示中,启动两个运行 Ubuntu 22.04 的 EC2 实例。确保在设置过程中选择 rust-link-shortener-ec2-role IAM 角色。如果不使用此角色,您的实例将无法访问 DynamoDB。第一个实例为 c5.xlarge 实例类型,第二个实例为 c6g.xlarge 实例类型。这两个实例运行后,连接到每个实例,并使用以下命令安装 Rust:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

安装 build-essential 包,以获得我们稍后要安装的任何模块所需的编译器和链接器。

sudo apt update
sudo apt install build-essential

代码签出

要签出示例项目,请前往 building-rust-applications-for-aws-graviton,然后使用以下命令克隆该存储库:

git clone https://github.com/build-on-aws/building-rust-applications-for-aws-graviton

查看 x86 实例和 Amazon Graviton 实例上的代码。您现在应该有一个 rust-link-shortener 目录,其中包含所有相应的代码。

针对 X86 编译

在 c5.xlarge 实例上,前往 building-rust-applications-for-aws-graviton 目录,然后运行以下命令,构建应用程序:

cargo build --release

构建完成后,输出结果应该如下所示:

Finished release [optimized] target(s) in 2m 41s

real 2m41.674s
user 10m6.078s
sys 0m25.774s

前往 target/release 目录,rust-link-shortener 二进制文件将位于其中,且准备启动。要启动该文件,请运行命令 ./rust-link-shortener。为了完成本演示,将应用程序配置为在端口 8000 上运行,并侦听所有接口。

针对 Amazon Graviton 编译 (ARM64)

在 c6g.xlarge 实例上,前往 building-rust-applications-for-aws-graviton 目录,然后运行以下命令,构建应用程序:

cargo build --release

构建完成后,输出结果应该如下所示:

Finished release [optimized] target(s) in 3m 27s

real 3m27.946s
user 12m57.304s
sys 0m26.632s

前往 target/release 目录,rust-link-shortener 二进制文件将位于其中,且准备启动。要启动该文件,请运行命令 ./rust-link-shortener。为了完成本演示,将应用程序配置为在端口 8000 上运行,并侦听所有接口。

测试应用程序

为了测试应用程序,我们将使用 cURL 发出一些示例请求,验证我们的应用程序是否正常运行。下面的所有命令都可以针对这两个 EC2 实例运行。

URL 短链接转换

以下命令可将 URL 转换为。我的实例使用 IP 地址 10.3.76.37,因此我在命令中使用该地址。确保将该 IP 地址替换为您的 EC2 实例的地址:

curl -X POST -d "https://aws.amazon.com/ec2/graviton/" http://10.3.76.37:8000/shorten_url -H 'Content-Type: application/json'

输出结果应如下所示:

https://myservice.localhost/rlbnDueu

URL 中的 rlbnDueu 是应用程序的标识符。

检索完整 URL

要检索原始 URL,我们需要向应用程序发出另一个请求,并将该值传递给 get_full_url API,如以下命令所示。

将 URL 短链接标识符替换为从上一个命令中获得的标识符,并确保您的 IP 地址正确无误。

curl -X GET -d "rlbnDueu" http://10.3.76.37:8000/get_full_url -H 'Content-Type: application/json'

输出结果应如下所示:

Your full URL is https://aws.amazon.com/ec2/graviton/

负载测试

每次进行软件或硬件更改时,都应该重新评估现有配置和假设,以确保充分享有新配置带来的益处。虽然全面的性能测试和优化不在本博客的讨论范围内,但您可以参阅 Amazon Graviton 技术指南中的全面的性能运行手册Rust 特定页面,而且亚马逊云科技团队也随时做好准备,帮助您解决任何问题。

在比较多个实例类型时,性能测试是关键。为了比较 c6g.xlarge 和 c5.xlarge 实例,我们将执行负载测试,以验证针对 Graviton 构建的应用程序是否按预期运行。我们在 GitHub 上的 Graviton 技术指南中讨论了各种负载测试方法,并建议使用 wrk2 等这样的框架。wrk2 是 wrk 的一个版本,该版本经过了修改,可以生成恒定的吞吐量负载,并报告不同百分位数的准确详细延迟。我决定继续使用 wrk2 测试我们应用程序的 shorten_url 函数,并在负载测试期间比较每秒总请求数以及每个百分位数的平均延迟。我在本指南中保持了负载测试的简单性,以说明测试的重要性。我将从与测试实例位于同一可用区的 c5.18xlarge 实例运行负载测试。我之所以要使用 c5.18xlarge 实例,是因为我知道该实例能够对我们的实例进行彻底的负载测试,因为该实例的大小比任何示例实例都大得多。

负载测试设置

第一步是签出 wrk2 存储库,并进行构建以供使用。

git clone git@github.com:kinvolk/wrk2.git
cd wrk2
make

由于我们的 shorten_url 函数使用 POST 方法并且需要一些数据,因此需要一个 lua 配置文件,以传递给 wrk2。我的 post.lua 文件包含以下内容:

wrk.method = "POST"
wrk.headers["content-type"] = "application/json"
wrk.body = "https://aws.amazon.com/ec2/graviton/"

运行负载测试

对于我们的示例应用程序,假设该应用程序在 65ms 内处理 99.9% 的请求。然后,我将对每个实例运行负载测试,看看每个实例在超过该延迟阈值之前每秒可以处理多少请求。首先,我使用以下命令对每个实例运行 5 分钟的负载测试。运行各个命令时,请确保 IP 地址正确。-c 参数控制在负载测试期间建立的连接数。-d 参数指定测试应运行的时长。-L 参数允许报告百分位数级的延迟数据统计。-R 参数指定运行负载测试时应处理的每秒请求数。-s 参数用于指定我们上面定义的 Lua 脚本。

#C5 Instance
./wrk -c120 -t60 -d 5m -L -R 13000 -s ./post.lua http://10.3.71.236:8000/shorten_url

#C6g Instance
./wrk -c120 -t60 -d 5m -L -R 13000 -s ./post.lua http://10.3.69.199:8000/shorten_url

运行此命令时,请确保 IP 地址正确。

初步结果

延迟百分位数 C5.xlarge C6g.xlarge
50 5.16ms 5.26ms
75 5.72ms 5.85ms
90 6.51ms 6.65ms
99 17.82ms 16.94ms
99.9 49.76ms 39.23ms
99.99 79.93ms 66.05ms
99.999 134.27ms 193.66ms
100 167.55ms 333.05ms

测试 Graviton 性能极限

我们还能加多少负载才能碰到极限?下面我们来看看。将 -R 参数调整为 15000,负载测试增加到每秒 800 个请求。

#C5 Instance
./wrk -c120 -t60 -d 5m -L -R 15000 -s ./post.lua http://10.3.71.236:8000/shorten_url

#C6g Instance
./wrk -c120 -t60 -d 5m -L -R 15000 -s ./post.lua http://10.3.69.199:8000/shorten_url
延迟百分位数 C5.xlarge C6g.xlarge
50 5.44s 5.47ms
75 8.00s 6.11ms
90 9.47s 7.08ms
99 11.20s 29.20ms
99.9 12.71s 65.47ms
99.99 13.82s 107.39ms
99.999 13.89s 447.74ms
100 13.90s 571.90ms

可以看到,Amazon Graviton 驱动的实例能够在每秒处理 15,000 个请求的同时,将延迟保持在目标 65ms。在如此大的负载下,Intel 驱动的实例确实开始受到影响。Amazon Graviton 实例为 Rust 应用程序提升了多达 40% 的性价比,同时与同类 EC2 实例相比,在获得相同性能的情况下,可节省多达 60% 的能源,从而提高了 Rust 应用程序的可持续性。

清理资源

我们已经完成了测试,可以清理我们在本教程中创建的所有资源了。确保终止您启动的任何 EC2 实例删除您的 DynamoDB 表,以避免产生额外费用。

总结

正如本教程所示,将 Rust 应用程序从 x86 EC2 实例迁移至 Amazon Graviton 驱动的实例简单易行。您现在可以尝试将您的 Rust 应用程序迁移至 Amazon Graviton 了!

如需了解常见的性能注意事项和其他信息,请访问 Github 上的 Graviton 技术指南存储库,并立即开始迁移您的应用程序。