Serverless 解惑——AWS Lambda 迁移阿里云函数计算指南

Serverless 解惑——AWS Lambda 迁移阿里云函数计算指南

本文介绍了从 AWS Lambda 迁移阿里云函数计算时需要了解的相关概念以及提供了相应的示例。

概念比较

在 AWS Lambda 中,函数是管理 AWS Lambda 的基本资源单位,用户可以在函数级别上授权、配置 CloudWatch 日志。在阿里云函数计算中,除了有函数外还有服务资源。其中,服务是管理函数计算的基本资源单位,可以在服务级别上授权、配置日志和创建函数等;函数是调度与运行的基本单位,也是一段代码的处理逻辑。
在阿里云函数计算中,一个服务下可以创建多个函数,每个函数可以设置不同的内存规格、环境变量等属性,这种服务或者函数层次化的抽象,在系统抽象和实现灵活度上能够取得很好的平衡。例如,实现一个微服务,调用阿里云语音合成服务,将文字转成语音,再把这段语音和一系列图片组合为视频。其中文字转语音函数是调用其他服务,可以设置很小的内存规格。而视频合成函数是计算密集型,需要更大的内存。因此,可以通过组合多个不同规格的函数实现微服务,优化成本。

免费开通服务

  1. 免费开通函数计算,按量付费,函数计算有很大的免费额度。

接下来,将通过一张表格的形式来呈现 AWS Lambda 与阿里云函数计算的概念比较:

概念 AWS Lambda 函数计算
服务 服务是管理函数计算的基本资源单位,可以在服务级别上授权、配置日志和创建函数等
函数 具有处理事件的代码,以及在 Lambda 与函数代码之间传递请求和响应的运行时 是调度与运行的基本单位,具有处理事件的代码,以及在阿里云函数计算服务与函数代码之间传递请求和响应的运行时
运行时(Runtime) 位于 Lambda 服务和函数代码之间,并在二者之间传递调用事件、上下文信息和响应。支持的运行时清单 位于阿里云函数计算服务和函数代码之间,并在二者之间传递调用事件、上下文信息和响应。支持的运行时清单
并发 在调用函数时,Lambda 会预配置其实例以处理事件。当函数代码完成运行时,它会处理另一个请求。如果当仍在处理请求时再次调用函数,则预配置另一个实例,从而增加该函数的并发性。并发限制 在函数计算 1.0 中,一个函数实例最多只能同时处理一个请求,如果当仍在处理请求时再次调用函数,则预配置另一个实例,从而增加该函数的并发性。在函数计算 2.0 中,函数计算支持了单实例并发处理多请求功能。并发限制
触发器 触发器是调用 Lambda 函数的资源或配置。这包括可配置为调用函数的 AWS 服务、用户开发的应用程序以及事件源映射。事件源映射是 Lambda 中的一种资源,它从流或队列中读取项目并调用函数。 触发器列表 触发器是触发函数执行的方式,触发器提供了一种集中的和统一的方式来管理不同的事件源。在事件源中,当事件发生时,如果满足触发器定义的规则,事件源则调用触发器所对应的函数。触发器列表

开发工具 & SDK

下述表格为 AWS Lambda 与阿里云函数计算的开发工具 & SDK:

类型 AWS Lambda 函数计算
命令行 AWS Command Line Interface (AWS CLI) Fcli: 阿里云函数计算的命令行工具,帮助用户便捷的管理函数计算中的资源
命令行 SAM CLI Funcraft: 用于支持 Serverless 应用部署的工具,能帮助用户便捷地管理函数计算、API 网关、日志服务等资源。Funcraft 通过一个资源配置文件(template.yml),协助用户进行开发、构建、部署操作
IDE AWS Toolkit Extension Aliyun Serverless VSCode Extension: 结合了 函数计算 Funcraft 工具 以及函数计算 SDK ,是基于 VSCode 的开发调试部署工具;以及其他平台上的 Cloud Toolkit
IDE C9 FC WebIDE
SDK Node.js: SDK for Javascript Node.js: fc-nodejs-sdk
SDK Python: SDK for Python Python: fc-python-sdk
SDK PHP: SDK for PHP PHP: fc-php-sdk
SDK Java: SDK for Java Java: fc-java-sdk
SDK Go: SDK for Go Go: fc-go-sdk
SDK C#: SDK for .NET C#: fc-csharp-sdk

