低代码到底是不是行业毒瘤?一线大厂怎么做的?戳此了解>>> 了解详情
写点什么

现在开放 AWS Lambda Rust

2019 年 10 月 14 日

现在开放 AWS Lambda Rust


AWS Lambda 让开发人员可以轻松为几乎任何类型的应用程序或后端服务运行代码,而且全部无需管理。它刚刚推出了 Runtime API。Runtime API 定义了基于 HTTP 的 Lambda 编程模型规范,可通过任何编程语言实现。为了启动该 API,我们开放了 Rust 语言运行时源代码。Rust 是一种用于编写和维护快速、可靠且高效代码的编程语言。


新推出的 Rust 运行时让您可以轻松启动实现我们以下 Handler 类型的 Rust 函数:pub type Handler<E, O> = fn(E, Context) -> Result<O, HandlerError>。运行时依靠 Serde 来对事件与响应进行序列化和反序列化。如下示例:


#[macro_use]extern crate lambda_runtime as lambda;#[macro_use]extern crate serde_derive;#[macro_use]extern crate log;extern crate simple_logger;
use lambda::error::HandlerError;
use std::error::Error;
#[derive(Deserialize, Clone)]struct CustomEvent { #[serde(rename = "firstName")] first_name: String,}
#[derive(Serialize, Clone)]struct CustomOutput { message: String,}
fn main() -> Result<(), Box<dyn Error>> { simple_logger::init_with_level(log::Level::Info)?; lambda!(my_handler);
Ok(())}
fn my_handler(e: CustomEvent, c: lambda::Context) -> Result<CustomOutput, HandlerError> { if e.first_name == "" { error!("Empty first name in request {}", c.aws_request_id); return Err(c.new_error("Empty first name")); }
Ok(CustomOutput { message: format!("Hello, {}!", e.first_name), })}
复制代码


创建、构建和部署 Rust 函数

首先我们建议使用 Rust 的构建工具和包管理器 Cargo 来创建和构建新项目:


$ cd MY_WORKSPACE$ cargo new my_lambda_function --binCargo 会自动为新项目创建文件夹,以及在项目根目录下创建 Cargo.toml 文件。打开 Cargo.toml 文件,并在 [dependencies] 部分添加一个 lambda_runtime 包:
[dependencies]lambda_runtime = "0.1"
复制代码


此外,我们还将需要一些依赖项:Serde 用于对事件进行序列化(反序列化),log 和 simple_logger 用于输出日志。


serde = "^1"serde_json = "^1"serde_derive = "^1"log = "^0.4"simple_logger = "^1"
复制代码


还需在 Cargo.toml 文件中再进行一项设置。当配置为使用 Runtime API 的自定义运行时时,AWS Lambda 希望在部署包中包含名为 bootstrap 的可执行文件。我们可以配置 Cargo 来生成一个名为 bootstrap 的文件,不考虑包的名称。首先,在文件的 [package] 部分添加 autobins = false 设置。然后,在 Cargo.toml 的底部添加新的 [[bin]] 部分:


[[bin]]name = "bootstrap"
复制代码


我们已完成的 Cargo.toml 文件应如下所示:


[package]name = "my_lambda_function"version = "0.1.0"authors = ["me <my_email@my_server.com>"]autobins = false
[dependencies]lambda_runtime = "^0.1"serde = "^1"serde_json = "^1"serde_derive = "^1"log = "^0.4"simple_logger = "^1"
[[bin]]name = "bootstrap"path = "src/main.rs"
复制代码


接下来,打开 Cargo 在您项目的 src 文件夹中创建的文件 main.rs,将上述基本示例的内容复制并粘贴到该文件中。它应该会替换 Cargo 创建的存根 main 方法。设置好新的来源后,我们差不多准备好构建和部署 Lambda 函数了


在开始构建之前,我们需要确保 Rust 编译器的目标平台无误。AWS Lambda 在 Amazon Linux 环境中执行函数。除非您已在 x86 64bit Linux 环境中运行此教程,否则我们需要为 Rust 编译器添加新的目标环境,可以通过 Rustup 工具来更轻松地实现这一点。然后按照以下说明,在 Mac OS X 上编译基本示例。


