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 事务日志传输
概述 可以使用日志传送将事务日志不间断地从一个数据库(主数据库)发送到另一个数据库(辅助数据库).不间断地备份主数据库中的事务日志,然后将它们复制并还原到辅助数据库,这将使辅助数据库与主数据库基本保持 ...
随机推荐
- XML文件中CDATA的作用
操作XML文件时,如果允许用户输入内容,例如∶"< ".">"."/".""等,当生成XML时,会破坏了XM ...
- 表示即将废弃一个方法,或不赞成使用的一个方法或属性或其它,关键词 deprecated
- web_submit_data函数上传图片
web_submit_data函数上传图片 通常loadrunner上传下载文件脚本不能通过录制来实现,录制上传脚本回放过程会出问题,主要原因在于上传文件的路径,了解了上传文件的原理之后,可以手工完成 ...
- Spring+Mybatis多数据源配置
一.配置文件 properties ds1.driverClassName=com.mysql.jdbc.Driver ds1.url=jdbc:mysql://192.168.200.130:330 ...
- mobx源码解读3
计算属性 function Todo() { this.id = Math.random() mobx.extendObservable(this, { aaa: 222, bbb: 11, ccc: ...
- touches, targetTouches, changedTouches 区别
1. touches: A list of information for every finger currently touching the screen2. targetTouches: Li ...
- EntityFramework Reverse POCO Generator工具
https://visualstudiogallery.msdn.microsoft.com/ee4fcff9-0c4c-4179-afd9-7a2fb90f5838
- typeahead.js 使用记录
github地址:https://github.com/twitter/typeahead.js 在aceAdmin界面模板中,有typeahead这一控件,版本号为0.10.2 , 这个版本对 mi ...
- SECD machine简介
secd machine是一种比较基础的虚拟机设计.一般是作为函数式语言的底层虚拟机. secd machine的"secd"四个字母分别指的是这种虚拟机的核心Stack, Env ...
- iOS中线程同步基本详解
为什么使用线程同步技术:多个线程是同时执行的 如果多个线程同时操作一个资源 会造成此资源的数据错乱 线程同步简介 线程同步,多条线程按顺序地访问某个资源 注意:此处的同步不是一起执行的意思 是一个一个 ...