亚马逊AWS官方博客

Amazon SNS FIFO(先进先出)发布/订阅消息传递简介

在设计分布式软件体系结构时,定义服务交换信息的方式非常重要。例如,使用异步通信解耦组件和简化缩放,从而减少更改带来的影响,并使新功能发布变得更加容易。

异步服务到服务通信的两种最常见形式是消息队列发布/订阅消息传递

  • 使用消息队列时,消息将存储在队列中,直到消息被使用者处理和删除。在 AWS 上,Amazon Simple Queue Service (SQS) 提供完全托管的消息队列服务,无需管理开销。
  • 通过发布/订阅消息传递,发布到某个主题的消息将传递给该主题的所有订阅者。在 AWS 上,Amazon Simple Notification Service (SNS) 是一种完全托管的发布/订阅消息传递服务,可向大量订阅者传递消息。每个订阅者还可以设置筛选策略,只接收其感兴趣的消息。

当您想要将消息扇出到多个应用程序时,可以使用主题,当想要向一个应用程序发送消息时,可以使用队列。将主题和队列结合使用,可以将微服务分布式系统无服务器应用程序解耦。

借助 SQS,您可以使用 FIFO(先进先出)队列来保留消息发送和接收的顺序,并避免多次处理一条消息。

SNS FIFO 主题简介
现在,我们通过引入 SNS FIFO 主题,增加类似的发布/订阅消息传递功能,为一个或多个订阅者提供严格的消息排序和去除重复的消息传递。

FIFO 主题管理排序和重复数据删除的方式与 FIFO 队列类似:

排序 – 在向 FIFO 主题发布消息时,可以通过包括消息组 ID 来配置消息组。对于每个消息组 ID,所有消息都按照到达顺序进行发送和传递。例如,要确保按顺序传递与同一客户相关的消息,您可以使用客户的账号作为消息组 ID 将这些消息发布到主题。FIFO 主题和队列的消息组数量没有限制。您不需要事先声明消息组 ID,任何值都可以正常工作。如果在消息之间没有逻辑区分,则可以简单地为所有消息使用相同的消息组 ID,这样将产生单独的一组有顺序的消息。消息组 ID 将传递给任何已订阅的 FIFO 队列

重复数据删除 – 分布式系统(如 SNS)和客户端应用程序有时会生成重复的消息。您可以通过两种方式避免来自主题的重复消息传递:在主题上启用基于内容的重复数据删除,或者向您发布的消息添加重复数据删除 ID。借助基于内容的重复数据删除功能,SNS 可对消息正文使用 SHA-256 哈希来生成消息重复数据删除 ID。成功发布具有特定重复数据删除 ID 的消息后,在 5 分钟的时间内,具有相同重复数据删除 ID 的所有消息都将被接受但不会传递。如果为 FIFO 队列订阅 FIFO 主题,则重复数据删除 ID 将传递给队列,并且 SQS 将使用它来避免接收重复消息

您可以将 FIFO 主题和队列结合使用,以简化操作顺序和事件至关重要或者无法容忍重复的应用程序实施。例如,处理财务操作和库存更新,或异步应用从客户端设备收到的命令。 FIFO 队列可以使用 FIFO 主题中的消息筛选功能来有选择地接收消息的子集,而不是发布到主题的每条消息。

如何使用 SNS FIFO 主题
FIFO 主题经常用于在收到需要按顺序处理的更新时提供帮助。例如,我可以使用 FIFO 主题从客户编辑其账户配置文件的应用程序接收更新。然后,我订阅 SQS FIFO 队列到 FIFO 主题,并使用该队列作为 Lambda 函数的触发器,该函数将账户更新应用到客户管理系统使用的 Amazon DynamoDB 表,该表需要保持同步。

FIFO 主题带来的解耦能力使添加新功能变得更加容易,并且对现有应用程序的影响最小。例如,为了给我的忠实客户提供额外促销作为奖励,我添加了一个新的 Loyalty 应用程序,该应用程序将信息存储在由 Amazon Aurora 管理的关系数据库中。为了保持 Loyalty 数据库中存储的客户信息与我的其他应用程序同步,我可以为相同的 FIFO 主题订阅一个新的 FIFO 队列,并添加新的 Lambda 函数,该函数按照生成顺序接收客户更新,并将更新应用至 Loyalty 数据库。通过这种方式,我不需要更改其他应用程序的代码和配置就能集成新的 Loyalty 应用程序。

首先,我在 SQS 控制台创建两个 FIFO 队列,将所有选项保留为默认值:

  • customer.fifo 队列用于处理客户管理系统中的更新。
  • loyalty.fifo 队列帮助我收集和存储用于 Loyalty 应用程序的客户更新。

SNS 控制台中,我创建 updates.fifo 主题。选择 FIFO 作为类型,并启用基于内容的消息重复数据删除

然后,订阅 customer.fifoloyalty.fifo 队列到该主题。

为了能够接收消息,我在两个队列的访问策略中添加一个语句,授予 updates.fifo 主题向队列发送消息的权限。例如,对于 customer.fifo 队列,该语句为:

{
  "Effect": "Allow",
  "Principal": {
    "Service": "sns.amazonaws.com"
  },
  "Action": "SQS:SendMessage",
  "Resource": "arn:aws:sqs:us-east-2:123412341234:customer.fifo",
  "Condition": {
    "ArnLike": {
      "aws:SourceArn": "arn:aws:sns:us-east-2:123412341234:updates.fifo"
    }
  }
}

现在,我使用 SNS 控制台按顺序发布 4 条消息,并为所有消息使用相同的消息组 ID。这样,它们将位于同一个消息组中。唯一不同的部分是消息正文,其中按顺序使用了以下内容:

  • Update One
  • Update Two
  • Update Three
  • Update One

在 SQS 控制台中,我只看到 3 条消息被传递到 FIFO 队列:

这是为什么? 在创建 FIFO 主题时,我启用了基于内容的重复数据删除功能。在 5 分钟的重复数据删除时段内,一共发送了 4 条消息。最后一条消息被识别为第一条消息的副本,但尚未传递到已订阅的队列。

我们来看一看队列中的实际消息。我使用 AWS 命令行界面 (CLI) 接收来自 SQS 的消息,使用 jq 命令行 JSON 处理器来格式化输出,并在正文中仅获取消息

以下是 customer.fifo 队列中的消息:

$ aws sqs receive-message --queue-url https://sqs.us-east-2.amazonaws.com/123412341234/customer.fifo --max-number-of-messages 10 | jq '.Messages[].Body | fromjson | .Message'

"Update One"
"Update Two"
"Update Three"

以下是 loyalty.fifo 队列中的消息:

$ aws sqs receive-message --queue-url https://sqs.us-east-2.amazonaws.com/123412341234/loyalty.fifo --max-number-of-messages 10 | jq '.Messages[].Body | fromjson | .Message'

"Update One"
"Update Two"
"Update Three"

如我所料,3 条具有唯一内容的消息已按发送顺序传递到两个队列。

现已推出
您可以在所有商业区域使用 SNS FIFO 主题。 每个 FIFO 主题或 FIFO 队列每秒最多可以处理 300 个事务 (TPS)。 通过 SNS,您只需按实际使用量付费,您可以在定价页面找到更多信息。

要了解更多信息,请参阅文档

Danilo