在 Mac OS X 上编译

如果您尚未安装 rustup,则首先需要安装它。然后,添加目标 x86_64-unknown-linux-musl:


$ rustup target add x86_64-unknown-linux-musl
复制代码


在构建应用程序之前,我们还需要安装目标平台链接器。幸好,Homebrew 的 musl-cross tap 为 Mac OS 提供了完整的交叉编译工具链。


$ brew install filosottile/musl-cross/musl-cross
复制代码


现在,我们需要告诉 Cargo,我们的项目使用新安装的链接器来构建 x86_64-unknown-linux-musl 平台。在您的项目文件夹中创建一个名为 .cargo 的新目录,并在这个新文件夹中创建一个名为 config 的新文件。


$ mkdir .cargo$ echo '[target.x86_64-unknown-linux-musl]linker = "x86_64-linux-musl-gcc"' > .cargo/config
复制代码


在我的系统中,部分依赖项没有自动选择已配置好的链接器,而是尝试使用了 musl-gcc。为了尽快解决这个问题,我创建了一个链接到新链接器的符号链接:


$ ln -s /usr/local/bin/x86_64-linux-musl-gcc /usr/local/bin/musl-gcc
复制代码


安装并配置完编译器的新目标平台后,现在我们就可以进行 Cargo 交叉编译了!


构建函数

使用以下命令构建 AWS Lambda 应用程序。如果您在 Amazon Linux 上运行这些命令,则不需要添加 --target 选项。


$ cargo build --release --target x86_64-unknown-linux-musl
复制代码


我们创建的是发布版本,而不是调试版本。调试版本非常大,而且虽然基本示例没有超出,但其他应用程序很可能会超出 AWS Lambda 函数的最大部署包大小。


在构建过程中会在 ./target/x86_64-unknown-linux-musl/release/bootstrap 目录中创建一个可执行文件。Lambda 需要部署包为 Zip 文件。运行以下命令为 AWS Lambda 创建 Zip 部署包文件:


$ zip -j rust.zip ./target/x86_64-unknown-linux-musl/release/bootstrap
复制代码


为了简化部署和构建过程,我们将向 SAM CLI(无服务器应用程序模型)添加 Cargo 构建器。当该版本的 SAM CLI 发布后,您将能够使用 SAM 模板轻松运行 sam build。


在 AWS Lambda 中部署函数

现在,我们可以在 AWS Lambda 中部署该文件。导航至 AWS Lambda 控制台,然后创建新函数。


选中从头开始创作选项,为您的函数命名,我的函数名叫 test-rust。然后,从运行时下拉菜单中选择 Provided。我们的示例函数不需要任何特殊权限。如果您已有基本执行角色,则可以选择现有角色。否则可以让 Lambda 控制台创建具有基本权限的新角色(您无需选择模板)。最后,单击创建函数。



在函数屏幕中,使用 Function code(函数代码)部分的上传按钮上传我们在此教程的构建步骤中创建的 rust.zip 文件。选择新文件后,保存函数更改。我们不需要更改任何其他配置。


因为我们的代码完全包含在 Lambda 将启动的 bootstrap 可执行文件中,因此不需要处理程序信息。128MB 的内存和 3 秒执行超时为“Hello, world”提供了充足的空余空间。

抛出错误时,运行时可以选择在函数的输出中包含完整的堆栈跟踪。要实现这一点,只需将 RUST_BACKTRACE 环境变量设为 1 即可。


现在,我们可以测试下函数。在 Lambda 控制台中,单击右上角的测试按钮。由于这是我们第一次测试该函数,因此 Lambda 控制台会要求我们定义测试事件。您可能注意到了,在上述示例代码中,我们希望传入事件中包含 firstName 属性。使用以下 JSON 作为测试事件,并为您的测试对象命名。


{  "firstName": "Rustacean"}
复制代码



最后,单击测试事件模式窗口中的创建。保存新的测试事件后,再次单击控制台右上角的测试,实际启动该函数。展开“执行结果”部分,查看函数的输出和日志。



