SQS 的 ApproximateReceiveCount 有多准确

How accurate is the ApproximateReceiveCount from SQS

我有一个系统,多个工作人员并行使用标准 SQS 队列。

我注意到当我有相对较多的消息(即 300 万条)时,我最后处理的总计数总是比消息总数多几条消息(大约 30 条)。 (多 0.001% ~ 0.002%)

我怀疑是因为 "At-least-once" 交货:

Amazon Doc: It is possible you will receive a message even after you have deleted it. This might happen on rare occasions if one of the servers storing a copy of the message is unavailable when you request to delete the message. The copy remains on the server and might be returned to you again on a subsequent receive request. You should create your system to be idempotent so that receiving a particular message more than once is not a problem.

因此,我想在处理之前使用"ApproximateReceiveCount"确定我的消息是否已被处理:

(Worker pseudocode)

List messages = sqs.receiveMessage()
for m in messages:
   if m.approximateReceiveCount > 1 then
      skip process
   else
      process as usual
end

我想知道这个 "approximateReceiveCount" 的准确性如何,让我的重复数据删除逻辑依赖于它是否是个好主意。

注意:

我已经设置了一个死信队列来处理任何花费时间超过 "Default Visibility Timeout"(设置为 1 小时)的消息。由于没有消息返回死信,我假设额外的计数不是由于此 "timeout" 影响。

您不能可靠地使用 approximateReceiveCount 属性 来删除重复邮件。因为如果你收到一条消息,然后失败,你的approximateReceiveCount可能是1,但消息仍然需要重新处理。

使用 SQS 时,最佳做法是确保您的 SQS 消息处理是 idempotent。这意味着多次处理同一条消息将产生相同的结果。

这意味着什么完全取决于您的业务逻辑。

  1. 您可以跟踪 SQS 消息 ID 以确定它们是否已被处理。
  2. 或者您可以在消息中使用其他 ID 来确定消息是否已被处理。
  3. 或者您可以多次处理数据,每次都得到相同的结果。

解决方案 1 或 2 可能难以可靠地实施,因为处理、跟踪和可能的故障之间可能存在竞争条件。

解决方案 3 可能是最好的,因为如果处理失败,您可能无法实际执行 1 或 2。

解决方案 1 或 2 的问题

示例 1:

假设你的逻辑如下:

  1. 从队列接收消息
  2. 处理消息
  3. 记录消息去重
  4. 从队列中删除消息

但是,如果您在第 2 步和第 3 步之间失败,或者在第 2 步和第 3 步之间另一个处理器第二次接收到消息,则您的重复数据删除逻辑失败。

示例 2:

或者,假设您的逻辑如下:

  1. 从队列接收消息
  2. 记录消息去重
  3. 处理消息
  4. 从队列中删除消息

现在,如果您在第 2 步之后或第 3 步期间失败(意味着处理永远无法正确完成),那么您将永远无法再正确处理您的消息。