65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 AWS SNS 和 Lambda 进行数据缓存同步

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2015年12月30日

CPOL

9分钟阅读

viewsIcon

19129

本文介绍了一种使用 AWS Lambda 和 SNS 的发布-订阅模型,用于保持 AWS 托管的 RDMB 记录系统和缓存同步。

引言

在本文中,我将介绍 Amazon Web Services (AWS) 中 SNS 发布-订阅功能的用例。我有一个混合 SQL Server-MongoDB 示例应用程序,用于管理一家虚构金融公司的账户持有人。SQL Server 数据库作为账户持有人数据的记录系统。应用程序使用 Entity Framework 将所有账户持有人数据的插入、更新和删除都提交到 SQL Server 数据库。MongoDB 文档数据库作为缓存,并且由于使用 NoSQL 文档数据库可以显著提高性能,因此用于搜索账户持有人。

虽然 AWS 可能不适用于所有数据同步问题,但如果您的数据缓存系统托管在 AWS 上,SNS 和 Lambda 可以提供一种优雅的解决方案来保持您托管在 AWS 上的缓存同步。本文将介绍以下 AWS 技术:

SNS 是 AWS 的发布-订阅消息服务,可用作云中企业消息传递的基础设施。 https://aws.amazon.com/sns/

Lambda 是 AWS 的一项服务,可让您在不配置或管理服务器的情况下运行代码。 https://aws.amazon.com/lambda/

AWS SDK for .NET 提供了与 AWS 服务交互的 API。 https://aws.amazon.com/sdk-for-net/

CloudWatch 是用于 AWS 云资源和运行在 AWS 上的应用程序的监控服务。 https://aws.amazon.com/cloudwatch/

下面是一张图,总结了集成 AWS SNS 和 Lambda 后数据同步的工作原理。

我假设您已经创建了一个 AWS 账户,并且可以访问 AWS 界面的 IAM、Lambda 和 SNS 部分。这是一个 Visual Studio 解决方案,因此我也假设您正在使用装有 Visual Studio 的 Windows 计算机,并且知道如何使用 NuGet 来安装 AWS SDK 包。

AWS 配置

创建 AWS IAM 用户以向 SNS 发送消息

在 AWS IAM 页面上,创建一个用户并为其附加 AWSSNSFullAccess 策略。 

AWS 会为用户创建一个访问密钥 ID秘密访问密钥。用户创建后,您将有机会仅查看和记录一次秘密访问密钥。一旦您离开该屏幕,出于安全目的,您可能无法再次从 AWS UI 中查看此用户的秘密访问密钥,因此您需要将其记录在 AWS 外部的安全位置。有关凭据安全最佳实践,请参阅 AWS 文档。

稍后在从应用程序代码连接到 AWS SNS 时,您将需要访问密钥 ID 和秘密访问密钥。

创建 SNS 主题

在 SNS 页面上,创建一个主题。记录主题 ARN 和区域,因为您将在应用程序代码中向 SNS 主题发送消息时需要这些信息。

创建 Lambda 函数

在此示例中,我们将使用 Python 创建一个 Lambda 函数,但您也可以使用 Node.JS。

首先,您需要在本地计算机上创建一个单独的文件夹来存储 Python 脚本以及稍后将要讨论的依赖 Python 模块。我将我的文件夹命名为“AWSLambdaUpdatePerson”。然后,我在新文件夹中创建了一个名为 AWSLambdaUpdatePersonMongo.py 的 Python 脚本。该脚本定义了一个事件处理程序,该处理程序使用 MongoDB Python 库连接到 AWS EC2 机器上的 MongoDB 实例,并使用事件消息体中的 JSON 更新 person 集合。我使用消息的主题来存储正在更新的 person 记录的 ID。当 SNS 在收到应用程序的消息时通知其订阅者时,Lambda 函数中的事件处理程序将被调用。事件处理程序中的 event 参数包含来自 SNS 的消息。

from __future__ import print_function

import json
import pymongo

def lambda_handler(event, context):
    # Open a connection to the Mongo instance on EC2
    client = pymongo.MongoClient("mongodb://****")

    # Get a reference to the footloosefs Mongo database
    db = client.footloosefs

    # The ID of the person we are updating will be in the subject
    personId = event['Records'][0]['Sns']['Subject']

    # The message will contain the JSON of the person attributes
    message = event['Records'][0]['Sns']['Message']
    
    print("From SNS: " + message)    
    print("From SNS: " + personId)  

    if personId:
        
         # Remove the document representing the person from the collection
        db.persons.remove( { "_id" : int(personId)  } )

        # Add the message with the updated person to the collection
        db.persons.insert_one( json.loads(message) )

        print("Processed insert or update for person: " + personId)

    return