祝贺您! 现在已成功构建并部署了使用 Rust 编写的第一个 AWS Lambda 函数。接下来,尝试使用无服务器应用程序模型 (SAM) 模板部署此函数。


深入了解代码

既然我们已成功运行了 Rust Lambda 函数,那么接下来我们来拆分看下示例代码中最重要的组成部分。从最上方开始,我们导入了包:


#[macro_use]extern crate lambda_runtime as lambda;#[macro_use]extern crate serde_derive;#[macro_use]extern crate log;extern crate simple_logger;
复制代码


我们导入的第一个包是 lambda_runtime。这是我们的新运行时,简洁起见,将其命名为 lambda。您可能还注意到了 #[macro_use],这是我们导入宏时对 Rust 编译器的声明。过不了多久,您就不需要这样做了,因为 Rust 2018 版让我们能够像导入普通函数或值一样导入宏。该运行时定义了一个 lambda! 宏,能让它轻松引导运行时。


serde_derive 包还使用宏来为给定结构体生成 marshaller。您会看到,示例代码中的结构体包含注释 #[derive(Serialize, Deserialize)],,分别处理序列化和反序列化。


库使用通过 log 包定义的宏来生成日志消息。示例代码包含 simple_logger 包,用于将消息打印到 stdout。有许多包实现了 log 门面,而且运行时本身并不会限制您选择哪一个。


在 extern 和 use 语句之后,我们的示例代码声明了 main() 方法,即 bootstrap 可执行文件的入口点。该代码将在 Lambda 启动我们的函数时运行。


fn main() -> Result<(), Box<dyn Error>> {    simple_logger::init_with_level(log::Level::Info).unwrap();    lambda!(my_handler);
Ok(())}
复制代码


我们要做的第一件事是初始化 simple_logger,并将日志记录级别设置为 Info。您也可以将其更改为 Debug 或 Trace,以便接收有关库及其依赖项在后台执行操作的更多信息。注意,simple_logger 包会锁定 stdout,因此在调试或跟踪模式下记录日志将大大降低您函数的性能。


接下来,我们使用在 lambda_runtime 包中定义的 lambda!() 宏来引导我们的自定义运行时。在其最基本的形式下,宏会将指针指向您在代码中定义的处理程序函数。自定义运行时使用 hyper 库向 Lambda Runtime API 发出 HTTP 请求。您可以选择将自己的 tokio 运行时传递给 lambda!() 宏:


let rt = tokio::runtime::Runtime::new()?;


lambda!(my_handler, rt);


在没有提示且现有库将创建其自己的运行时的情况下,您可能想创建一个自定义 Tokio 运行时。您可以单击此处,查看一个完整的运行示例。


之后,自定义运行时会启动并开始轮询 Lambda Runtime API 来获取新事件。


代码的下一部分定义了处理程序函数。处理程序函数必须遵守在 lambda_runtime 包中创建的 Handler 类型。


fn my_handler(e: CustomEvent, c: lambda::Context) -> Result<CustomOutput, HandlerError> {    if e.first_name == "" {        error!("Empty first name in request {}", c.aws_request_id);        return Err(c.new_error("Empty first name"));    }
Ok(CustomOutput { message: format!("Hello, {}!", e.first_name), })}
复制代码


处理程序函数会接收实现 serde::Deserialize 特征的事件对象。自定义运行时还会为每个事件生成 Context 对象,并将其传递给处理程序。Context 对象包含您会在正式运行时中找到的相同属性。


处理程序返回的值必须是具有实现 serde::Serialize 的自定义输出类型的 Result。此外,自定义运行时库会指定可用于包装自定义错误的 HandlerError 类型。您可以在 Context 对象中使用 new_error(msg: &str) 方法来实例化具有 backtrace 的新 HandlerError 对象。自定义运行时知道如何将 HandlerError 序列化为 JSON,并且会在 RUST_BACKTRACE 环境变量告知它应该包含 backtrace 时包含 backtrace。


小结

