构建适用于 Amazon Graviton 的 Rust 应用程序
本教程中使用的示例代码来自 GitHub
如今,各类企业都在将可持续发展作为其业务发展的关键目标,目的是提高运营效率并降低成本,同时减少碳排放。实现这些可持续发展目标意味着业务各个层面都要进行变革,在此过程中中应用程序和软件开发是重点。对于 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 技术指南存储库,并立即开始迁移您的应用程序。