ZooKeeper事务日志记录器SyncRequestProcessor
SyncRequestProcessor作为一个ZooKeeper中的一个关键线程(ZooKeeperCriticalThread),是ZooKeeper请求处理链中的事务日志记录处理器,其主要用来将事务请求记录到事务日志文件中去,同时还会触发ZooKeeper进行数据快照。
数据结构
LinkedBlockingQueue<Request> queuedRequests:上一个RequestProcessor调用nextProcessor.processRequest(request)将request排入该队列中等待处理。Thread snapInProcess:负责快照线程,保证数据快照过程不影响ZooKeeper的主流程,需创建一个单独的异步线程来进行数据快照。LinkedList<Request> toFlush:在持久化过程中,使用组提交(Group Commits)来优化磁盘I/O操作。想象一个场景:当客户端有大量的事务请求,如果每次写请求都同步到磁盘,那么性能就会产生问题。所以设置该链表来暂存需要持久化到磁盘的Request。int snapCount:默认为100000,表示ZooKeeper每隔snapCount次事务日志记录后进行一个数据快照。
toFlush以及flush时机
toFlush队列可用于存储请求,可能是读也可能是写。
ZooKeeper专门使用线程SyncRequestProcessor来处理请求,所以这个线程必须合理的工作,否则会对整体的性能造成影响。如果客户端请求为读请求就没必要进行flush了,但如果是写请求,就必须把请求写入log,这个写入未必能保证真的同步到磁盘。所以合适的时机将缓存的事务日志刷入到磁盘是必须的。
从程序的设计应该能看到作者出于这个考虑选择了两个时机来做这件事情:
- 如果没有请求的时候(即较空闲的时候)
- 如果一直繁忙,则toFlush队列到达了一定数量(1000),就会批量同步
注意点
数据快照
每进行一次事务日志记录之后,ZooKeeper都会检测当前是否需要进行数据快照。理论上进行
snapCount次事务操作后就会开始数据快照,但是考虑到数据快照对于ZooKeeper所在机器的整体性能影响,需要尽量避免ZooKeeper集群中所有机器在同一时刻进行数据快照。因此ZooKeeper在具体的实现中,并不是严格按照这个策略执行,而是采取“过半随机”策略,即符合如下条件就进行数据快照:logCount > (snapCount / 2 + randRoll)
其中
logCount代表了当前已经记录的事务日志数量,randRoll为1 ~ snapCount/2之间的随机数,因此上面的条件就相当于:如果我们配置的snapCount为100000,那么ZooKeeper会在50000 ~ 100000次事务日志记录后进行一次数据快照。事务日志文件切换
当满足上述条件时,ZooKeeper就要开始进行数据快照了。首先是进行事务日志文件的切换。所谓的事务日志文件切换时指当前的事务日志已经“写满”,需要重新创建一个新的事务日志。即每当进行一次数据快照,重新创建一个事务日志文件。
源码
int logCount = 0;
int randRoll = r.nextInt(snapCount/2); // 产生0~snapCount/2之间的随机数
while (true) {
Request si = null;
if (toFlush.isEmpty()) {
si = queuedRequests.take(); // toFlush为空,不需要flush,没有数据则直接阻塞掉
} else {
si = queuedRequests.poll(); // 没有数据直接返回,有则拿出
if (si == null) { // 如果queuedRequests中没有数据,但toFlush不空,则表明ZooKeeper现在比较空闲,可以进行flush
flush(toFlush);
continue;
}
}
if (si == requestOfDeath) {
break;
}
if (si != null) {
if (zks.getZKDatabase().append(si)) { // 如果si是事务请求
logCount++;
if (logCount > (snapCount / 2 + randRoll)) { // 满足条件,需要进行数据快照
randRoll = r.nextInt(snapCount/2);
zks.getZKDatabase().rollLog(); // 切换事务日志文件
if (snapInProcess != null && snapInProcess.isAlive()) {
LOG.warn("Too busy to snap, skipping");
} else {
snapInProcess = new ZooKeeperThread("Snapshot Thread") { // 创建数据快照异步线程
public void run() {
try {
zks.takeSnapshot();
} catch(Exception e) {
LOG.warn("Unexpected exception", e);
}
}
};
snapInProcess.start(); // 保证数据快照过程不影响ZooKeeper的主流程,创建一个单独的异步线程来进行数据快照
}
logCount = 0;
}
} else if (toFlush.isEmpty()) { // 如果是非事务请求(读操作)且toFlush为空
// 说明近一段时间读多写少,直接响应,此处优化为了读比较频繁操作
// 为何读写不分开???
if (nextProcessor != null) {
nextProcessor.processRequest(si);
if (nextProcessor instanceof Flushable) {
((Flushable)nextProcessor).flush();
}
}
continue; // nextProcessor已经对该si处理过了,不用添加到toFlush中
}
toFlush.add(si);
if (toFlush.size() > 1000) { // 超过1000,直接flush
flush(toFlush);
}
}
}
参考
- zookeeper储存之实现分析
- 从Paxos到ZooKeeper分布式一致性原理与实践书籍
ZooKeeper事务日志记录器SyncRequestProcessor的更多相关文章
- zookeeper 事务日志
前面提到,在zookeeper server的配置文件zoo.cfg中可以通过dataLogDir来配置zookeeper的事务日志的输出目录,这个事务日志类似于下面这样的文件: 这个文件是一个二进制 ...
- zookeeper 事务日志与快照日志
zookeeper日志各类日志简介 zookeeper服务器会产生三类日志:事务日志.快照日志和log4j日志. 在zookeeper默认配置文件zoo.cfg(可以修改文件名)中有一个配置项data ...
- zookeeper 事务日志查看
在version下的日志是二进制文件,查看需要转换 创建/data/middleware/zookeeper-3.4.14/translog.sh 脚本 格式化命令: java -classpath ...
- Zookeeper日志文件&事务日志&数据快照
Zookeeper持久化两类数据,Transaction以及Snapshot,logDir存储transaction命令,dataDir存储snap快照,其下子目录名称以version-2命名,子目录 ...
- zookeeper读取事务日志、快照日志
zookeeper的事务日志的格式如 log.xxx, xxx表示顺序序号 我使用的zookeeper版本:3.5.5 事务日志 执行命令 java -cp .:/tmp/zookeeper-3.5. ...
- ZooKeeper系列(5):ZooKeeper的日志和快照
ZooKeeper系列文章:https://www.cnblogs.com/f-ck-need-u/p/7576137.html#zk ZooKeeper有两种日志.一种快照.日志分为事务日志和Zoo ...
- SharePoint 2010 数据库xxx的事务日志已满
接到领导安排,说客户有问题 请求协助解决,对方给我展示的错误日志,如下: 数据库'WSS_Content_xxxx'的事务日志已满.若要查明无法重用日志中的空间的原因,请参阅sy.databases中 ...
- SQL Server 事务以及事务日志综述
事务是一个非常重要的概念,特此在这里写一些文章来总结.整篇文章还在持续更新中. 在本系列文章中,你将看到以下内容: 数据库事务(Database Transaction)概述 事务操作(BEGIN/C ...
- SQL Server 事务日志传输
概述 可以使用日志传送将事务日志不间断地从一个数据库(主数据库)发送到另一个数据库(辅助数据库).不间断地备份主数据库中的事务日志,然后将它们复制并还原到辅助数据库,这将使辅助数据库与主数据库基本保持 ...
随机推荐
- mysql快速导入大量数据问题
今天需要把将近存有一千万条记录的*.sql导入到mysql中.使用navicate导入,在导入100万条之后速度就明显变慢了, 导入五百万条数据的时候用了14个小时,且后面的数据导入的越来越慢. 后来 ...
- 关于spring AOP的学习
比较好的帖子http://www.cnblogs.com/xing901022/p/4265544.html
- 线程操作UI界面的方法
以前一般都是用BeginInvoke来刷新UI界面,现在采用 SynchronizationContext 来刷新,写起来清楚多了. SynchronizationContext synchroniz ...
- VR发展的最大障碍在于内容?
VR目前基本处于半死不活的状态,国内基本就是一堆的VR“盒子”在浑水摸鱼,就小米有点自知之明,冠以“玩具”的定位.但是说到VR发展的最大问题,居然说是什么内容没有吸引力,真让人无语啊.另外,还有什么价 ...
- vim的一些配置
所有用户的共同配置位于 /etc/vimrc 或者 /ect/vim/vimrcz中,可能还会有其他的配置文件,例如vimrc.tiny,具体的应用场景文件内会有说明. 某个特定用户的vim配置位于 ...
- VC++ 6.0远程调试配置
VC开发环境之所以提供远程调试的能力,是因为有些情况下单机调试会让你崩溃掉...比如,调试GUI程序的WM_PAINT消息,因为要单步调试,所以调试器会对界面的重绘产生副作用(Heisenberg不确 ...
- extjs ajax java简单精美验证码实现 有图
前端:利用ExtJs的autoEl功能加载图片. var imgCheckValid = new Ext.create('Ext.Component',{ width: 70, //图片宽度 heig ...
- 【网络编程/C++】修改本机ip地址
昨天学会了编程实现获取本地网卡信息,今天再接再砺学会了修改本机ip地址.其实原理很简单就是用c++调用一下dos命令而已,不得不说,dos命令实在是太强大了,当然听说还有种修改注册表的方法,不过没有试 ...
- -moz-transform: rotate(-5deg);
目前越来越多的浏览器兼容CSS3标准了,就连IE浏览器老大哥也开始向CSS3低头,微软宣布IE9浏览器支持更多的CSS3属性,IE9更注重 HTML5标准.不过CSS3里有一个使对象旋转的属性tran ...
- Java 对文件的读取操作
package pack; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; ...