ZooKeeper
适合读多写少的场景,读操作几乎是内存级别的,这得益于ZooKeeper
将数据保存在内存中。数据在内存中,就有一个问题,ZooKeeper
重启了数据还会在吗?
当然在了,ZooKeeper
将数据以事务日志形式持久化到文件中。每个更新请求,必须先将事务日志写到文件中,然后才把数据同步到内存数据库。
1、事务日志存放目录
事务日志文件默认存储在dataDir
目录下,因为每次事务请求都是一次磁盘IO操作,事务日志的写入性能直接影响了ZooKeeper
对事务请求的吞吐,为了更高的吞吐和低延迟,建议单独为事务日志配置一个目录dataLogDir
,以免受其他操作影响。
dataLogDir
下会先生成一个子目录version2
,2表示ZooKeeper
日志格式的版本号,同一版本的日志可以互相迁移恢复数据。version2
下才是事务日志文件。
2、文件大小和后缀名
事务日志的文件有两个特点:
-
文件大小出奇一致:都是
67108880KB
,即64MB
。 -
文件名后缀是一串看似有些规律的数字,而且随着修改时间推移呈递增状态。
(1)磁盘空间预分配
文件大小都是64MB
,是因为日志文件的磁盘空间预分配。
事务日志不断追加写入文件的操作会触发底层磁盘IO为文件开辟新的磁盘块,即磁盘Seek,为了避免频繁的文件大小增长带来的磁盘Seek开销,ZooKeeper
在创建事务日志文件时就向操作系统预分配了一块比较大的磁盘块,保证了单一事务日志文件所占用的磁盘块是连续的,以此提升事务的写入性能。默认是64MB
,空闲部分用空字符(\0
)填充。
如果后续检测到文件空间不足4KB
,将扩容再次预分配64MB
,直到创建新的事务日志文件。
(2)ZXID作为后缀名
文件名后面的一串数字是事务ID:ZXID
,并且是写入事务日志文件的第一条事务ZXID
。前面讲了,ZXID
高32位是当前Leader
任期编号,低32位是事务计数器,比如 log.1400000001
、log.1400000003
,都是Leader
任期编号为20时产生的事务日志文件。
3、事务日志可视化
事务日志文件中存放的是二进制格式的数据,不能用vim、cat等工具直接打开,需要用apache-zookeeper-3.7.0
提供的脚本bin/zkTxnLogToolkit.sh
打开:
bin/zkTxnLogToolkit.sh logs/zoo-1/version-2/log.1400000003
一行就是一个事务记录,每行从左到右依次是操作时间、客户端session
ID、CXID
(客户端操作序列号)、ZXID
、操作类型(做了什么),如果操作类型是 createSession
,后面的30000就是session
的超时时间。
4、相关配置项
跟事务日志有关的配置除了dataLogDir
外,还有 preAllocSize
。
(1)dataLogDir
zoo.cfg
中默认没有显式配置dataLogDir
,事务日志和快照日志共享dataDir
。但是强烈建议,单独为事务日志指定dataLogDir
。
事务日志记录对磁盘性能要求极高,为了保证数据一致性,ZooKeeper
在返回客户端请求响应前,必须将本次请求对应的事务日志写入到磁盘中。因此,事务日志写入性能直接决定了ZooKeeper
在处理事务请求时的吞吐。
针对同一块磁盘的其他并发读写操作(如ZooKeeper
运行时日志输出和操作系统自身的读写等),尤其是数据快照操作,会极大影响事务日志的写性能。因此尽量给事务日志的输出配置一个单独的磁盘或是挂载点,极大提高ZooKeeper
整体性能。
(2)preAllocSize
java 系统属性: ZooKeeper.preAllocSize
,从字面意思就可以看出,preAllocSize
是用来配置事务日志文件预先分配文件大小的参数。默认65536
,单位KB
,即64MB
。
5、什么时候创建新日志文件
在进行事务日志写入前,ZooKeeper
会判断是否正在关联一个可写的事务日志文件,如果有则继续追加到该文件中,如果没有就需要创建新的日志文件并关联上。
什么时候ZooKeeper
没有关联上一个可写的事务日志文件呢?有两种情况:
-
ZooKeeper
停止会导致之前关联的事务日志文件断开,重启后第一次事务日志写入,需要创建新的日志文件。 -
上一个事务日志文件写满了(达到阈值,触发了快照之后),需要创建新的日志文件。
需要注意ZooKeeper
服务不要频繁重启,否则会产生很多日志文件,并且有些文件还没有写满,非常浪费磁盘空间。
快照日志是将ZooKeeper
服务器上某个时刻的全量内存数据,写入到指定磁盘文件中。可以这样理解,快照日志文件是存量数据,事务日志文件是增量数据,二者加起来就是最大限度的全量数据。
1、文件存储
和事务日志类似,快照日志存放在dataDir
子目录version2
中,文件名为snapshot.ZXID
,不需要像事务日志文件一样预分配空间。
需要强调快照文件名后缀 ZXID
是触发快照的瞬间,提交的最后一个事务ID。如果是事务ZXID5
触发快照,那么快照文件名就是snapshot.ZXID5
,快照之后的下一个事务的ID是ZXID6