【问题标题】:What is the recommended way to fanout in SQS lambda environment?在 SQS lambda 环境中扇出的推荐方法是什么?
【发布时间】:2020-05-25 18:27:03
【问题描述】:

我想通过 SQS / 消息队列架构在 lambda 环境中向我的数据库中的用户发送推送通知,以便做到这一点

  1. 我首先需要查询数据库中启用推送通知的所有用户。
  2. 遍历所有这些
  3. 为每个用户发送 SQS 事件/消息。
  4. 让我的 sqs 触发的 lambda 处理/发送推送通知

有没有更好的方法来实现这一点,以避免查询大量用户和/或循环遍历所有结果来为每个用户发送 SQS 消息?

【问题讨论】:

  • 仅供参考,您可以批量发送和接收 SQS 消息。
  • SQS 触发的 lambda 是否必须查找有关用户的信息才能知道将通知发送到何处,或者是否所有信息都在步骤 1 中收集?
  • 你是Using Amazon SNS Mobile Push吗?您是否向所有用户发送完全相同的消息?这是一条短信,还是推送到他们设备上的移动应用程序?您是将其发送给 ALL 用户,还是只是基于某些逻辑的子集?该组是否可能被重复使用,或者每封邮件的收件人列表是否不同? (请随意编辑您的问题以添加这些详细信息,而不是通过评论来回答。)
  • @JasonWadsworth 都聚集在 Step1 中,SQS 触发的 lambda 只需使用接收到的信息调用 PushNotification 服务
  • @JohnRotenstein 我没有使用 SNS,我使用的是 firebase 云消息传递。它是对移动应用程序的推送通知。是的,是相同的消息,并且仅针对基于某些逻辑的一部分用户。收件人列表可能会有所不同,因为它基于事件和用户偏好。

标签: amazon-web-services aws-lambda architecture amazon-sqs serverless-framework


【解决方案1】:

我会在这里采取稍微不同的方法,但类似。

  1. 为用户查询数据库
  2. 遍历用户
  3. 向SQS发送一条消息,用于发送一批记录,使用SQS的SendMessageBatch操作发送。所以一批批。每批消息都会有几个“用户”要发送给,而不仅仅是一个。这应该会提高您的性能,因为批处理将需要更少的 lambda 调用。
  4. Lambda 处理 SQS 消息(可能不止一条),每条 SQS 消息都会导致发送许多推送通知。在 Firebase 的情况下,我相信有一种方法可以发送批次,这会更好。即使没有,您也可以使用 Promise.all 类型逻辑一次发送多条消息。

使用这种结构,您可以非常快速地发送大量消息,而且可能会便宜很多。想象一下,您需要发送给 100 万用户。如果您批量发送 100 条,每批 25 条发送到 SQS,那么每次调用 SQS 有 2,500 条消息。这意味着对 SQS 的 400 次调用,甚至比如果您分批发送 25 条消息所必须进行的 40K 次要好得多。

在接收端,即使您将 SQS 集成限制为每次调用 1 条消息,您也会有 10,000 次 lambda 调用。如果您假设每次调用甚至 1 秒,以及 1000 次并发调用,则需要 10 秒(可能更少)。如果您为每个用户发送一条消息,则必须进行 1M 次 lambda 调用。如果您假设每次调用需要 100 毫秒,那么您可以发送 10/秒,因此如果有 1000 次并发执行,则需要 100 秒。实际上,这些数字可能比批处理版本的数字还要好,尤其是如果您不将其限制为一次 1 条消息。

编辑 根据 cmets,问题似乎更多的是关于过程的第一部分。考虑到这一点,我建议以下选项。

  1. 如果您发现自己需要重复处理相同的大型群组,大多数消息服务(当然是 Firebase 和 SNS)都支持某种主题订阅模型。鉴于这些是推送通知,您可以在代码中为设备订阅主题。这最终会导致一条消息从您的代码发送到消息传递服务。该服务处理其余部分。这可能是任何有大量收件人的首选解决方案,特别是如果您可以预先知道收件人。这甚至适用于动态主题。例如,考虑一个人在帖子上遇到的情况。对该帖子的任何新评论都应向所有对该帖子发表评论的人发送消息。您可以在创建帖子时即时创建主题,并在他们发表评论时将收件人添加到主题中。如果用户希望停止接收消息,您可以从主题中删除该用户。
  2. 如果您事先不知道收件人,上述解决方案是一个可靠的解决方案。但是,如果您担心前两个步骤中的 Lambda 超时,我会稍作修改。我会利用 AWS Step Functions 并在 lambda 中分页数据。 Lambda 将通过调用中提供的context 对象告诉您还剩多少时间。您可以定期检查以确定是否应该退出 lambda 并将当前分页信息传递给 step 函数。 step 函数可以将该分页信息传递回 lambda,它应该被编码为接受分页信息作为请求的一部分,并从该点继续(如果提供)。

【讨论】:

  • 虽然这提供了一种优化,但它并没有真正回答问题的关键,有没有比查询所有数据、循环和队列更好的方法。也许是一个不同的架构来更早地为这个事件做准备,或者一些解决 lambda 超时或错误的解决方案?
  • 我明白你的意思。我将添加一些用于优化前端部分的 cmets/options。
【解决方案2】:

我建议在您的应用程序架构中增加一个部分,
我个人更喜欢避免使用主数据库进行繁重的查询,
假设您拥有庞大的用户群。

我建议在 ElasticSearch 或 CloudSearch 等搜索引擎中维护您的用户列表,或者在 AWS DynamoDb 中仅包含用户列表的简单表,或者创建数据库的只读副本。
为了不让您感到困惑,请使用搜索引擎(首选)或 AWS DynamoDb

这将避免在查询读取专用数据存储时对数据库造成压力,并且不会影响其他运行中的模块
而且这种方式查询速度很快

第 2 步:遍历所有这些

第 3 步:使用 Jason 建议的 SendMessageBatch 方法向 SQS 批量发送消息

第 4 步:根据您的 SQS 设置,您可以在 Lambda 函数上处理多条消息

【讨论】:

  • 这只是移动扫描一个数据库寻找另一个。搜索组件是针对用户子集的一个很好的建议,但问题是关于提取和加载到队列的最佳方式。
  • @noetix 我想​​知道如何避免该循环,搜索将使查询问题的处理速度更快,但是循环嗯,这个周末想想有趣的事情哈哈
  • 如果您想将相同的消息发送到群组(架构解决),或者随着时间的推移分配加载并批量查询数据库,我认为答案在于订阅频道。两者各有利弊,我希望赏金会浮出水面。
  • 这可以通过 AWS SNS 完成,因为它为每个主题提供 1000 万个订阅,但应用程序将需要以某种方式强制其用户接受 SNS 订阅,但我相信要发送的每封电子邮件都需要自定义消息,使用 SNS 将更像是一个常见的消息用例
猜你喜欢
  • 1970-01-01
  • 2017-01-25
  • 1970-01-01
  • 2010-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-20
相关资源
最近更新 更多