将 AWS Lambda 集成到分布式系统中是一种利用无服务器计算优势的强大方法,可以在无需管理基础设施的情况下执行代码。AWS Lambda 在事件驱动架构模式中表现出色,其中函数会在响应特定事件时被触发,通过仅对使用的计算时间收费来实现成本效益。在使用 Lambda 的过程中,保证函数是无状态这一点非常重要,这意味着它们不应在不同的调用之间存储状态。然而,触发 Lambda 函数需要与诸如 SNS 或 SQS 等其他 AWS 服务进行集成,这会增加架构的复杂性,因此全面理解系统设计至关重要。
在本文中,我将展示如何将AWS Lambda用作通知服务的一部分,其中SNS用来发布消息到主题,Lambda将被触发来处理这些通知。我们将逐步配置所需的AWS服务,包括IAM、SNS、SES和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 Lambda 作为通知服务。然而,我们无法从代码中触发 Lambda 函数。例如,我们可以利用 AWS 简单通知服务(SNS)发布消息到一个主题,然后 Lambda 函数可以订阅该主题。AWS Lambda 处理程序函数可以封装通知逻辑(例如选择通知类型、用户白名单等),但不能直接发送电子邮件和短信。可以使用 AWS 简单电子邮件服务(SES)发送电子邮件。
预订系统架构,其中包括 AWS Lambda 作为其中的通知服务
我们的预订服务应提供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 IAM
Create user
按钮。用户页
用户名区域
直接附加策略
的权限选项。AmazonSNSFullAccess
用户权限设置
创建访问密钥
。我的页面
创建了一个用户账号
export: ACCESS_KEY_ID = 将你的access_key_id export: SECRET_ACCESS_KEY = 将你的secret_access_key
接下来,我们需要创建一个SNS,用来发布消息。
新建主题
按钮并点击 下一步 >
SNS 话题 banner
创建话题
。zh: SNS话题模板
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 Lambda函数之前,我们需要配置AWS简单邮件服务(SES)来发送邮件。默认SES服务是在沙盒模式下运行,这意味着您只能向经过验证的电子邮件发送信息。如果要向任何邮箱发送邮件,您需要申请进入生产环境。在我们的例子中,我们将继续使用沙盒模式。
SES 邮件验证, 部分
SES领域部分
完成验证过程
SES 配置页面概要
在SES配置面板里找到发送测试邮件的部分
要离开SES沙盒并向任何收件地址发送邮件,你需要申请生产权限并提供你已验证的域名。
现在,我们可以创建一个由SNS主题触发的Lambda函数。不过,我们需要创建一个IAM角色,以便Lambda函数可以被SNS主题触发。
前往IAM(身份与访问管理)
角色
选项卡,然后点击 创建角色
按钮。Lambda
服务,并将其作为服务或用例,并将其设为 AWS 服务
,作为受信任的实体。IAM角色的信任实体类型
添加以下策略:AWSLambdaBasicExecutionRole
和 AmazonSESFullAccess
IAM权限部分
LambdaUseSES
),然后单击 创建角色按钮
。创建好角色(Role)后,接下来我们就可以创建 Lambda 函数了。
创建函数
按钮。AWS Lambda 函数创建
使用蓝图选项
并查找 sns
蓝图。我们使用的是 py3.10
的 SNS 集成。使用蓝图来创建AWS Lambda函数
notification-handler
)。使用现有角色
选项,然后选择我们之前创建的用于 Lambda 的角色 LambdaUseSES
。AWS Lambda 权限设置
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 日志了。怎么查看这个日志呢?
监控(Monitoring)
选项卡。在CloudWatch中查看日志
按钮。AWS Lambda 监控选项卡,
AWS Lambda 日志流清单
AWS Lambda 日志流
我们可以看到请求 21c1841e-a6c2-4ecc-9856-fe6a1682454d
这一信息,成功发送邮件给 user+577461@example.com 的日志。邮件我也在我的收件箱里找到了。
收到了一封邮件
最终,虽然我们的示例Lambda函数很直接,但一个准备投入生产的版本应该考虑到更多的复杂性,例如重试机制、针对不同通知类型(电子邮件、短信、推送)的决策,以及强大的错误处理措施。需要仔细考虑这些场景,以确保可靠性和可扩展性。如果您对成本有所顾虑,可以使用诸如AWS定价计算器之类的工具来估算,根据您的使用情况估算Lambda的成本。
虽然 AWS Lambda 是一个强大的无服务器事件驱动工具,但重要的是要认识到它不是一个适用于所有情况的解决方案。了解它的局限性和它在某些特定场景中的优势是最大化利用此服务,特别是在分布式系统架构中的关键。