分布式开发模式中,我们经常会讲到预写式日志(Write-ahead logging,缩写 WAL),其主要方式是将所有修改在提交之前都先写入log日志中。
举个例子说明:当我们的设备接收到请求进行操作时,突然断电了。在重启恢复时,我们需要确认操作是成功了,还是部分成功,甚至失败了。我们可以通过检测log,判断计划执行操作的内容与实际上执行操作的内容进行比较,通过比较程序来觉得是否应用,还是回滚等补救措施。
WAL 是关系数据库系统中用于提供原子性和持久性(ACID属性中的两个)的一系列技术,比如PostgreSQL也是用WAL来提供point-in-time恢复和数据库复制特性。
martin fowler 说过:
Provide durability guarantee without the storage data structures to be flushed to disk, by persisting every state change as a command to the append only log.
相比于持久化数据结构到磁盘,我们可以通过将每个状态的改变作为指令追加到日志中来提供持久性的保证。
WAL的解决方案:
每台服务器独立维护单个日志,将使状态更改的操作指令顺序地存储在硬盘上的文件中。按顺序追加的单个日志可以简化重启时的日志处理和后续在线操作(当日志被追加新的命令时)。每个日志条目都有一个唯一的标识符。唯一的日志标识符有助于在日志上执行某些其他操作,如分段日志或清除带有低水位标记的日志等。日志更新可以通过更新队列实现。
关于segment log 段日志、低水位日志check point low-water mark、以及更新日志会在后续文章内容讲到。
定义我们的日志类:
class WALEntry…
private final Long entryId;
private final byte[] data;
private final EntryType entryType;
private long timeStamp;
ky存储结构:
class KVStore…
private Map<String, String> kv = new HashMap<>();
public String get(String key)