简单示例

迁移 Hello World 函数

接下来将介绍如何将 AWS Lambda 的一个简单示例迁移至阿里云函数计算服务。

exports.handler = async (event, context) => {
    console.log(`Event: ${JSON.stringify(event)}`);
    console.log(`Context: ${JSON.stringify(context)}`);
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello World!'),
    };
    return response;
};

上述为 AWS Lambda Nodejs10.x 运行时的函数代码,在该函数中做了以下三件事:

  1. 打印 Event 事件信息
  2. 打印 Context 上下文信息
  3. 返回 Response 对象,内容为

    {
       "statusCode": 200,
       "body": "\"Hello World!\"",
    }

    我们将其迁移至阿里云函数计算服务,根据 快速入门/HelloWorld 示例 中的内容创建好 nodejs10 运行时的函数代码,修改代码内容如下:

module.exports.handler = function(event, context, callback) {
  console.log(`Event: ${JSON.stringify(JSON.parse(event))}`);
  console.log(`Context: ${JSON.stringify(context)}`);
  const response = {
    statusCode: 200,
    body: JSON.stringify('Hello World!'),
  };
  callback(null, response);
}

上述为阿里云函数计算 nodejs10 运行时的函数代码。注意,该函数代码和 AWS Lambda Nodejs10.x 运行时函数代码有以下两点不同:

  1. event 参数的输出方式
    在 AWS Lambda Nodejs10.x 中,输出 event 的代码为 console.log(`Event: ${JSON.stringify(event)}`);;而在阿里云函数计算 nodejs10 中,输出 event 的代码为 console.log(`Event: ${JSON.stringify(JSON.parse(event))}`);。在 AWS Lambda 中,事件 Event 传入的类型是 JSON 对象;而在阿里云函数计算中,事件 Event 传入的类型是 Buffer。
  2. 函数返回结果的方式
    在 AWS Lambda Nodejs10.x 中,函数返回结果的代码为 return response;;而在阿里云函数计算 nodejs10 中,函数返回结果的代码为 callback(null, response);

上述两点的不同是由于阿里云函数计算 Nodejs 普通函数入口和 AWS Lambda Nodejs 函数入口有所不同,阿里云函数计算 Nodejs 普通函数入口有以下三个参数:

  1. event 参数
  2. 参数是调用函数时传入的数据,其类型是 Buffer,是函数的输入参数。函数不对它的内容进行任何解释,在函数中可以根据实际情况对 event 进行转换。
  3. context 参数
  4. 参数中包含一些函数的运行时信息(例如 request id / 临时 AK 等),其类型是 object。包含以下信息:

    • requestId: 本次调用请求的唯一 id。
    • function: 当前调用的函数的一些基本信息如函数名 / 函数入口 / 函数内存 / 超时时间
    • credentials: 函数计算服务通过扮演用户提供的 服务角色 获得的一组临时密钥,其有效时间是 6 小时。可以在代码中使用它去访问相应的服务( 例如 OSS )
    • service: 当前调用的函数所在的 service 的信息,包括 service 的名字,接入的 SLS 的 logProject 和 logStore 信息,service的版本信息qualifier和version_id,qualifier表示调用函数时指定的service版本或别名,version_id表示实际调用的service版本。
    • region: 当前调用的函数所在区域,如 cn-shanghai。
    • accountId: 当前调用函数用户的阿里云 account id。
  5. callback 参数

    • callback 参数用于返回调用函数的结果,其签名是 function(err, data),与 Node.js 中惯用的 callback 一样,它的第一个参数是 error ,第二个参数 data 。如果调用时 err 不为空,则函数将返回 HandledInvocationError ,否则将返回 data 的内容。如果 data 是 Buffer 类型则它的数据将直接被返回,如果 data 是 object ,则会将其转换成 JSON 字符串返回,其他类型将被转换成 string 返回。

