zookeeper日志有三类:快照(虽然不是日志但是它是数据)、事务日志(记录每次操作)、zookeeper自己系统日志。第三个不属于数据类所以这里不做说明。
快照数据
Zookeeper在运行时会在内存中维护一个完整的数据,就像内存数据库一样。ZKDatabase就是Zookeeper的内存数据库,负载管理Zookeeper的会话、存储和事务日志。它会定期dump一份数据快照到硬盘上,在Zookeeper启动时根据这个快照数据和事务日志来加载一份完整的数据到内存。这一点跟Redis很像,其实很多时候思路都是一样。
通过在配置文件中设置dataDir来指定快照保存位置。将内存数据库写入快照文件其实是一个序列化的过程。快照文件保存只是每个节点的元数据而非数据本身。
那么每次快照间隔多久呢?
其实可以通过snapCount来进行配置,这个值得含义是每次快照之间的事务数量。也就是说执行多少次事务操作后进行一次快照。
- 每完成一次事务操作Zookeeper都会检查是否达到snapCount设置也就是来判断是否需要进行快照操作,因为快照本身对机器性能有影响,要避免集群中所有节点都进行快照
- 如果要进行快照操作,首先就需要对事务日志进行截断然后切换,所以事务日志写满不是以64M为标准而是以事务条数为标准的。
- 创建异步线程来执行快照操作(这一点又和Redis的bgsave一样)
- 从ZKDatabase中获取全量数据和会话,因为要保存内存所有数据节点信息和会话信息
- 生成快照名称,会根据已提交的最大ZXID来生成快照名称
- 数据序列化,首先会序列化文件头信息(魔数、版本、dbid信息),然后对会话信息和DataTree(Zookeeper内存数据的核心一个树形数据结构,代表内存完整数据)分别序列化,同时生成一个校验和,然后一起写入数据文件中。
事务日志
在配置文件中通过dataLogDir来配置事务日志路径,如果不配置默认保存在dataDir指定的路径下面。
这些文件都是65M,其实是64M。而且都是以log.开头后面是一个十六进制数字作为后缀。这个后缀是一个ZXID它是写入该日志的第一个事务的事务ID,这样可以达到快速定位某一事务的效果。
日志写入过程:
- 当需要写入事务日志的时候Zookeeper会判断它是否和一个可写入的事务日志相关联,如果关联就写入,如果没有则用该事务的事务ID来创建一个事务日志,同时将这个事务日志对应的文件流放入到一个集合中(streamsToFlush),这个集合中记录的是当前需要强刷数据到磁盘的文件流(因为操作系统通常有延迟写入机制,对于Linux系统强刷等于调用fsync)。
- 事务日志文件采用预先分配空间策略,这样为了保证单一事务日志文件所占用的磁盘块是连续的,这也是为了提高性能。当Zookeeper发现当前正在写入的事务日志文件空间不足4KB时,就会启动预先分配空间策略进行扩容。第一次使用事务日志或者事务日志达到切割条数(snapCount参数触发快照)会启动预先分配策略;其他时候只要发现当前使用的事务日志空余不足4KB就进行扩容,扩容时使用0进行填充。
- 确保日志文件空间够之后就需要对进行事务序列化操作,最终产生一个字节数组。主要对事务头(TxnHeader)和事务体(Record)进行序列化。
- 根据序列化后的字节数据计算一个校验和
- 将字节数组和校验写入到文件流中。
- 由于该事务日志的文件流在集合中,这时候就会从集合里面取出文件流强刷落盘。
原文地址:http://blog.51cto.com/littledevil/2134476
时间: 2024-10-30 00:59:00