分布式系统模式简述-Low-Water Mark

java达人
关注

作者: Unmesh Joshi

译者: java达人

预写日志中的索引,表示可以丢弃日志的哪一部分。

问题

预写日志维护对持久性存储的每一次更新。随着时间的进展,它会无限制地增长。Segmented Log允许一次处理较小的文件,但是如果不检查,总磁盘存储量将无限制增长。

解决方案

有一种机制可以告诉日志记录机器可以安全地丢弃日志的哪一部分。该机制提供了最低的偏移量或low water mark,在此之前的日志可以丢弃。让任务在后台的单独线程中运行,该任务连续检查可以丢弃日志的哪一部分并删除磁盘上的文件。

this.logCleaner = newLogCleaner(config);this.logCleaner.startup();

日志清理器可以实现为定时任务

public void startup() {    scheduleLogCleaning();}

private void scheduleLogCleaning() {    singleThreadedExecutor.schedule(() -> {        cleanLogs();    }, config.getCleanTaskIntervalMs(), TimeUnit.MILLISECONDS);}基于快照的Low-Water Mark

大多数共识实现(例如Zookeeper或etcd(在RAFT中定义))都实现了快照机制。在此实现,存储引擎需要定期快照。除快照外,它还存储成功应用的日志索引。参考“Write-Ahead Log”模式中的简单键值存储实现,可以采取以下快照:

public SnapShot takeSnapshot() {    Long snapShotTakenAtLogIndex = wal.getLastLogEntryId();    return new SnapShot(serializeState(kv), snapShotTakenAtLogIndex);}

一旦快照成功保存在磁盘上,日志管理器将获得Low-Water Mark,以丢弃较旧的日志。

List<WALSegment> getSegmentsBefore(Long snapshotIndex) {    List<WALSegment> markedForDeletion = new ArrayList<>();    List<WALSegment> sortedSavedSegments = wal.sortedSavedSegments;    for (WALSegment sortedSavedSegment : sortedSavedSegments) {        if (sortedSavedSegment.getLastLogEntryId() < snapshotIndex) {            markedForDeletion.add(sortedSavedSegment);        }    }    return markedForDeletion;}基于时间的Low-Water Mark

在某些系统中,不一定要使用日志来更新系统状态,可以在给定的时间窗口后丢弃日志,而不必等待任何其他子系统共享可以删除的最低日志索引。例如,在像Kafka这样的系统中,日志将保留7周;消息时间超过7周的所有日志段都将被丢弃。对于此实现,每个日志条目还包括创建时的时间戳。然后,日志清理器可以检查每个日志段的最后一个条目,并丢弃早于配置的时间窗口的日志段。

private List<WALSegment> getSegmentsPast(Long logMaxDurationMs) {    long now = System.currentTimeMillis();    List<WALSegment> markedForDeletion = new ArrayList<>();    List<WALSegment> sortedSavedSegments = wal.sortedSavedSegments;    for (WALSegment sortedSavedSegment : sortedSavedSegments) {        if (timeElaspedSince(now, sortedSavedSegment.getLastLogEntryTimestamp()) > logMaxDurationMs) {            markedForDeletion.add(sortedSavedSegment);        }    }    return markedForDeletion;}
private long timeElaspedSince(long now, long lastLogEntryTimestamp) {    return now - lastLogEntryTimestamp;}

例子

?所有共识算法(例如Zookeeper和RAFT)中的日志实现均实现基于快照的日志清理

?Kafka中的存储实现遵循基于时间的日志清理


声明: 本文由入驻OFweek维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。
侵权投诉

下载OFweek,一手掌握高科技全行业资讯

还不是OFweek会员,马上注册
打开app,查看更多精彩资讯 >
  • 长按识别二维码
  • 进入OFweek阅读全文
长按图片进行保存