本页译自英文,由模型翻译。若与英文原文存在差异,以英文原文为准。
结算
ack、retry、drop 和 retry_after 在 Redis 流、可靠列表、简单列表和 Pub/Sub 上变成什么。
以文字阅读本图
- 结果: ack; retry; drop
- 流: XACK; XADD 副本 再 XACK; XACK
- 认领式: XACK; 保持 待处理; XACK
- 可靠列表: LREM; LPUSH 再 LREM; LREM
- 无确认: 不支持; 不支持; 不支持
运行时用处理器返回的结果结算每次投递,本 crate 把结果映射到该形式自己的确认。流在订阅的组里用 XACK 确认。可靠列表用 LREM 把条目从它的处理中列表移除。简单列表和 Pub/Sub 没有可确认的东西,在那里结算会返回 AckError::Unsupported。结算命令走连接池,而不是订阅的读取客户端。
流上的重试把条目的副本追加到同一个流,然后确认原条目。两步之间崩溃,留下的是重复,而不是丢失。认领式订阅则通过待处理条目列表重试。它什么也不追加,也不确认;条目空闲达到 min_idle 之后,下一次读取把它认领回来,id 不变,投递次数加一。可靠列表先把条目推回队列,再把它从处理中列表移除。
带延迟的重试
以文字阅读本图
- 运行时副本: XACK 原条目; 副本保存在 进程中: 崩溃即丢失; 计时器触发时 XADD 副本
- 延迟队列: 对流条目返回 retry_after(delay); ZADD 副本, 再 XACK; 在 Redis 中, 以到期时间 为分值; 由读取清扫: XADD 回到流
- 认领式: 留在待处理 条目列表中; min_idle 之后 被认领回来
- 对流条目返回 retry_after(delay) → XACK 原条目
- 对流条目返回 retry_after(delay) → ZADD 副本, 再 XACK
- 对流条目返回 retry_after(delay) → 留在待处理 条目列表中
- XACK 原条目 → 副本保存在 进程中: 崩溃即丢失
- 副本保存在 进程中: 崩溃即丢失 → 计时器触发时 XADD 副本: 延迟
- ZADD 副本, 再 XACK → 在 Redis 中, 以到期时间 为分值
- 在 Redis 中, 以到期时间 为分值 → 由读取清扫: XADD 回到流: 到期
- 留在待处理 条目列表中 → min_idle 之后 被认领回来: 空闲
Redis 没有针对单个条目的延迟,因此流订阅用三种方式之一提供 retry_after。默认情况下,运行时确认原条目并持有一个副本,延迟到期时把副本发布回流。副本的重试计数加一。计时器触发前崩溃,副本就会丢失。
delayed_retry 配合 DelayedRetry::DurableZset 可以把副本保存在 Redis 中。副本先加入一个以到期时间为分值的有序集合,然后原条目才被确认。每次读取先用 XADD 把到期的副本移回流上,每次最多 128 个,因此延迟的误差不超过一个 block 间隔。分值是挂钟时间的毫秒数,所以共享同一队列的各个服务,时钟应当一致。
认领式订阅让条目保持待处理,min_idle 过去之后,下一次读取把它认领回来。短于 min_idle 的延迟也要等满 min_idle。
列表订阅和 Pub/Sub 订阅使用运行时的副本,副本回到列表或频道。模式订阅的副本发往何处,在它的挂载点指定。
max_attempts 上限用两个计数之一统计尝试次数,用哪一个由订阅形式决定。认领模式和回收模式使用服务器在待处理条目列表中记录的投递次数。其他所有形式使用副本携带的重试计数消息头,延迟队列每一轮都会把它加一。