我很难理解领导者何时真正确认客户。这是 DistributedLog文档的一部分:
每个附加到日志段的批处理条目将由日志段编写器分配一个单调递增的条目 ID。所有条目都异步写入管道中。因此,日志段写入器会更新内存中的指针,称为 LAP (LastAddPushed),它是写入器推送到日志段存储的最后一个批处理条目的条目 id。条目可以乱序写入,但只能按条目 ID 顺序进行确认。除了成功确认之外,日志段编写器还更新内存中的指针,称为 LAC (LastAddConfirmed)。LAC 是作者已经确认的最后一个条目的条目 ID。在 LAC 和 LAP 之间写入的所有条目都是未确认的数据,它们对读者不可见。
读取器可以读取高达 LAC 的条目,因为已知这些条目是持久复制的 - 因此可以安全地读取,而不会违反读取顺序的风险。writer 在发送给 BookKeeper 的每个条目中都包含当前 LAC。因此,每个后续条目都会使前一个条目中的记录对读者可见。LAC 更新可以搭载在编写器写入的下一个条目上。由于读者是严格的追随者,他们可以利用 LAC 从任何副本中读取持久数据,而无需与作者进行任何沟通或协调。
DL 引入了一种系统记录,称为控制记录——它作为两阶段提交算法中的提交请求。如果在指定的 SLA 内没有应用程序记录到达,编写器将生成控制记录。随着控制记录的写入,它将推进日志流的LAC。在收到写入用户记录的确认后立即添加控制记录,如果没有添加应用程序记录,则定期添加控制记录。它被配置为写入器刷新策略的一部分。虽然控制日志记录存在于物理日志流中,但它们不会由日志读取器传递给应用程序。
现在考虑以下场景:
- Leader 向 Bookkeeper 发布消息
- 追随者获取消息,附加到日志并向领导者发送ACK
- 领导者从追随者那里得到确认,增加 LAC 并回复客户端消息已提交。
- 现在:领导者在它可以搭载 LAC 已增加的追随者之前失败。
- 问题是:由于潜在的领导者不知道 LAC 已增加的事实,它成为新的领导者并将日志截断为旧的 LAC,这意味着我们丢失了日志中已由前任领导者确认的条目。
结果客户端已经确认消息已经写入成功,但是已经丢失了。