![带您玩转Lambda,轻松构建Serverless后台!](https://static001.infoq.cn/resource/image/aa/40/aa035c6ad590b725019842ffd7a5cc40.jpg?x-oss-process=image/crop,y_63,w_1500,h_842/resize,w_726,h_408)
Amazon CTO Werner Vogels 曾经在 AWS re:Invent 大会上提到: 如果把云计算理解成一个执行环境,那么,在这个环境里,函数(即业务逻辑的载体)+数据(即跟业务相关的输入与输出)就是应用的核心,有了 Functions、Data、Event 这三者,其它任何代码和框架,无非是整个应用的胶水和 UI 罢了。那么,最理想的情况就是用最少的时间写胶水,将更多的时间投入到核心应用的开发中,甚至,彻底实现整个软件栈的微服务化。
那么能不能做到呢?答案是肯定的。AWS Lambda 也在这样的背景下应运而生了,其实在很多人眼里,Lambda 是一个具有“革命性”的服务,我本人也非常喜欢 Lambda 这个服务,因为它给我的感觉是: 轻、快、高可用!能够快速将想法写成代码,并应用到生产,不需要关心底层基础设施的运维。接下来,让我们一起搭建一个 serverless 的后台!
【1】AWS Lambda 怎么用?
怎么学习 Lambda 呢?让我们从一个简单的数学问题开始,10 以内乘法和加法运算,获得随机的一个数字。代码有注释,如下:
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-1.png)
//Node.js尽量全使用严格模式
'use strict';
//利用console.log可以将日志自动打到CloudWatch里面
console.log('Loading function');
exports.handler = (event, context, callback) => {
//定义一个最小值为2
var min = 2;
//定义一个最大值为10
var max = 10;
//生成一个随机数,乘以最大值,再加上一个最小值
var generatedNumber = Math.floor(Math.random() * max) + min;
//利用callback回调,得到结果。
callback(null, generatedNumber);
};
接下去,然后选择 Lambda 服务
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-2.png)
创建一个 Lambda Function
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-3.png)
选择 Node.js 6.10 的环境
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-4.png)
当然,Lambda 目前支持 C#,Node.js,Python,Java,后续会支持很多的语言比如 Go,PHP,Ruby 等。换言之,之后任何能在 Linux 上跑的环境都能在 Lambda 上运行。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-5.png)
接下去把上面那段代码拷贝进去,选择“Role”角色,这其实就是 Lambda 执行时所拥有的权限。当然,你可以通过 IAM 服务创建一个新的 Role,或者选择已经存在的 Role。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-6.png)
然后点击“Create Function”,接着就会看到
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-7.png)
好!Lambda 创建成功了!在 Lambda 上方点击 Test,进行测试,能看到输出的结果。细心的你已经发现,代码运行的时间只有 0.3ms 哦。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-8.png)
查看 Lambda 执行的结果:
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-9.png)
您可以多次点击 test,每次输出的结果都不一样,这是因为,代码一开始生成了一个随机数,所以每次输出的结果也都是随机的。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-10.png)
您可以点击“View logs in CloudWatch”,能看到所有 Lambda 运行相关的日志。AWS 已经把这部分的日志已经自动集成到 CloudWatch 里面了。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-11.png)
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-12.png)
如果你想结合自己常用的日志分析工具,比如 sumologic,可以再用一个 Lambda 将 CloudWatch Logs 的日志导出。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-45.png)
【2】Lambda + API Gateway
到这里,我们发现,应用的逻辑可以交给 Lambda 执行,那前端的 HTTP 请求怎么办呢?AWS 还有一个服务叫 API Gateway,提供的 HTTP 网关服务,那么,Lambda 怎么和 API Gateway 又怎么结合起来使用呢?
接下去,您可以进入到 API Gateway 这个服务里面,点击“Create API”。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-13.png)
写入 API 的名字然后创建
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-14.png)
创建一个 Method
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-15.png)
选择 HTTP Get 方法。目前,AW API Gateway 支持 HTTP DELETE, HEAD, OPTIONS, PATCH, POST, PUT 等方法。指定我们之前创建的 Lambda 函数,选择“Integration Type”Lambda Function。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-16.png)
输入 Lambda 对应的 Region 和 Lambda 函数的名字,然后点击 Save。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-17.png)
然后进行部署 API,点击“Deploy API”。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-18.png)
指定 API 的版本,比如 prod 或者 test。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-19.png)
注意,当你定义好这个 API 之后,可以自动生成整套 SDK,有 Android,JavaScript,iOS-OC,iOS-Swift,Java。所以,开发人员可以基于这一套自定义的、标准的 SDK 进行统一开发。只要指定了统一的后端数据库,所有的开发人员都可以各自开发自己的内容,互不干扰,最终形成一个统一、完整的项目。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-20.png)
然后点击“Stages”,查看 Get 的 http 地址。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-21.png)
将这个地址复制到浏览器(比如 Firefox),可以查看 Lambda 运行后输出的结果。这样,Lambda 就和 API gateway 结合起来了。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-22.png)
点击刷新,当然数字会变。
【3】Lambda + API Gateway + 传参
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-23.png)
如果客户端需要想传递参数,怎么办呢?
那就可以通过 API Gateway 接受客户端(比如浏览器)输入的参数,然后 API Gateway 把这个参数传递给后端的 Lambda,Lambda 通过 event 对象获得前端 API Gateway 传递过来的参数,从而进行代码的逻辑执行。
让我们先改动一下 Lambda 的代码,将固定值 2 和 10 换成以变量的形式传递进去。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-24.png)
然后再到 API Gateway 服务里面,找到“Integration Request”。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-25.png)
找到“Body Mapping Templates”,修改其中的“application/json”,输入提供的内容。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-26.png)
{
"min":$input.params('min'),
"max":$input.params('max')
}
点击保存,这样,就通过客户端就可以把参数传递给 API Gateway 了。比如:
https://j3bi4vs4w4.execute-api.us-west-2.amazonaws.com/prod/number
这个时候打开之前的链接是空值,因为还没传递参数进去。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-27.png)
https://j3bi4vs4w4.execute-api.us-west-2.amazonaws.com/prod/number?min=1&max=10
在浏览器客户端中,传递参数进去之后,比如 min=1,max=10,如下:
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-28.png)
刷新浏览器,当然会得到随机的结果。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-29.png)
再来一次,刷新浏览器,当然会得到随机的结果。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-30.png)
【4】快速部署 Lambda 函数?
部署 Lambda 的函数,可以直接在控制台输入代码,也可以在本地写好之后打成 zip 包上传到 Lambda,或者上传到 S3 再指定链接内部加载到 Lambda 上。
当然,如果觉得不是很方便,目前其实已经有很多开源的框架支持都 Lambda 的快速部署了,比如 SERVERLESS.com,Claudiajs.com,APEX,Zappa,Kappa,Chalice 等。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-31.png)
【注意!】我们会在下一期内容中专门讲解这些框架怎么用,以及如何借用这些框架,再配合 AWS CodePipeline,CodeCommit,CodeBuild,CloudFormation 完全实现 serverless 微服务化,一键自动化发布和部署整个软件栈。
在这里,由于个人喜好,我们拿一个比较轻量的工具 APEX 举例,http://apex.run/,Apex集成了Lambda的SDK,用户只需要在本地执行apex init 命令就创建了一个 Lambda 环境以及所需的 Role,然后通过 deploy 命令就可以将本地的 Lambda 代码以及所需要的依赖自动打成 zip 包,并上传到云端环境。并且 Apex 会自动进行 Lambda 版本管理,更重要的是,还支持回滚,查看云端 log。这可以让您真正只关心代码,写完代码之后直接部署就可以了,非常方便。你会发现,开发的时候甚至连 AWS 的控制台都不需要打开!
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-32.png)
本地安装,一条 curl 语句。搞定了!真的挺简单的。
curl https://raw.githubusercontent.com/apex/apex/master/install.sh | sudo sh
接下去通过 aws configure 配置你的权限
danrongm:~ danrong$ aws configure
AWS Access Key ID [****************2T5A]:
AWS Secret Access Key [****************Tcma]:
Default region name [us-west-2]:
Default output format [json]:
创建 apex 项目: apex init,然后输入项目名称 first-apex-project
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-33.png)
接着就开始部署了
acbc32c13f31:apex-demo danrongm$ apex deploy
• creating function env= function=hello
• created alias current env= function=hello version=1
• function created env= function=hello name=first-apex-project_hello version=1
Apex 自动会帮您创建 Role,以及进行版本的管理和控制。当你修改完代码之后,可以再次执行 apex deploy,只要代码有改变,版本号以数字形式就会往上增加。
如果部署其中的一个函数: apex deploy hello
如果调用函数显示输出结果: apex invoke hello
另外,可以直接在本地查看日志的输出。
**apex-demo danrongm$ apex invoke -L hello 会把日志输出的所有内容输出**
START RequestId: 7c432478-ee78-11e6-8d9b-21a4e48977b8 Version: 5
2017-02-09T03:33:13.014Z 7c432478-ee78-11e6-8d9b-21a4e48977b8 processing event: {}
END RequestId: 7c432478-ee78-11e6-8d9b-21a4e48977b8
REPORT RequestId: 7c432478-ee78-11e6-8d9b-21a4e48977b8 Duration: 0.41 ms Billed Duration: 100 ms Memory Size: 128 MBMax Memory Used: 10 MB 104
查看 Apex 的所有日志(其实就是最近 5 分钟内的 CloudWatch 的日志)
apex logs
【5】Lambda + CloudWatch Event
有些场景,有可能是想定期、或者定时让 Lambda 去执行处理逻辑,针对这种情况,可以使用 CloudWatch Event,触发 Lambda 定时执行。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-34.png)
可以在 CloudWatch 里面创建一个 Rule,然后 Event selector 可以通过 Cron 方式定期调用 Lambda 函数,如下:
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-35.png)
这样,你就可以按照一定的规则,定时的去触发 Lambda 函数了。更多内容可参考:
http://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/events/RunLambdaSchedule.html
【6】Lambda + DynamoDB –> 数据写入到数据库
用户发送 HTTP 请求,交给 API Gateway 处理,业务逻辑交给 Lambda 处理,那如果动态的数据需要存储到数据库呢?AWS 提供了 NoSQL 的数据库 DynamoDB 和关系型数据库 RDS,这些都可以和 Lambda 配合使用。值得一提的是,Lambda 可以和 RDS 一样,放在 VPC 内部,配置安全组。
那么,如何使用 Lambda 把处理后的数据存储在 DynamoDB 呢?Lambda 又怎么和数据库进行交互呢?直接上代码。首先创建一个 Lambda 函数,比如命名为: lambda_dynamodb_write,代码如下
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-36.png)
'use strict';
console.log('Loading function');
var AWS = require('aws-sdk');
var docClient = new AWS.DynamoDB.DocumentClient();
AWS.config.region = 'us-west-2’;
exports.handler = function (event, context, callback){
var params = {
Item: {
date: Date.now(),
message: "Danrong"
},
TableName: 'lambda_dynamodb_write_read'
};
docClient.put(params, function(err, data){
if(err){
callback(err, null);
}else{
callback(null, data);
}
});
};
【7】Lambda + DynamoDB –> 数据从数据库读取
搞定了数据库的写入操作,Lambda 又怎么读写数据库里的内容呢?直接上代码。
创建一个 Lambda 函数,比如命名为: lambda_dynamodb_read,代码如下
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-37.png)
'use strict';
console.log('Loading function');
var AWS = require('aws-sdk');
var docClient = new AWS.DynamoDB.DocumentClient({region:'us-west-2'});
exports.handler = function(event, context, callback){
var params = {
TableName: 'lambda_dynamodb_write_read',
Limit: 100
};
docClient.scan(params, function(err,data){
if(err){
callback(err, null);
}else{
callback(null, data);
}
});
};
对于数据库的修改和删除操作,同样可以轻松做到。到这里,Lambda 和 DynamoDB 的交互就搞定了。
【8】Lambda + API Gateway + DynamoDB
此时,我们再将前面三者,即 Lambda,API Gateway,DynamoDB 结合起来。创建一个 Date 为主键的 DynamoDB Table,让它存储 Lambda 处理的结果,如下:
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-38.png)
由于之前我们已经创建过 HTTP GET 了,同样的方式,在 API Gateway 里面,创建一个 HTTP POST 的方法。如下:
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-39.png)
API Gateway 中可以解决跨域 CORS 的问题,点击“Enable CORS”。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-40.png)
到这里,客户端浏览器发出请求,会发送到 API Gateway 那边,然后 API Gateway 传递客户端的参数给 Lambda,Lambda 通过 Event 对象获取 API Gateway 传参的值,并处理逻辑。比如将数据写入到 DynamoDB,或者从 DynamoDB 读取数据显示在前端。
【9】Lambda + API Gateway + DynamoDB + S3 + CloudFront
托管静态网站。如果您是一个网站,或者是移动、IoT 等后台,可以把前端显示的静态内容,比如 HTML,JS,CSS,以及所有图片托管在 S3 上,启用静态网站托管。
到这里,一个 serverless 的网站就做好了,您可以点击下面链接进行尝试。
https://s3.amazonaws.com/danrong.io/index-ajax.html
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-41.png)
前端显示的 HTML 代码开源,您可以公开下载:
https://s3.cn-north-1.amazonaws.com.cn/danrong-share/external/aws-china-blog-lambda-demo-index.html
接下去,其实就是前端的 UI 设计了,比如,我比较喜欢用http://www.bootcss.com/
完全可以改善一下前端的展示风格,看起来舒服一点。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-42.png)
如果要解决域名的问题,可以使用 Amazon Route53 访问(注意,域名也可以直接在 Route53 上购买),这样,就可以用您自定义的域名访问一个 Serverless 的网址了。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-43.png)
到这里,一个类似于“点击发布评论”、“查看所有评论”的网站就完成了。整个网站基于微服务的思想,完全实现了 serverless 的架构。
【10】Lambda + CodeCommit + CodePipeline + CodeBuild + CloudFormation
到这里,或许您已经在考虑 Lambda 如何做到持续化的发布和部署呢?能不能让我的开发人员只关心写代码,其余之后的事情全部一键搞定呢?比如,开发人员在本地用各种各样的 IDE 写代码,写完之后将代码提交到 Git 仓库,然后整个 pipeline 自动完成。在 AWS 的世界里,当然可以!例如,整个流程可以这样:
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/0410-44.png)
我们完全可以利用 AWS 全面的开发工具,CodeCommit + CodePipeline + CodeBuild + CloudFormation,实现从代码开发,到代码提交,到代码发布,到代码构建,到代码部署,一键自动化发布整个软件栈。再配合 Serverless 的各种框架(见前面正文),真正可以做到微服务化并且快速迭代敏捷开发!
另外,读者也可以关心一下 Security 安全的问题,比如 Authentication, Authorization, Sensitive data 等问题;关于 Quality,比如 Testing, Continuous Integration, Deployment 等问题。这两部分的内容,我们将会在下一期中介绍,期待您继续关注 AWS 中国官方微信。
更多关于 Lambda 内容可以参考:
https://aws.amazon.com/cn/lambda/
http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/welcome.html
作者介绍:
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/Mao+Danrong-mini.png)
毛郸榕
AWS 解决方案架构师,负责基于 AWS 的云计算方案架构的咨询和设计,同时致力于 AWS 云服务在国内的应用和推广,毕业于北京航空航天大学云计算专业,硕士,毕业后直接加入亚马逊 AWS 中国。在大规模后台架构、企业混合 IT 和自动化运维等方面有着丰富的实践经验。目前在集中精力学习新一代无服务器架构的开发与设计。
本文转载自 AWS 技术博客。
原文链接:
https://amazonaws-china.com/cn/blogs/china/lambda-serverless/
评论