更多内容可以参考 Node.js 函数入口

复杂示例

迁移 S3 触发 Lambda 的函数

接下来将介绍如何将 AWS Lambda 带有 S3 触发器并访问 S3 的简单示例函数迁移至阿里云函数计算服务。

console.log('Loading function');

const aws = require('aws-sdk');

const s3 = new aws.S3({ apiVersion: '2006-03-01' });

exports.handler = async (event, context) => {
    // Get the object from the event and show its content type
    const bucket = event.Records[0].s3.bucket.name;
    const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
    const params = {
        Bucket: bucket,
        Key: key,
    };
    try {
        const result = await s3.getObject(params).promise();
        console.log(result);
        return result;
    } catch (err) {
        console.log(err);
        const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
        console.log(message);
        throw new Error(err);
    }
};

上述为 AWS Lambda Nodejs10.x 运行时的函数代码,该函数配置了 S3 触发器以及相应的 Execution Role,该函数的主要逻辑如下:

  1. 当为 S3 触发器配置的事件源发生了相关事件时,事件源将调用该函数。
  2. 从 Event 事件信息中获取到事件相关的 Bucket 以及 Key。
  3. 访问 S3 获取到相关对象。

我们将其迁移至阿里云函数计算服务,根据 快速入门/HelloWorld 示例 中的内容创建好 nodejs10 运行时的函数代码,修改代码内容如下:

const oss = require('ali-oss');

module.exports.handler = async (event, context) => {
    // Get the object from the event and show its content type
    const event = JSON.parse(event);
    const bucket = event.events[0].oss.bucket.name;
    const key = event.events[0].oss.object.key;
    let client = new OSS({
      bucket: bucket,
      accessKeyId: context.credentials.accessKeyId,
      accessKeySecret: context.credentials.accessKeySecret,
      stsToken: context.credentials.securityToken,
    });
    try {
        const result = await client.get(key);
        console.log(result);
        callback(null, result);
    } catch (err) {
        console.log(err);
        const message = `Error getting object ${key} from bucket ${bucket}.`;
        console.log(message);
        callback(err);
    }
};

上述为阿里云函数计算 nodejs10 运行时的函数代码,代码逻辑和 AWS Lambda 大致相同。其中,OSS 为阿里云对象存储服务。除此之外,还需要为该函数配置 OSS 触发器以及相应的 ServiceRole 和 InvocationRole。相关概念如下:

  1. 服务角色 Service Role
    为服务配置服务角色,即允许该服务下的函数扮演这个角色。假设该角色拥有 OSS 的相关权限,则函数通过扮演该角色可以使用 OSS 上的资源。阿里云函数计算的服务角色和 AWS Lambda 中的 Execution Role 是相同的作用。
  2. 触发角色 Invocation Role
    触发角色,事件源需要扮演一个角色来触发函数的执行,要求这个角色有触发函数执行的权限。关于事件源角色的详细信息请参考文章 权限简介

除了上述的服务角色和触发角色外,还需要注意的一点是,在函数中是通过如下的代码片段生成了 OSS client:

let client = new OSS({
  bucket: bucket,
  accessKeyId: context.credentials.accessKeyId,
  accessKeySecret: context.credentials.accessKeySecret,
  stsToken: context.credentials.securityToken,
});

context 参数中包含了 credentials 信息,函数计算服务通过扮演用户为服务配置的服务角色获得的一组临时密钥。用户可以在代码中使用它去访问相应的服务( 例如 OSS ),这就避免了把自己的 AK 信息写死在函数代码里。

