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。这意味着多次处理同一条消息将产生相同的结果。
这意味着什么完全取决于您的业务逻辑。
- 您可以跟踪 SQS 消息 ID 以确定它们是否已被处理。
- 或者您可以在消息中使用其他 ID 来确定消息是否已被处理。
- 或者您可以多次处理数据,每次都得到相同的结果。
解决方案 1 或 2 可能难以可靠地实施,因为处理、跟踪和可能的故障之间可能存在竞争条件。
解决方案 3 可能是最好的,因为如果处理失败,您可能无法实际执行 1 或 2。
解决方案 1 或 2 的问题
示例 1:
假设你的逻辑如下:
- 从队列接收消息
- 处理消息
- 记录消息去重
- 从队列中删除消息
但是,如果您在第 2 步和第 3 步之间失败,或者在第 2 步和第 3 步之间另一个处理器第二次接收到消息,则您的重复数据删除逻辑失败。
示例 2:
或者,假设您的逻辑如下:
- 从队列接收消息
- 记录消息去重
- 处理消息
- 从队列中删除消息
现在,如果您在第 2 步之后或第 3 步期间失败(意味着处理永远无法正确完成),那么您将永远无法再正确处理您的消息。
我有一个系统,多个工作人员并行使用标准 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。这意味着多次处理同一条消息将产生相同的结果。
这意味着什么完全取决于您的业务逻辑。
- 您可以跟踪 SQS 消息 ID 以确定它们是否已被处理。
- 或者您可以在消息中使用其他 ID 来确定消息是否已被处理。
- 或者您可以多次处理数据,每次都得到相同的结果。
解决方案 1 或 2 可能难以可靠地实施,因为处理、跟踪和可能的故障之间可能存在竞争条件。
解决方案 3 可能是最好的,因为如果处理失败,您可能无法实际执行 1 或 2。
解决方案 1 或 2 的问题
示例 1:
假设你的逻辑如下:
- 从队列接收消息
- 处理消息
- 记录消息去重
- 从队列中删除消息
但是,如果您在第 2 步和第 3 步之间失败,或者在第 2 步和第 3 步之间另一个处理器第二次接收到消息,则您的重复数据删除逻辑失败。
示例 2:
或者,假设您的逻辑如下:
- 从队列接收消息
- 记录消息去重
- 处理消息
- 从队列中删除消息
现在,如果您在第 2 步之后或第 3 步期间失败(意味着处理永远无法正确完成),那么您将永远无法再正确处理您的消息。