ETCD数据存储情况( 三 )


2.6 数据存储
etcd的存储分为内存存储和持久化(硬盘)存储两部分,内存中的存储除了顺序化地记录下所有用户对节点数据变更的记录外,还会对用户数据进行索引、建堆等方便查询的操作 。而持久化则使用预写式日志(WAL:Write Ahead Log)进行记录存储 。
在WAL的体系中,所有的数据在提交之前都会进行日志记录 。在etcd的持久化存储目录中,有两个子目录 。一个是WAL,存储着所有事务的变化记录;另一个则是,用于存储某一个时刻etcd所有目录的数据 。通过WAL和相结合的方式,etcd可以有效地进行数据存储和节点故障恢复等操作 。
也许你会有这样的疑问,既然已经在WAL实时存储了所有的变更,为什么还需要呢?原因是这样的,随着使用量的增加,WAL存储的数据会急剧增加,为了防止磁盘空间不足,etcd默认每10000条记录做一次,经过以后的WAL文件就可以删除 。通过API可以查询的历史etcd操作默认为1000条 。
首次启动时,etcd会把启动的配置信息存储到data-dir参数指定的数据目录中 。配置信息包括本地节点ID、集群ID和初始时集群信息 。用户需要避免etcd从一个过期的数据目录中重新启动,因为使用过期的数据目录启动的节点会与集群中的其他节点产生不一致(如:之前已经记录并同意节点存储某个信息,重启后又向节点申请这个信息) 。所以,为了最大化集群的安全性,一旦有任何数据损坏或丢失的可能性,你就应该把这个节点从集群中移除,然后加入一个不带数据目录的新节点 。
(1)预写式日志(WAL)
WAL最大的作用是记录了整个数据变化的全部历程 。在etcd中,所有数据的修改在提交前,都要先写入到WAL中 。使用WAL进行数据的存储使得etcd拥有两个重要功能 。
WAL与在etcd中的命名规则
在etcd的数据目录中,WAL文件以$seq-$index.wal的格式存储 。最初始的WAL文件是.wal,表示是所有WAL文件中的第0个,初始的Raft状态编号为0 。运行一段时间后可能需要进行日志切分,把新的条目放到一个新的WAL文件中 。
假设,当集群运行到Raft状态为20,需要进行WAL文件的切分时,则下一份WAL文件就会变为.wal 。如果在10次操作后又进行了一次日志切分,那么后一次的WAL文件名会变为.wal 。可以看到-符号前面的数字是每次切分后自增1,而-符号后面的数字则是根据实际存储的Raft起始状态来定 。
的存储命名则比较容易理解,以$term-$index.wal格式进行命名存储 。term和index就表示存储时数据所在的Raft节点状态,当前的任期编号以及数据项位置信息 。
(2) 关键部分源码解析
从代码逻辑中可以看到,WAL有两种模式,读(read)模式和数据添加()模式,两者是互斥的 。一个新创建的WAL文件处于模式,并且不会进入到read模式 。一个本来存在的WAL文件被打开的时候必然是read模式,只有在所有记录都被读完的时候,才能进入模式,进入模式后也不会再进入read模式 。这样做有助于保证数据的完整与准确 。
集群在进入到/.go的函数准备启动一个etcd节点时,会检测是否存在以前的遗留WAL数据 。
etcd从v0.4.6升级到v2.0.0,它数据格式存储的格式也变化了 。检测的第一步是查看文件夹下是否有符合规范的文件,若检测到格式是v0.4的,则调用函数升级到v0.5 。从中获得集群的配置信息,包括token、其他节点的信息等等,然后载入WAL目录的内容,从小到大进行排序 。根据中得到的term和index,找到WAL紧接着下一条的记录,然后向后更新,直到所有WAL包的entry都已经遍历完毕,Entry记录到ents变量中存储在内存里 。此时WAL就进入模式,为数据项添加进行准备 。