在本文中,我们将使用 Lambda—Amazon Web Services(AWS)套件中的一个新工具—来启动并运行一个微服务。 我们将使用 Lambda 创建一个 HTTP GET 终端,该终端使用 GitHub 的API 发起请求,从 GitHub 中提取存储库信息并返回一个 JSON 响应。
为方便你可以按本文中的步骤进行操作,你将需要一个自己的 AWS 账户。 如果没有,您可以在 https://aws.amazon.com/ 上创建免费的AWS账户。
Lambda 的口号是:“运行代码不用考虑服务器”。乍一看,这可能让人觉得比较困惑。 代码究竟是在哪里或如何运行的呢?
“无服务器”是一个新的软件基础设施术语,你可能有所耳闻。 它用于描述按需执行代码的解决方案。“无服务器”这个术语可能会误导大家,因为事实上,在程序中仍然有服务器。 更好的描述符是 FaaS 或“函数即服务”。
这两个定义用于描述新的开发和部署经验。 这种新体验被认为是“无服务器”的,因为作为开发人员,不再需要管理,监视或扩展正在运行代码的任何服务器。 您只需将代码上传到 FaaS 提供服务的程序(在本例中为 AWS Lambda),FaaS 提供程序将在后台帮你执行代码并管理所有的基础架构。
鉴于这一“无服务器”架构扩展的定义,让我们来看看用 Lambda 工作的一些利弊。
传统的服务器托管使用重复计费周期。 你的服务器总是启动和运行使用资源和等待输入。 为了保持服务器正常运行,你按月或按年作为账单周期来支付费用。用按需定价,Lambda 按每个函数的使用进行计费。这意味着你的项目利用 Lambda 的功能是不频繁的,相比传统的托管解决方案,你可以节省大量的金钱。
Lambda 定价如下:
了解更多: https://aws.amazon.com/lambda/pricing/
每 100 万个请求 0.20 美元
每 GB 秒的计算时间 0.00001667 美元,每次执行时间接近 100ms
在一个传统的被托管的基础设施中, 你会进入到这样一个时期,你可能需要担心性能和扩展性。随着应用程序使用量和通信量的增加,您可能需要添加更多的托管服务器基础设施来跟上需求。对于你的用户,这可能导致失败,成为瓶颈。 当需要增加或减少额外的开销时,Lambda 会自动完成扩展性。
你可以在本地写 Lambda 功能代码,隔离测试,但是在没有创建你的拼装版的 Lambda,你不能在本地模拟生产环境。
Lambda 有两个主要概念:代码和触发器。 代码是不言自明的。 在我们的示例中,就是那些由您编写并上传到 Lambda 以产生你所需行为的 JavaScript 代码。
一旦你上传后,代码不会自行执行。 Lambda 有一个称为“触发器”的附加概念。触发器是由其他 AWS 服务触发的事件,它们将数据传递到 Lambda 函数以供执行。
一些示例触发器:
用指向 AWS API 网关的 HTTP 请求来触发 Lambda 代码。
用轮循的事件触发,例如来源于 CloudWatch 事件的 corn 任务。
用 DynamoDB 表的更新来触发 Lambda 代码。
你可以从与预期的 Lambda 签名相匹配的 JavaScript 中,通过导出一个常规函数来定义一个 Lambda 函数。
exports.myLambdaFunction = (event, context, callback) => { // Use callback() and return }
该函数接收3个参数:
event— Lambda 传递给函数的'触发数据'的键值对字典。
context— AWS 内部信息,例如 AWS 请求ID, Lambda 超时时间, 和日志信息.
更多详细信息请看: http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html
callback— 一个标准的 JavaScript 异步回调句柄。
更多详细信息请看: http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html#nodejs-prog-model-handler-callback
开始创建新的 Lambda 函数。访问 Lambda 仪表盘:
https://console.aws.amazon.com/lambda/home?region=us-east-1#/functions?display=list然后会看到像这样的界面:
点击蓝色的按钮 创建 Lambda 函数(Create a Lambda function) 来开始。
下一个界面会提示你 选择一个设计图(Select a blueprint) 并提供一个可过滤的设计图列表。点击 空函数(Blank Function) 选项,它应该是设计图列表中的第一个选项。这个页面可用于将来参考着使用其它工具。
接下来的界面是 配置触发器(Configure Triggers) ,显示成这样:
点击 下一步(Next) 离开这个界面。我们会在后面,建立起我们的函数之后,再来定义触发器。
在这一部分,需要给 Lambda 函数一个名称。我会使用 GithubGet 这个名称。你也可以填写对这个函数的描述,这是可选的。
默认情况下,Lambda UI 设置为内联编辑代码。 您应该看到一个内联编辑器,编辑器中有一个样本函数,如下所示:
内联编辑器需要很少的开销来获取和运行 lambda 代码,但对于本教程,我们将做一些更进阶的事情。
在大多数真实环境中,你如果要创建更多的复杂函数,常常需要通过npm来安装第三方的库。
让我们创建一个使用 npm 依赖项的自定义函数,并将其上传到Lambda。 您可以按照下面的步骤,或者可随意使用 示例代码库 中的代码
让我们为我们的新函数设置一个文件夹,并在文件夹中用默认的 package.json 文件初始化 npm:
npm init -f
接下来,我们将安装 GitHub 客户端:
npm install github
创建 index.js 文件,使用以下代码:
var GitHubApi = require('github'); var github = new GitHubApi(); exports.handler = (event, context, callback) => { github.search.repos({ q: 'sitepoint', sort: 'stars' }, function(err, res){ if(err){ callback(err); } var results = res.items.map((repo) => { return { url: repo.html_url, stars: repo.stargazers_count }; }); callback(null, { statusCode: 200, headers: { "Content-Type": "application/json" }, body: JSON.stringify(results) }); }); };
下面是这段代码的功能细节:
引入并初始化了 GitHubAPI
定义了一个与 Lambda 签名匹配的 handler 函数。
当 handler 函数被调用时,它会发出一个查询请求到 GitHub,对所有符合‘sitepoint’的数据仓库进行查询。
在 Github 的应答格式中,创建了一个 map 数据结构,其中包含了每个数据仓库的网址和星标数。
最后,用 http 响应(如对象)调用 Lambda 的回调函数,好与 API 网关预计集成 相匹配。
任意使用一个你熟悉的 zip 工具,创建一个包含函数文件的 zip 压缩包。我在 OS X 系统上使用 zip 命令行是这样的:
zip -r lambdaupload.zip ./index.js ./node_modules/
要将代码上传到 Lambda, 在内联编辑器的 “代码条目类型” 选项上选择 “ 上传 zip 文件 ”,然后使用弹出的窗口上传您的代码。
在这一部分下,我们要设置几个值。 Handler 是在上传的 JavaScript 文件中 Lambda 函数的引用。 默认情况下,它设置为 index.handler。hander 函数通过查找 index 文件与我们上传的文件相映射,并为我们 hander 函数检索出与我们 export.handler 文件相对应的的导出语句。
使用以下信息填写“Role”字段,为创建 Lambda 函数的基本角色:
Role: 从模板中创建新的 role
Role name: Lambda 获取 Role
Policy templates: 简单的微服务权限
这部分完成后, 单击“Next” 按钮继续。比可以看到 ‘Review’ 界面的概述配置:
如果一切正常,单击“创建函数”按钮继续。
既然我们的函数已经创建并初始化了,我们需要一种方法来调用它。现在是时候为该函数分配触发器了。对于触发器的实现,我们将使用 API 网关。
API 网关是另一种 AWS 服务,它能自动创建可配置响应源的 HTTP 终端。我们将把我们的 Lambda 函数作为 API 网关的响应。
点击‘Triggers’(触发器)
点击‘Add trigger’
点击lambda旁边的空白区域
选择“API Gateway”
在安全性中选择“Open”
点击提交
这些步骤可以在下面动画中看到:
当成功添加触发器之后,你应该可以在 Triggers 标签中看到触发器和你的函数被关联起来。
在 API 网关 ID 中会列出一个 URL。你可以访问在浏览器中这个 URL,然后你赢高可以看到一个 JSON 响应,类似下面的日志:
[{"url":"https://github.com/bodrovis/Sitepoint-source","stars":106}, {"url":"https://github.com/Azzurrio/moviestore","stars":80}, {"url":"https://github.com/bodrovis/SitepointMiniChat","stars":54}, {"url":"https://github.com/upchuk/d8-demo-modules","stars":34},
恭喜!你已经成功在 Lambda 上部署和触发代码了。
希望这个项目能给你在 AWS Lambda 上工作建立一个好的基础。虽然我们在函数代码中整合了第三方客户端(GitHub),但它可以替换为其它客户端 API 或者数据库的客户端链接。
这篇文章中演示了建立起 Lambda 的这个过程。这过程看起来手工操作比较多,时间也不长。还有另外一个配置和初始化 Lambda 的方法,就是通过 AWS API 来完成。
现在,已经有一些框架基于 AWS API 建立起来了,它们有助于简化这个过程。
https://serverless.com/
Serverless 框架是当前最强大的无服务器框架。在写文本的时候,这个框架进行了重大版本更新,从0.5 更新到官方 1.0 发行版。很不幸,这个更新并不向后兼容。大多数流行的插件当前还是 0.5,未能更新到 1.0,还需要等等待一段时间才能使用。
Serverless 以及它的插件,承诺提供一个非常全面的 Lambda 体验。它的本地开发环境提供了快速迭代、自动化的 Lambda 代码开发、多个开发平台环境,以及其它功能。
https://open-lambda.org/
OpenLambda 试图通过提供一个本地开发体验来模拟 Lambda 环境。它提供工具来让部署 Lambda 代码变得容易,也提供快速迭代。这弥补了上面列出的 Lambda 的一些缺点。