迁移 AWS Step Functions 调用 AWS Lambda

接下来将介绍如何将 AWS Step Functions 调用 AWS Lambda 的简单示例迁移至阿里云函数工作流和函数计算服务。

{
  "StartAt": "Hello",
  "States": {
    "Hello": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:ap-southeast-1::function:helloworld",
      "End": true
    }
  }
}

上述为 AWS Step Functions 的流程代码,该流程调用了 AWS Lambda 的函数,假设调用的函数代码为简单示例中的 Hello World 函数。

我们将其迁移至阿里云函数工作流服务,根据 快速入门/创建流程 中的内容创建好 函数工作流的流程,修改流程代码内容如下:

version: v1beta1
type: flow
steps:
  - type: task
    name: helloworld
    resourceArn: acs:fc:cn-hangzhou::services/helloworld/functions/sayHello

上述为阿里云函数工作流服务的流程代码,代码逻辑和 AWS Step Functions 大致相同。可以看到,当将 AWS Lambda 成功迁移至阿里云函数计算服务后,如果有迁移 AWS Step Functions 调用 AWS Lambda 的需求,只需要将 AWS Step Functions 的流程逻辑迁移至阿里云函数工作流服务即可。

其他

参考链接

  1. 函数计算计费方式
  2. 函数计算开发语言列表
  3. 函数计算触发器列表
  4. 函数计算监控指标
  5. 函数计算 Funcraft 工具
  6. 函数计算 VSCode 插件

加入我们

团队介绍

阿里云函数服务是一个全新的,支持事件驱动编程模式的计算服务。 他帮助用户聚焦自身业务逻辑,以 Serverless的方式构建应用,快速的实现低成本,可扩展,高可用的系统,而无需考虑服务器等底层基础设施的管理。 用户能够快速的创建原型,同样的架构能随业务规模平滑伸缩。让计算变得更高效,更经济,更弹性,更可靠。无论小型创业公司,还是大型企业,都受益其中。我们的团队正在迅速扩张,求贤若渴。我们想寻找这样的队友:
基本功扎实。既能阅读论文追踪业界趋势,又能快速编码解决实际问题。
严谨的,系统化的思维能力。既能整体考虑业务机会,系统架构,运维成本等诸多因素,又能掌控设计/开发/测试/发布的完整流程,预判并控制风险。
好奇心和使命感驱动。乐于探索未知领域,不仅是梦想家,也是践行者。
坚韧、乐观、自信。能在压力和困难中看到机会,让工作充满乐趣!
如果您对云计算充满热情,想要构建一个有影响力计算平台和生态体系,请加入我们,和我们一起实现梦想!

职位描述

构建新一代 Serverless 计算平台,包括:

  1. 设计和实现完整可扩展的前端系统,包括身份验证/权限管理,元数据管理,流量控制,计量计费,日志监控等等
  2. 设计和实现弹性可靠的后端系统,包括资源调度,负载均衡,容错处理等等
  3. 丰富易用的 SDK/Tools/CLI/控制台
  4. 用户需求驱动,追踪业界趋势,利用技术推动业务的成长

职位要求

  1. 算法/数据结构/操作系统等基础知识扎实,优秀的逻辑思维能力。
  2. 至少掌握一门编程语言。例如 Java/Go/C/C#/C++。
  3. 有大规模、高可用分布式系统开发经验者优先。
  4. 有 Web/Mobile Backends/Microservice 开发经验者优先。
  5. 良好的沟通能力和团队合作精神,有一定的组织协调能力。
  6. 本科及以上学历
  7. 3 年以上工作经验
    通过“阿里巴巴编码规范” 认证的同学优先录取,认证地址:https://edu.aliyun.com/certification/cldt02

简历提交

yixian.dw AT alibaba-inc.com

上一篇:淡出到灰色:无头浏览器会扼杀网页设计吗?


下一篇:Aliyun Serverless VSCode Extension v1.9.0 发布