该运行时仍然处于早期阶段,非常欢迎您提供相关反馈,促进其发展。此外,我们知道目前还有其他 Rust for Lambda 库,如 lando、rust-aws-lambda 和 rust-crowbar。非常感谢从事这些项目的相应作者所付出的努力和提供的灵感。


该运行时让使用 Rust 编写高性能 Lambda 函数变得轻而易举。欢迎访问我们的 aws-lambda-rust-runtime GitHub 存储库,参与该项目,并提供您的反馈和问题!


Rust 徽标由 Mozilla 提供,根据知识共享署名协议 (CC-BY) 条款使用。


本文转载自 AWS 技术博客。


原文链接:


https://amazonaws-china.com/cn/blogs/china/rust-runtime-for-aws-lambda/


2019 年 10 月 14 日 15:04237
用户头像

发布了 1249 篇内容, 共 33.1 次阅读, 收获喜欢 34 次。

关注

欲了解 AWS 的更多信息,请访问【AWS 技术专区】

评论

发布
暂无评论
发现更多内容

超低功耗LoRa无线通信应用实践

不脱发的程序猿

物联网 无线通信 四月日更 LoRa 无线通信模组

手起刀落,连斩获阿里(四面)+字节(四面)+美团(三面)三家一线大厂Offer!

Java架构追梦

Java 架构 阿里巴巴面试经历 腾讯面试经历 全套大厂面试真题

架构实战营模块1作业

竹林七贤

不是吧?不会多态,你还说自己会Java

学Java关注我

Java 编程 架构 程序人生 技术宅

教你一个著名的流行数据格式:Python JSON

华为云开发者社区

Python 数据 Python JSON JSON序列化 半结构化数据

架构实战营第一次作业

CmHuang

架构实战营

架构实战营模块1作业

阿体

架构实战营模块一总结

竹林七贤

数字化时代,都说企业转型迫在眉睫,如何转型成了关键?

一只数据鲸鱼

物联网 数字化 数据可视化 企业转型

企业为何开始选择使用成品训练数据集?

澳鹏Appen

人工智能 机器学习 数据集 人工智能大数据 数据流

“区块链+”,应用积分营销

电微13828808271

区块链

翻译:《实用的Python编程》07_05_Decorated_methods

codists

Python

如何用 iMazing 备份和恢复辐射避难所

懒得勤快

手机 游戏 ios管理 imazing

2021最新中高阶Android面试题总结,成功入职阿里

欢喜学安卓

android 程序员 面试 移动开发

Spring Boot + RabbitMQ实现订单过期自动取消功能

Lonely Sufferer

RabbitMQ springboot

【Java 试题】AQS解析

程序员架构进阶

AQS Java源码 28天写作 四月日更 4月日更

CSS实现动画环绕下划线效果

Sakura

四月日更

架构训练营

架构训练营

模块一:课后作业

a1vin-tian

架构实战营

2021互联网大厂面经最新分享:百度/阿里/蚂蚁(附答案解析)

比伯

Java 架构 面试 程序人生 技术宅

假期后来一波干货:一文理清JVM和GC

比伯

Java 程序员 架构 JVM 计算机

什么是 NIO ?6000 字详解 NIO

hepingfly

Java nio IO流

Oracle数据库的安装和使用指导

攻城狮Chova

数据库 oracle 安装 4月日更

3d导航栏

赫鲁小夫

4月日更

架构实战营-模块1-微信业务架构-学生系统架构备选方案

吴建中

“区块链+版权”应用保护者

电微13828808271

你在备战“字节”时一定需要这个,程序员进大厂指南+算法已开源

Java架构师迁哥

《iOS应用逆向与安全》

马士兵-苹果老师

读后感

独家对话阿里云函数计算负责人不瞋:你所不知道的 Serverless

Serverless Devs

阿里云 运维 云原生 #Serverless

架构实战营模块 1 作业

Geek_2b52aa

架构实战营

2021 年推荐给 React 开发者的 Visual Studio Code 插件及配置

清秋

推荐 vscode 插件 React 4月日更

2021 ThoughtWorks 技术雷达峰会

2021 ThoughtWorks 技术雷达峰会

现在开放 AWS Lambda Rust-InfoQ