SNS 消息包含 person 要在 persons MongoDB 集合中更新的 JSON 格式数据。Python 脚本连接到 MongoDB 实例,删除任何现有的 person 文档,并使用 SNS 消息体中的 JSON 插入新 person 文档。

由于 Python 脚本依赖于 MongoDB Python 库 pymongo,因此我们需要在此脚本所在的文件夹中下载依赖的 Python 库。为此,我们需要安装 Python。

由于我使用的是 Windows 计算机,因此我使用的是 Windows 版 Python 3.5,我从 Python Windows 下载网站安装的:https://pythonlang.cn/downloads/windows/。Python 3.5 的好处是它预装了 pip。pip 是安装自定义 Python 库的首选 Python 安装程序。

我还安装了 7-Zip 用于创建存档。 http://www.7-zip.org/

为了方便起见,我在同一个文件夹中创建了一个 BAT 文件,它运行以下命令:

    python -m pip install pymongo -t AWSLambdaUpdatePerson

    7z a awslambda.zip AWSLambdaUpdatePerson\*

python 命令运行 pip,它将 pymongo 及其所有依赖项安装到文件夹中。请注意,pip 命令将使用 Internet 访问 Python 中央存储库并下载 MongoDB Python 库,这类似于 NuGet 的工作方式。7z 命令将文件夹的全部内容压缩到 zip 文件 awslambda.zip 中。如何创建 zip 文件由您决定,但它必须包含 Python 脚本文件以及不属于 AWS Python SDK(也称为 Boto3)的任何依赖项。

这是我的 zip 文件。bson 和 gridfs 文件夹是 pymongo 所必需的,因此它们是由 pip 以及核心 pymongo 库下载的。

最后,我们将进入 AWS 控制台创建 Lambda 并上传 zip 文件。

从 AWS Lambda 登录页面,点击“立即开始”按钮。然后点击右下角的“跳过”按钮(基本上我们跳过蓝图选择,因为我们已经有了 Lambda 的代码)。在下一个屏幕中,为 Lambda 输入名称和描述,然后选择 Python 2.7 作为运行时。您需要记住 Lambda 的名称,以便在下一个部分创建 SNS 订阅时使用。

然后选择“上传 ZIP”并上传您创建的 zip 文件。

在 Handler 输入框中,将处理程序函数名称更改为您创建的 Python 脚本的名称。因此,将“lambda_function.lambda_handler”更改为“AWSLambaUpdatePersonMongo.lambda_handler”。

此时,系统会提示您使用现有角色或为脚本创建一个新的 Lambda 基本角色。

然后点击“下一步”按钮,您将看到一个确认页面,然后点击“创建”。

创建 SNS 订阅

现在我们需要创建一个 SNS 订阅,以便在我们的应用程序代码将消息发送到 SNS 主题时调用 Lambda 函数。

转到 SNS 主题列表页面,选择您之前创建的主题。在“操作”菜单中,选择“订阅主题”。在对话框中,选择“AWS Lambda”作为协议,然后选择您创建的 Lambda。然后点击“创建订阅”按钮。

发送通知到 SNS 的应用程序代码

使用 NuGet 安装 AWS SDK

使用 NuGet 将 AWSSDK.Core 和 AWSSDK.SimpleNotificationService 库安装到您的 Visual Studio 项目中。我在示例中使用了 ASKSDK 版本 3.1。由于我的应用程序涉及将对象序列化为 JSON,因此我还通过 NuGet 安装了 Newtonsoft JSON 库。

存储 AWS 用户凭据

使用 AWS 服务的应用程序必须使用具有使用请求服务权限的身份进行身份验证。之前我们创建了一个具有发布消息到 SNS 权限的 AWS 用户。现在我需要向应用程序提供凭据(访问密钥 ID 和秘密访问密钥)。我没有将凭据硬编码在代码或 web.config 中,而是在本地计算机上创建了一个包含凭据的文件,并将 AWS SDK 指向该文件的位置。

该文件包含配置文件的名称、访问密钥 ID 和秘密访问密钥,格式如下(请注意,实际凭据已用***** 屏蔽)。

[UpdatePersonCollection]

aws_access_key_id = *****

aws_secret_access_key = *****

在我的机器上,我将文件命名为“credentials”,位于 C:\awsprofiles。

