跳到主要内容
英文版本为准

本页译自英文,由模型翻译。若与英文原文存在差异,以英文原文为准。

结算

ack、drop、retry 和 retry_after 在 Kinesis 上变成什么。Kinesis 为每个分片保存一个检查点,而不是逐条确认记录。

一个分片上的水位线:检查点停在第一个尚未结算的投递之前一个分片,记录按到达顺序排列1已结算2已结算3运行中4已结算5已结算6运行中检查点:记录 2第一个运行中的记录之前的最后一条LeaseStore::checkpoint持有租约时3 结算后,检查点移到 5:6 仍在运行
以文字阅读本图
  1. 检查点:记录 2 第一个运行中的记录 之前的最后一条 → 2 已结算: 指向
  2. 检查点:记录 2 第一个运行中的记录 之前的最后一条 → LeaseStore ::checkpoint 持有租约时: 写入
  3. 一个分片,记录按到达顺序排列
  4. 1 已结算
  5. 3 运行中
  6. 4 已结算
  7. 5 已结算
  8. 6 运行中
  9. 3 结算后, 检查点移到 5: 6 仍在 运行

检查点指定分片中的一条记录,表示它之前的每条记录都已处理。因此本 crate 按到达顺序跟踪每个分片的投递。结算把它的投递标为已处理,检查点移到从最旧的投递开始、连续已处理的那一段投递中的最后一条记录。并行工作分区发来的 ack 可以按任意顺序到达,检查点绝不会越过仍在运行的记录。结算只在推进检查点时才写入租约存储,并且只有本实例持有该分片时,存储才接受这次写入。

结果对分片的影响
ack已处理:没有更早的记录仍在运行时,检查点前移
drop已处理,与 ack 相同:检查点越过有毒的记录
retry()被拒绝(AckError::Unsupported)并记录日志:记录保持未处理并挡住检查点,下次获取该分片的租约时,从检查点重新读取该分片
在 max_attempts 或死信流下的 retry()一个计数的副本发往流,原记录算作已处理
retry_after(delay)延迟结束后,一个计数的副本发往流,原记录算作已处理
上限用尽记录发往死信流;没有死信流时,记录算作已处理,检查点越过它
关闭前没有结算检查点保持原位,分片的下一个所有者会再次读取该记录

分片按顺序读取,Kinesis 无法交回单条记录,因此重新入队被拒绝。读取者继续读取,该记录会在重启或租约移交之后,连同它之后的每条记录一起回来。投递是至少一次的。

seek 让它所移动的分片的水位线重新开始。对 seek 之前读到的投递进行结算不会改变任何东西,因此迟到的 ack 绝不会把检查点移回 seek 之前的位置。已关闭的分片只在它的每次投递都结算之后才标为 SHARD_END,它的子分片在那之后开始读取。

重试​

Kinesis 上的一次重试:尝试上限决定把副本发到流、发到死信流,还是让检查点越过该记录一条记录x-ruststream-retry-count 说明这是第几次尝试处理器返回retry_after(delay),或在有声明时返回 retry()max_attempts:这次尝试是否低于上限?低于上限:原记录结算,副本发往流到达上限:记录发往死信流到达上限,没有死信流:检查点越过该记录副本是位于最新处的新记录,落在其键选定的分片上延迟的副本保存在进程中:计时器触发前崩溃就会丢失它
以文字阅读本图
  1. 一条记录 x-ruststream-retry-count 说明这是第几次尝试 → 处理器返回 retry_after(delay),或在有声明时返回 retry(): 已处理
  2. 处理器返回 retry_after(delay),或在有声明时返回 retry() → max_attempts:这次尝试是否低于上限?: 重试
  3. max_attempts:这次尝试是否低于上限? → 低于上限: 原记录 结算,副本 发往流: 低于上限
  4. max_attempts:这次尝试是否低于上限? → 到达上限: 记录发往 死信流: 到达上限
  5. max_attempts:这次尝试是否低于上限? → 到达上限, 没有死信流: 检查点 越过该记录
  6. 低于上限: 原记录 结算,副本 发往流 → 副本是位于最新处的新记录, 落在其键选定的分片上
  7. 延迟的副本保存在进程中: 计时器触发前崩溃就会丢失它

Kinesis 既不扣留记录,也不统计投递次数,所以这两件事都由运行时来做。retry_after 结果,以及声明了 max_attempts 或 dead_letter 死信流的注册上的 retry(),都走这条路径。尝试次数随副本的 x-ruststream-retry-count 消息头传递,第一次投递算作一次。

副本发往订阅读取的流,也就是 KinesisStream 描述符报告的地址,因此注册无需指定目的地。副本落在最新处,位于其分区键选定的分片上,排在此后写入的记录之后。因此重试的记录会失去它与相邻记录之间的顺序。在这一顺序重要的地方,不要声明上限,让 retry() 挡住分片。流的每个消费者都会收到副本,而不只是发起重试的那个。

用尽尝试次数的记录连同它的载荷和消息头发往死信流。设置了上限却没有死信流时,记录按 drop 的方式了结。