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代表了当前已经记录的事务日志数量,randRoll1 ~ snapCount/2之间的随机数,因此上面的条件就相当于:如果我们配置的snapCount100000,那么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事务日志记录器SyncRequestProcessor的更多相关文章

  1. zookeeper 事务日志

    前面提到,在zookeeper server的配置文件zoo.cfg中可以通过dataLogDir来配置zookeeper的事务日志的输出目录,这个事务日志类似于下面这样的文件: 这个文件是一个二进制 ...

  2. zookeeper 事务日志与快照日志

    zookeeper日志各类日志简介 zookeeper服务器会产生三类日志:事务日志.快照日志和log4j日志. 在zookeeper默认配置文件zoo.cfg(可以修改文件名)中有一个配置项data ...

  3. zookeeper 事务日志查看

    在version下的日志是二进制文件,查看需要转换 创建/data/middleware/zookeeper-3.4.14/translog.sh 脚本 格式化命令: java -classpath ...

  4. Zookeeper日志文件&事务日志&数据快照

    Zookeeper持久化两类数据,Transaction以及Snapshot,logDir存储transaction命令,dataDir存储snap快照,其下子目录名称以version-2命名,子目录 ...

  5. zookeeper读取事务日志、快照日志

    zookeeper的事务日志的格式如 log.xxx, xxx表示顺序序号 我使用的zookeeper版本:3.5.5 事务日志 执行命令 java -cp .:/tmp/zookeeper-3.5. ...

  6. ZooKeeper系列(5):ZooKeeper的日志和快照

    ZooKeeper系列文章:https://www.cnblogs.com/f-ck-need-u/p/7576137.html#zk ZooKeeper有两种日志.一种快照.日志分为事务日志和Zoo ...

  7. SharePoint 2010 数据库xxx的事务日志已满

    接到领导安排,说客户有问题 请求协助解决,对方给我展示的错误日志,如下: 数据库'WSS_Content_xxxx'的事务日志已满.若要查明无法重用日志中的空间的原因,请参阅sy.databases中 ...

  8. SQL Server 事务以及事务日志综述

    事务是一个非常重要的概念,特此在这里写一些文章来总结.整篇文章还在持续更新中. 在本系列文章中,你将看到以下内容: 数据库事务(Database Transaction)概述 事务操作(BEGIN/C ...

  9. SQL Server 事务日志传输

    概述 可以使用日志传送将事务日志不间断地从一个数据库(主数据库)发送到另一个数据库(辅助数据库).不间断地备份主数据库中的事务日志,然后将它们复制并还原到辅助数据库,这将使辅助数据库与主数据库基本保持 ...

随机推荐

  1. ios 判断相册文件图片大小的方法

    ALAssetsLibrary* alLibrary = [[ALAssetsLibrary alloc] init]; [alLibrary assetForURL:[info objectForK ...

  2. IIS7.5 webapi 不支持 Delete、Put 解决方法

    在IIS管理界面选择API的项目,选择 “Features View”. 2.  选择 “Handler Mappings” 菜单. 3. 打开“WebDAV” 选项. 4. 点击 “Request ...

  3. CSS实现DIV超长截断,并显示...

    DIV显示内容有时会超长,并把页面撑的很难看, 以前的做法是在JS中,或者后台判断其长度,过长就截断, 但由于中英文数字展示的宽度并不一样,截断的长度也就只能取最小值, 展示的效果也不好.利用CSS提 ...

  4. Quartus II中的Waring(转)

    1.Found clock-sensitive change during active clock edge at time <time> on register "<n ...

  5. CALayer

    刚刚无聊,画了一个月亮. - (void)viewDidLoad { [super viewDidLoad]; self.view.layer.backgroundColor = [UIColor b ...

  6. Acadia Lab 203 + Lab 231

    在做完 Lab 6 之后,惊觉选做实验缺口很大,于是遍历了一遍夏任务,找到了一条最省力的路线. 做完 Lab 6 的连线不用拆,可以接下来做以下两个实验: Lab 203 网络时钟 核心代码如下: v ...

  7. ASP.NET MVC 介绍

    ASP.NET分为WebForm(数据访问层 界面层 业务逻辑层)和MVC MVC : Model(模型)是应用程序中用于处理应用程序数据逻辑的部分. 通常模型对象负责在数据库中存取数据. View( ...

  8. 收藏网址 ios开源库

    http://www.csdn.net/article/2015-07-21/2825264-27-ios-open-source-libraries/1

  9. 各种Java序列化性能比较

    转载:http://www.jdon.com/concurrent/serialization.html 这里比较Java对象序列化 XML JSON  Kryo  POF等序列化性能比较. 很多人以 ...

  10. 笔记002:javascript简介

    1. HTML服务于内容 CSS服务于表现 Javascript服务于行为(一切东西的粘合剂) 2.javascript能运行多种宿主环境中(Web浏览器最普遍) 3.历史 1995 Netscape ...