然后,我在 web.config 的 appSettings 部分中包含了以下键值对。AWSProfileName 键引用了凭据文件中的文件名,AWSProfileLocation 指示 AWS SDK 凭据文件的位置。

    <add key="AWSSNSTopicArn" value="arn:aws:sns:us-east-1:127504306426:FootlooseFSPersonUpdate"/>

    <add key="AWSProfileName" value="UpdatePersonCollection"/>

    <add key="AWSProfilesLocation" value="C:\awsprofiles\credentials" />

还有其他存储 AWS 凭据的方法。您可以在 AWS 文档链接中查看它们: http://docs.aws.amazon.com/AWSSdkDocsNET/latest/V3/DeveloperGuide/net-dg-config-creds.html

使用 ASK SDK 向 SNS 发送消息

现在我们已经安装了 AWS SDK Core 和 SNS 库,并设置了我们的凭据和 web.config,我们可以编写发送消息到 SNS 主题的代码。下面的代码将基于更新后的 Person EF 实体创建一个新的 PersonDocument 对象,使用 Newtonsoft JSON 序列化器序列化该对象,并将消息发送到 AWS SNS 主题。

// Convert the Person Entity to a PersonDocument for MongoDB
var personDocument = new PersonDocument();

personDocument.PersonID = person.PersonID;
personDocument.EmailAddress = person.EmailAddress;
personDocument.FirstName = person.FirstName;
personDocument.LastName = person.LastName;
personDocument.PhoneNumber = person.Phones.Any(p => p.PhoneTypeID == 1) ? person.Phones.First(p => p.PhoneTypeID == 1).Number : string.Empty;

var address = person.Addresses.Any(a => a.AddressTypeID == 1) ? person.Addresses.First(a => a.AddressTypeID == 1).Address : null;

if (address != null)
{
  personDocument.StreetAddress = address.StreetAddress;

  personDocument.City = address.City;

  personDocument.State = address.State;

  personDocument.Zip = address.Zip;
}

// Serialize the PersonDocument object into a JSON string
var message = JsonConvert.SerializeObject(personDocument);

// Connect to AWS SNS
var topicArn = ConfigurationManager.AppSettings["AWSSNSTopicArn"];
var snsClient = new AmazonSimpleNotificationServiceClient(RegionEndpoint.USEast1);
          
try
{                
      // Send the message to the SNS Topic      
      var publishRequest = new Amazon.SimpleNotificationService.Model.PublishRequest();
      publishRequest.TopicArn = topicArn;
      publishRequest.Message = message;
      publishRequest.Subject = personId.ToString();

      snsClient.Publish(publishRequest);

      return true;
}
catch (Exception ex)
{
       // TODO Log exception
       return false;
}                       

当 AmazonSimpleNotificationServiceClient 被实例化时,AWS SDK 会尝试在 web.config 中指定的​​位置查找身份验证凭据。请注意,我们将 person ID 存储在消息的主题中。通过主题 ARN 端点、主题和消息,AmazonSimpleNotificationServiceClient 对象将消息发布到 AWS SNS 系统。

应用程序演示时间!

现在,让我们作为应用程序的用户来查看发布-订阅过程的实际操作。账户持有人(person)搜索屏幕使用户能够按多个属性查询账户持有人。这些查询是在 AWS EC2 机器上的 MongoDB person 文档集合上运行的。

在此屏幕中,我们选择一个人来修改该人的信息。

在此示例中,我们将 Marcia Aalderink 的电子邮件地址从 hotmail.com 更改为 gmail.com。然后我们保存了表单。保存表单,除了将信息保存到我们的 SQL Server 记录系统外,还会执行我们之前看到的 C# 代码片段,该代码片段创建一个 PersonDocument 对象,序列化该对象,并将消息发送到 SNS。

然后我们立即返回搜索屏幕,该屏幕在我们返回时会刷新。在搜索结果中,我们看到 Marcia 的电子邮件地址已在 MongoDB 数据库中更新。这意味着在很短的时间内,SNS 收到了消息,将其转发给了 Lambda 订阅者,并且 Lambda 函数被执行了。

 

AWS Lambda 的执行会记录在 CloudWatch 系统中。要查看 Lambda 日志,请从 Amazon Web Services 登录页面转到“CloudWatch”并选择“Logs”。然后从日志列表中选择 Lambda。 您可以查看 Lambda 何时执行、消息主题、发送到 Lambda 的消息内容、发送消息的系统、Lambda 执行所需的时间以及使用的内存量。

您还可以通过 CloudWatch 设置警报,以便在 Lambda 函数运行出现任何异常时发送通知。

感谢您的阅读,如果您有使用 AWS SNS 和 Lambda 的经验,我很想听听您的经验或任何一般性建议。

© . All rights reserved.