将 AWS Lambda 集成到分布式系统中是一种利用无服务器计算优势的强大方法,可以在无需管理基础设施的情况下执行代码。AWS Lambda 在事件驱动架构模式中表现出色,其中函数会在响应特定事件时被触发,通过仅对使用的计算时间收费来实现成本效益。在使用 Lambda 的过程中,保证函数是无状态这一点非常重要,这意味着它们不应在不同的调用之间存储状态。然而,触发 Lambda 函数需要与诸如 SNS 或 SQS 等其他 AWS 服务进行集成,这会增加架构的复杂性,因此全面理解系统设计至关重要。
在本文中,我将展示如何将AWS Lambda用作通知服务的一部分,其中SNS用来发布消息到主题,Lambda将被触发来处理这些通知。我们将逐步配置所需的AWS服务,包括IAM、SNS、SES和Lambda,来创建一个简单的通知服务系统。
AWS Lambda 介绍AWS Lambda 是一种无服务器计算服务 AWS Lambda,允许您无需预置或管理服务器就能运行代码。此服务根据传入流量自动扩展,使您的应用程序能够处理不同的工作量而无需手动干预。您只需为使用的计算时间付费,这使其对于事件驱动的应用程序来说既经济又可扩展。
Lambda 可以被触发或直接触发其他 AWS 服务(如 API Gateway、SNS 或 S3),响应事件执行代码(推送模型)。根据不同的事件来源,AWS 决定调用是同步还是异步:Lambda 将结果返回给触发的服务,或异步处理事件并根据需要重试。
AWS Lambda 推送模型
在拉模型中,Lambda 函数从队列或流中获取并处理数据,定期处理新到来的事件,当它们进来时。
AWS Lambda 拉取模式
在Lambda中,安全性至关重要,它使用两种类型的权限:调用权限(invocation权限)允许事件源触发该函数,以及执行角色(execution角色),赋予Lambda访问其他AWS服务的权限。这些角色通过IAM策略来管理。
AWS Lambda 权限种类
Lambda 可以用多种方式配置,比如:
- AWS 管理控制台(UI 界面)
- AWS CLI
- AWS SDK(特定语言的SDK API)
- AWS Cloudformation — 基础设施即代码(JSON, YAML)
- AWS 无服务器应用模型(用于创建不同类型的函数的模板)。
当用户预订房间或服务时,我们希望通知该用户。在这种情况下,可以使用 AWS Lambda 作为通知服务。然而,我们无法从代码中触发 Lambda 函数。例如,我们可以利用 AWS 简单通知服务(SNS)发布消息到一个主题,然后 Lambda 函数可以订阅该主题。AWS Lambda 处理程序函数可以封装通知逻辑(例如选择通知类型、用户白名单等),但不能直接发送电子邮件和短信。可以使用 AWS 简单电子邮件服务(SES)发送电子邮件。
预订系统架构,其中包括 AWS Lambda 作为其中的通知服务
向 AWS SNS 发布消息,我们的预订服务应提供API以在生产环境中的系统中执行操作。然而,为了简化,我们将使用一个简单的函数来模拟预订过程。
import boto3
import json
import os
import random
# 初始化SNS客户端
sns = boto3.client(
'sns',
region_name=os.environ.get('REGION'),
aws_access_key_id=os.environ.get('ACCESS_KEY_ID'),
aws_secret_access_key=os.environ.get('SECRET_ACCESS_KEY'),
)
# 您的SNS主题的ARN
sns_topic_arn = os.environ.get('TOPIC_ARN')
# 定义一个发布消息的函数
def publish_message(message):
response = sns.publish(
TopicArn=sns_topic_arn,
Message=json.dumps({'default': json.dumps(message)}),
MessageStructure='json',
)
print(f"消息已成功发送到SNS: {response['MessageId']}")
if __name__ == "__main__":
# 如果该脚本被直接运行,而不是被导入
r = random.randint(0, 1000000)
message = {
'event': '预订',
'user_id': '12345',
'email': f'user+{r}@example.com',
'body': '内容:预订成功',
}
publish_message(message)
为了使用 AWS SDK for Python,我们需要先安装 boto3
包。我们可以使用 pip 来安装它:
$ pip install boto3 # 使用pip安装boto3库
为了将我们的代码与任何AWS服务集成,最简单的方法是创建一个具有编程访问权限的新IAM用户并附加所需的策略。
- 使用您的AWS根账户登录AWS管理控制台:console.aws.amazon.com。
- 导航到IAM。
导航到 AWS IAM
- 点击“用户”选项卡,接着点击
Create user
按钮。
用户页
- 输入用户名。
用户名区域
- 选择
直接附加策略
的权限选项。 - 添加以下策略:
AmazonSNSFullAccess
用户权限设置
- 继续进行下一步,创建用户。
- 选择刚刚创建的用户并点击
创建访问密钥
。
我的页面
- 下载 CSV 文件。
创建了一个用户账号
- 在系统中设置环境变量:
export: ACCESS_KEY_ID = 将你的access_key_id
export: SECRET_ACCESS_KEY = 将你的secret_access_key
接下来,我们需要创建一个SNS,用来发布消息。
- 进入 AWS 管理控制台中的 SNS 控制台。
- 点击
新建主题
按钮并点击下一步 >
SNS 话题 banner
- 使用默认设置,并点击
创建话题
。
zh: SNS话题模板
- 复制刚刚创建的主题的ARN。
zh: SNS话题页
- 设置环境变量:
export TOPIC_ARN=arn:aws:sns:us-east-1:338535437683:notifications
export REGION=us-east-1
当我们执行代码时
$ python app.py
消息已通过SNS发布: ea014270-af41-52d3-acb4-1de1320e28fa
我们应该获取一条日志信息,表明消息已成功发布到SNS话题。
在下一节中,我们将添加一个处理来自主题的事件的 AWS Lambda 函数。
AWS SES 配置在准备AWS Lambda函数之前,我们需要配置AWS简单邮件服务(SES)来发送邮件。默认SES服务是在沙盒模式下运行,这意味着您只能向经过验证的电子邮件发送信息。如果要向任何邮箱发送邮件,您需要申请进入生产环境。在我们的例子中,我们将继续使用沙盒模式。
- 打开 AWS Management Console 并进入 SES 服务。
- 提供您希望在沙盒模式下接收测试消息的电子邮件地址。
SES 邮件验证, 部分
- 提供域名(但无需在测试模式下),。
SES领域部分
完成验证过程
SES 配置页面概要
- 确认您邮箱中的地址。
- 发送一封测试邮件。
在SES配置面板里找到发送测试邮件的部分
要离开SES沙盒并向任何收件地址发送邮件,你需要申请生产权限并提供你已验证的域名。
AWS Lambda 函数现在,我们可以创建一个由SNS主题触发的Lambda函数。不过,我们需要创建一个IAM角色,以便Lambda函数可以被SNS主题触发。
- 在 AWS Management Console 中转到 IAM 服务。
前往IAM(身份与访问管理)
- 点击
角色
选项卡,然后点击创建角色
按钮。 - 选择
Lambda
服务,并将其作为服务或用例,并将其设为AWS 服务
,作为受信任的实体。
IAM角色的信任实体类型
添加以下策略:AWSLambdaBasicExecutionRole
和 AmazonSESFullAccess
IAM权限部分
- 输入角色名称(比如
LambdaUseSES
),然后单击创建角色按钮
。
创建好角色(Role)后,接下来我们就可以创建 Lambda 函数了。
- 在 AWS Management Console 中导航到 Lambda 服务。
- 点击
创建函数
按钮。
AWS Lambda 函数创建
- 选择
使用蓝图选项
并查找sns
蓝图。我们使用的是py3.10
的 SNS 集成。
使用蓝图来创建AWS Lambda函数
- 指定函数名(本例中为
notification-handler
)。 - 选择
使用现有角色
选项,然后选择我们之前创建的用于 Lambda 的角色LambdaUseSES
。
AWS Lambda 权限设置
- 在SNS触发器部分中,选择我们创建的
notifications
SNS主题。它会自动创建一个订阅。
AWS Lambda SNS 触发器
- 函数代码稍后会更新。
- 点击
创建函数
按钮来继续。
我们的 AWS Lambda 函数现在已设置为响应由 notifications
主题发送的 SNS 消息。
AWS Lambda 图解
最后一步就是更新Lambda函数的代码。我们将用下面这段代码。
import json
import boto3
client = boto3.client('ses', region_name='eu-central-1')
def lambda_handler(event, context):
data = json.loads(event['Records'][0]['Sns']['Message'])
body = data.get('body')
email = data.get('email')
response = client.send_email(
Destination={
'ToAddresses': ['verified@mail.com']
},
Message={
'Body': {
'Text': {
'Charset': 'UTF-8',
'Data': body,
}
},
'Subject': {
'Charset': 'UTF-8',
'Data': '预订邮件发送给:' + email,
},
},
Source='verified@mail.com'
)
print("发送邮件给:" + email)
return {
'statusCode': 200,
'body': json.dumps("邮件发送成功,MessageId 为: " + response['MessageId'])
}
在Lambda函数内部,我们可以使用boto3
包来使用SES服务发送邮件,而无需任何额外的配置。我们需要在代码中记录想要发送的邮件地址。由于我们处于沙箱模式,所以我们只能向经过验证的邮件地址发送邮件。因此,发送的邮件地址必须是我们在SES服务中验证过的地址。当代码准备就绪时,我们可以通过点击Deploy
来更新Lambda函数代码。新的Lambda函数版本已经准备好,可以通过SNS主题触发。
为了从头到尾测试它,我们可以运行 app.py
脚本来验证它。
$ python app.py
消息已发到SNS, 87633e01-380e-5060-a9a4-619089a9bc6a
邮件应该已经到了我们的邮箱。不过,给 Lambda 函数赋予 AWSLambdaBasicExecutionRole
权限后,它就可以访问 CloudWatch 日志了。怎么查看这个日志呢?
- 导航到您的Lambda函数的页面。
- 点击
监控(Monitoring)
选项卡。 - 点击
在CloudWatch中查看日志
按钮。
AWS Lambda 监控选项卡,
- 点击最新的一条日志流。(每个部署的版本都会有自己独立的日志流。)
AWS Lambda 日志流清单
- 看看日志。
AWS Lambda 日志流
我们可以看到请求 21c1841e-a6c2-4ecc-9856-fe6a1682454d
这一信息,成功发送邮件给 user+577461@example.com 的日志。邮件我也在我的收件箱里找到了。
收到了一封邮件
结论部分最终,虽然我们的示例Lambda函数很直接,但一个准备投入生产的版本应该考虑到更多的复杂性,例如重试机制、针对不同通知类型(电子邮件、短信、推送)的决策,以及强大的错误处理措施。需要仔细考虑这些场景,以确保可靠性和可扩展性。如果您对成本有所顾虑,可以使用诸如AWS定价计算器之类的工具来估算,根据您的使用情况估算Lambda的成本。
虽然 AWS Lambda 是一个强大的无服务器事件驱动工具,但重要的是要认识到它不是一个适用于所有情况的解决方案。了解它的局限性和它在某些特定场景中的优势是最大化利用此服务,特别是在分布式系统架构中的关键。
共同学习,写下你的评论
评论加载中...
作者其他优质文章