场景:
如今须要开发一个先后端分离的应用,后端采用 RESTful API 最为方便,可是若是这个后端服务会在一天中的某些时候有高并发的状况,使用什么样的架构最为简单呢?html
刚思考这个问题的时候我想到的解决方案可能有如下几种:python
使用CDN内容分发网络,减小主服务器的压力git
使用LVS服务器负载均衡编程
使用缓存json
硬件层 提升带宽,使用SSD 硬盘,使用更好的服务器后端
代码层,优化代码(使用性能更好的语言等缓存
但以上的几个方法都须要关注服务器的存储和计算资源,以便随时调整以知足更高的性能,而且高并发的请求也是分时段的,配置了更高性能的服务器在访问量变低的时候也是资源浪费。bash
这个时候可使用 FaaS(Functions as a Service) 架构,跟传统架构不一样在于,他们运行于无状态的容器中,能够由事件触发,短暂的,彻底被第三方管理,功能上FaaS就是不须要关心后台服务器或者应用服务,只需关心本身的代码便可。其中AWS Lambda是目前最佳的FaaS实现之一。服务器
AWS Lambda 是一项计算服务,使用时无需预配置或管理服务器便可运行代码。AWS Lambda 只在须要时执行代码并自动缩放。借助 AWS Lambda,几乎能够为任何类型的应用程序或后端服务运行代码,并且无需执行任何管理。如今 AWS Lambda 支持 Node.js、Java、C# 和 Python。网络
Lambda 常见的应用场景有如下几种:
下图是将Lambda 做为事件源用于 AWS 服务案例的一个执行流程图:
这篇文章主要介绍 将 Lambda 做为事件源用于 AWS 服务 和 配合 API Gateway 建立简单的微服务。
接下来将使用一个案例介绍如何使用 Lambda。
须要注意的是:处理程序填写部分为 代码文件名+文件中函数名,这里咱们文件名lambda_function, 函数名是 lambda_handler,处理程序部分填写为 lambda_function.lambda_handler。
登陆 aws 控制台,打开 API Gateway,选择咱们刚刚选用的 API,点击测试,咱们将会看到如下输出
详细信息能够参考 官方文档(https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/getting-started.html)
经过上面的步骤,咱们了解了如何使用一个 Lambda 函数,如今咱们看下如何构建 Lambda 函数。
在建立 Lambda 函数时,须要指定一个处理程序(此处理程序是代码中的函数),AWS Lambda 可在服务执行代码时调用它。在 Python 中建立处理程序函数时,使用如下通常语法结构。
def handler_name(event, context):
...
return some_value
复制代码
在该语法中,须要注意如下方面:
event
- AWS Lambda 使用此参数将事件数据传递处处理程序。此参数一般是 Python dict
类型。它也能够是 list
、str
、int
、float
或 NoneType
类型。
context
- AWS Lambda 使用此参数向处理程序提供运行时信息。此参数为 LambdaContext
类型。
(可选)处理程序可返回值。返回的值所发生的情况取决于调用 Lambda 函数时使用的调用类型:
若是使用 RequestResponse
调用类型(同步执行),AWS Lambda 会将 Python 函数调用的结果返回到调用 Lambda 函数的客户端(在对调用请求的 HTTP 响应中,序列化为 JSON)。例如,AWS Lambda 控制台使用 RequestResponse
调用类型,所以当您使用控制台调用函数时,控制台将显示返回的值。
若是处理程序返回 NONE
,AWS Lambda 将返回 null。
若是使用 Event
调用类型(异步执行),则丢弃该值。
在执行 Lambda 函数时,它能够与 AWS Lambda 服务进行交互以获取有用的运行时信息,例如:
context 对象提供了如下方法:
返回在 AWS Lambda 终止函数前剩余的执行时间(以毫秒为单位)。
context 对象提供了如下属性:
正在执行的 Lambda 函数的名称。
正在执行的 Lambda 函数版本。若是别名用于调用函数,function_version
将为别名指向的版本。
ARN 用于调用此函数。它能够是函数 ARN 或别名 ARN。非限定的 ARN 执行 $LATEST
版本,别名执行它指向的函数版本。
为 Lambda 函数配置的内存限制(以 MB 为单位)。您在建立 Lambda 函数时设置内存限制,而且随后可更改此限制。
与请求关联的 AWS 请求 ID。这是返回到调用了 invoke
方法的客户端的 ID。 注意若是 AWS Lambda 重试调用(例如,在处理 Kinesis 记录的 Lambda 函数引起异常的状况下)时,请求 ID 保持不变。
CloudWatch 日志组的名称,可从该日志组中查找由 Lambda 函数写入的日志。
CloudWatch 日志流的名称,可从该日志流中查找由 Lambda 函数写入的日志。每次调用 Lambda 函数时,日志流可能会更改,也可能不更改。若是 Lambda 函数没法建立日志流,则该值为空。当向 Lambda 函数授予必要权限的执行角色未包括针对 CloudWatch Logs 操做的权限时,可能会发生这种状况。
经过 AWS 移动软件开发工具包进行调用时的 Amazon Cognito 身份提供商的相关信息。它能够为空。identity.cognito_identity_ididentity.cognito_identity_pool_id
经过 AWS 移动软件开发工具包进行调用时的客户端应用程序和设备的相关信息。它能够为空。client_context.client.installation_idclient_context.client.app_titleclient_context.client.app_version_nameclient_context.client.app_version_codeclient_context.client.app_package_nameclient_context.custom由移动客户端应用程序设置的自定义值的 dict
。client_context.env由 AWS 移动软件开发工具包提供的环境信息的 dict
。
查看如下 Python 示例。它有一个函数,此函数也是处理程序。处理程序经过做为参数传递的 context
对象接收运行时信息。
from __future__ import print_function
import time
def get_my_log_stream(event, context):
print("Log stream name:", context.log_stream_name)
print("Log group name:", context.log_group_name)
print("Request ID:",context.aws_request_id)
print("Mem. limits(MB):", context.memory_limit_in_mb)
# Code will execute quickly, so we add a 1 second intentional delay so you can see that in time remaining value.
time.sleep(1)
print("Time remaining (MS):", context.get_remaining_time_in_millis())
复制代码
此示例中的处理程序代码只打印部分运行时信息。每一个打印语句均在 CloudWatch 中建立一个日志条目。若是您使用 Lambda 控制台调用函数,则控制台会显示日志。
您的 Lambda 函数可包含日志记录语句。AWS Lambda 将这些日志写入 CloudWatch。若是您使用 Lambda 控制台调用 Lambda 函数,控制台将显示相同的日志。
如下 Python 语句生成日志条目:
print
语句。logging
模块中的 Logger
函数(例如,logging.Logger.info
和 logging.Logger.error
)。print
和 logging.*
函数将日志写入 CloudWatch Logs 中,而 logging.*
函数将额外信息写入每一个日志条目中,例如时间戳和日志级别。
可查找 Lambda 函数写入的日志,以下所示:
在 AWS Lambda 控制台中 - AWS Lambda 控制台中的 ** Log output** 部分显示这些日志。
在响应标头中,当您以编程方式调用 Lambda 函数时 - 若是您以编程方式调用 Lambda 函数,则可添加 LogType
参数以检索已写入 CloudWatch 日志的最后 4 KB 的日志数据。AWS Lambda 在响应的 x-amz-log-results
标头中返回该日志信息。有关更多信息,请参阅Invoke。
若是您使用 AWS CLI 调用该函数,则可指定带有值 Tail
的 --log-type parameter
来检索相同信息。
在 CloudWatch 日志中 - 要在 CloudWatch 中查找您的日志,您须要知道日志组名称和日志流名称。可使用代码中的 context.logGroupName
和 context.logStreamName
属性来获取此信息。在运行 Lambda 函数时,控制台或 CLI 中生成的日志将会向您显示日志组名称和日志流名称。
若是 Lambda 函数引起异常,AWS Lambda 会识别失败,将异常信息序列化为 JSON 并将其返回。考虑如下示例:
def always_failed_handler(event, context):
raise Exception('I failed!')
复制代码
在调用此 Lambda 函数时,它将引起异常,而且 AWS Lambda 返回如下错误消息:
{
"errorMessage": "I failed!",
"stackTrace": [
[
"/var/task/lambda_function.py",
3,
"my_always_fails_handler",
"raise Exception('I failed!')"
]
],
"errorType": "Exception"
}
复制代码
详细信息参考官方文档:https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/lambda-app.html
AWS Lambda 在使用中会强加一些限制,例如,程序包的大小或 Lambda 函数在每次调用中分得的内存量。
每一个调用的 AWS Lambda 资源限制
资源 | 限制 |
---|---|
内存分配范围 | 最小值 = 128 MB/最大值 = 1536 MB (增量为 64 MB). 若是超过最大内存使用量,则函数调用将会终止。 |
临时磁盘容量(“/tmp”空间) | 512MB |
文件描述符数 | 1024 |
过程和线程数(合并总数量) | 1024 |
每一个请求的最大执行时长 | 300 秒 |
Invoke 请求正文有效负载大小 (RequestResponse/同步调用) | 6MB |
Invoke 请求正文有效负载大小 (Event/异步调用) | 128 K |
每一个区域的 AWS Lambda 帐户限制
资源 | 默认限制 |
---|---|
并发执行数 | 1000 |
并发执行是指在任意指定时间对您的函数代码的执行数量。您能够估计并发执行计数,可是,根据 Lambda 函数是否处理来自基于流的事件源的事件,并发执行计数会有所不一样。
基于流的事件源 - 若是您建立 Lambda 函数处理来自基于流的服务(Amazon Kinesis Data Streams 或 DynamoDB 流)的事件,则每一个流的分区数量是并发度单元。若是您的流有 100 个活动分区,则最多会有 100 个 Lambda 函数调用并发运行。而后,每一个 Lambda 函数按照分区到达的顺序处理事件。
并不是基于流的事件源 - 若是您建立 Lambda 函数处理来自并不是基于流的事件源(例如,Amazon S3 或 API 网关)的事件,则每一个发布的事件是一个工做单元。所以,这些事件源发布的事件数(或请求数)影响并发度。
您可使用如下公式来估算并发 Lambda 函数调用数。
events (or requests) per second * function duration
复制代码
例如,考虑一个处理 API Gateway 的 Lambda 函数。假定 Lambda 函数平均用时 0.3 秒,API Gateway 每秒请求 1000 次。所以,Lambda 函数有 300 个并发执行。
具体信息参考Lambda 函数并行执行
**AWS Lambda 部署限制 **
项目 | 默认限制 |
---|---|
Lambda 函数部署程序包大小 (压缩的 .zip/.jar 文件) | 50 MB |
每一个区域能够上传的全部部署程序包的总大小 | 75GB |
可压缩到部署程序包中的代码/依赖项的大小 (未压缩的 .zip/.jar 大小).注意每一个 Lambda 函数都会在其的 /tmp 目录中接收到额外的 500 MB 的非持久性磁盘空间。该 /tmp 目录可用于在函数初始化期间加载额外的资源,如依赖关系库或数据集。 |
250MB |
环境变量集的总大小 | 4 KB |
本文内容主要参考 AWS Lambda 官方文档,详细信息请访问 https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/welcome.html
最后,感谢女友支持。
欢迎关注(April_Louisa) | 请我喝芬达 |
---|---|
![]() |
![]() |