

Snapshot(快照)触发时机的优化
值得一提的是快照(Snapshotting)触发时机的优化,频繁的快照一方面会带来频繁的磁盘I/O,并且快照时实际上需要对存储加互斥锁,不仅影响可靠性,也影响性能。本节分析了V1-V3中快照触发机制和优化。
Fig 4.3.1 V0.4.9中持久化快照时机

V1中快照的触发是根据Commit Index来计算绝对偏移量的,这就导致会出现大量不必要的Snapshot,一方面系统性能、稳定性会受到影响,另一方面频繁的I/O也对文件系统的可靠性形成很强的依赖,最终影响整个集群的稳定性。
Fig 4.3.2 V2/V3中触发快照时机

V3中触发快照的时机和V2相同,都是在Apply阶段(执行已经Commit的Log的时候)。看似V2/V3的实现是一样的,没有变化?
其实在设置相同的—snapshot-count时,V3做了一个优化,可以很大程度上减少不必要的Snapshot开销。尽管V2/V3中触发Snapshot的时机都在执行(Apply)一条指令的时间,SYNC指令会触发频繁的Snapshot。
Fig 4.3.3 V2中SYNC指令的触发时机

500ms一次的SYNC操作是频繁Snapshot的罪魁祸首之一,这里的SYNC指令是用来干什么的呢?这个SYNC就是用来清除过期的TTL key的。精度写死了500ms,这就不难理解为什么ETCD里面TTL精度是1s了。V3里对这个地方做了一个判断,只在V2存储中有TTL key的时候才发起SYNC指令。
Fig 4.3.4 V3中的SYNC指令的触发时机

此处的优化可以减少没有TTL key时的Snapshot操作,也可以降低频繁SYNC指令造成的V2存储的全局互斥锁,性能更稳定;当然,如果V3中始终存在TTL key,这个优化就不起作用了。
需要强调的是,以上提到的TTL key是V1中引入的特性。在V3的存储中,TTL key从属于Lease,由Leader来统一管理,就不需要每个节点频繁、定时(500ms)清理过期的Key了。