【源码】【事务日志和快照】

  • 概念:事务日志和快照
    事务日志:客户端对服务器的每一次request请求都算一次会话,把请求内容记录记录下来,叫做事务日志,文件命令以log前缀开头;
    快照:zookeeper启动之后,会把硬盘的数据初始化到内存里面,并以KEY-VALU形式放在DataTree类数据结构中,即内存里面;然后zookeeper在满足一定条件之后把内存数据持久化到磁盘上面,持久化之后的文件叫做快照,文件命名以snapshot.前缀开头;

  • 操作业务代码逻辑
    在SyncRequestProcessor类run方法里面;

  • 两种日志何时被初始化到磁盘?

  1. 这里是列表文本.事务日志:一个事务请求过来之后,会最终到FileTxnlog的append函数,需要注意的是此时只会吧request数据放到BufferedOutputStream流缓存里面,并不执行该流的flush()函数,当然,也不会在磁盘持久化,然后SyncRequestProcessor的run()函数题里面会对每一个apend成功的函数,然后把该request对象存放到toFlush集合里面;如果此时toFlush集合长度大于1000,则会执行toflush函数,即磁盘化;如果此时只是第一个请求过来了,即长度加入之后为1,则继续在run的函数体内while循环,执行到si = queuedRequests.poll();函数,此时分两种情况,如果再此过程中没有任何请求过来(注意包含客户端定期的ping请求),则si为null,此时也会执行flush函数,然后磁盘持久化,反之,如果此时恰好一个请求过来,则会继续执行后面的逻辑,而不会电泳flush,假如此时系统突然断电,则上一个未被flush的request请求就会丢失数据了(虽然此种概率很小);总的来说:该逻辑只在系统空闲时候来执行flush,除非flush容量超过1000才会flush一次,所以系统空闲是指queuedRequests的消费能力大于生产能力,即存在没有消息消费的时候,才会被flush,这样设计也是避免频繁磁盘IO请求造成IO负载增加,另外优先处理业务请求;
  2. 快照日志:快照日志是在每次rollog之后,会生成快照,所谓rolllog是日志达到一定大小了,然后按照规则生产一个新的文件,继续存放事务日志。rolllog的时间点是有一定规则的,即logCount > (snapCount / 2 + randRoll),logcount是指每一次事务请求之后logcount都会加1,snapCount直必须大于等于2, 如果不设定默认值是100000,可以在zoo.cfg指定snapCount的值。ranRoll为小于snapCount/2大于0的随机数,当满足以上条件时候,会开启snapInProcess线程来执行takeSnapshot方法,最终调用snapCount函数。当然,在生成此线程时候,发现如果上次开启的snapInProcess线程还未执行完毕,则抛出“Too busy to snap, skipping”异常。
  3. 所以,如果想恢复zookeeper数据,事务文件和快照文件都需要的。因为,在快照文件生成之后,有可能有新的事物文件生成,但是此时并没有生成新的快照文件;
  • 频繁的写事务日志,如何提高磁盘文件日志写入的高效性?
  1. 缓存技术:事务日志的写入zookeeper用的而是BufferedOutputStream内存缓存,只有在显示调用flush函数的时候,才会刷新到磁盘即group commit();
  2. 预分配技术:首先明白文件大小和文件占用空间是不同的概念。Windows默认创建一个文件默认文件空间为一扇区即4KB。因为window文件系统是按照簇为基本的单位来分配空间,一个簇一般为8个扇区,一个扇区为512B,随后再写入更多的文件,就需要开闭新的簇空间,虽然文件系统是采用链表形式来存放文件,允许文件在不同的簇上面,试想,如果第一个簇在第一个磁道,第二个簇在最里面磁道,这样读写一个文件自然就增加了磁盘的寻道时间,这才是最关键的。另外准确来说文件读写这会带来至少两次额外的磁盘寻道:一次是为了更新元数据,另一次是文件的末尾。 如果能让所有的簇都按照连续的簇分配,自然就会减少磁盘寻到时间,也就增加了文件读写的速度。为了提高文件读写,可以在创建文件时候,指定更大文件的文件空间文件。具体实现方式是通过FileChannel对象,可以通过FileOutputStream的.getChannel()获取。然后调用channel的write(bybuffer,possion)函数,目前zookeeper指定possion为96MB,即65536 * 1024。bybuffer为长度为1内容为空的字节缓冲器。FileChannel.position可以获取文件大小的位置。所以,虽然文件占用空间变大了,但是文件的大小是不变的,即position的值是不变的。这样就提高了文件的读写速度。
  • 文件格式:都是以二进制形式存储
  1. 事务日志:新创建文件会首先写入FileHeader数据,其中magic为ZKLG,version为2;
  2. 快照文件:新创建也会写入fileHeader。其中magic为ZKSN,version也为2;
  • 客户端服务器数据传输
  1. 都是以二进制形式通过NIO的socket传输。所有的请求都包含RequestHeader和requestData两部分。第一部分是表示什么样的操作,如增加、修改等等,第二部分是表示具体的数据内容;
  2. 这些数据会在客户端封装成Packet对象,然后放入outgoingQueue队列里面(参考ClientCnxn类),消费线程消费到之后最终调用到ClientCnxnSocketNIO里面,然后调用p,createBB()最终拿到ByteBuffer,最终通过socket传入服务器;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值