zk 有 2 种文件,快照和事务日志,快照是某一时刻的全量数据,事务日志中记录了数据的修改事件。

快照的文件名是 snapshot.zxid,zxid 是当前最大的事务 id

// org.apache.zookeeper.server.persistence.FileTxnSnapLog#save
public void save(DataTree dataTree,
ConcurrentHashMap<Long, Integer> sessionsWithTimeouts)
throws IOException {
long lastZxid = dataTree.lastProcessedZxid;
// 快照文件名为 snapshot.lastZxid
File snapshotFile = new File(snapDir, Util.makeSnapshotName(lastZxid));
LOG.info("Snapshotting: 0x{} to {}", Long.toHexString(lastZxid),
snapshotFile);
snapLog.serialize(dataTree, sessionsWithTimeouts, snapshotFile); }

事务日志的文件名是 log.zxid,zxid 是当前文件第一条日志的事务 id

// org.apache.zookeeper.server.persistence.FileTxnLog#append
public synchronized boolean append(TxnHeader hdr, Record txn)
throws IOException
{
if (hdr == null) {
return false;
} if (hdr.getZxid() <= lastZxidSeen) {
LOG.warn("Current zxid " + hdr.getZxid()
+ " is <= " + lastZxidSeen + " for "
+ hdr.getType());
} else {
lastZxidSeen = hdr.getZxid();
} if (logStream==null) {
if(LOG.isInfoEnabled()){
LOG.info("Creating new log file: " + Util.makeLogName(hdr.getZxid()));
}
// 创建一个新的事务日志文件 log.zxid,这里的 zxid 是第一条事务日志的 zxid
logFileWrite = new File(logDir, Util.makeLogName(hdr.getZxid()));
fos = new FileOutputStream(logFileWrite);
logStream=new BufferedOutputStream(fos);
oa = BinaryOutputArchive.getArchive(logStream);
FileHeader fhdr = new FileHeader(TXNLOG_MAGIC,VERSION, dbId);
fhdr.serialize(oa, "fileheader");
// Make sure that the magic number is written before padding.
logStream.flush();
filePadding.setCurrentSize(fos.getChannel().position());
streamsToFlush.add(fos);
}
filePadding.padFile(fos.getChannel());
byte[] buf = Util.marshallTxnEntry(hdr, txn);
if (buf == null || buf.length == 0) {
throw new IOException("Faulty serialization for header " +
"and txn");
}
Checksum crc = makeChecksumAlgorithm();
crc.update(buf, 0, buf.length);
oa.writeLong(crc.getValue(), "txnEntryCRC");
Util.writeTxnBytes(oa, buf); return true;
}

zk 加载数据:从 snap 文件和 log 文件解析出全量数据

// org.apache.zookeeper.server.persistence.FileTxnSnapLog#restore
public long restore(DataTree dt, Map<Long, Integer> sessions,
PlayBackListener listener) throws IOException {
snapLog.deserialize(dt, sessions);
return fastForwardFromEdits(dt, sessions, listener);
}

逆序选择 100 个 snap 文件,从最新的文件开始解析,如果有一个文件校验正确,则退出

public long deserialize(DataTree dt, Map<Long, Integer> sessions)
throws IOException {
// we run through 100 snapshots (not all of them)
// if we cannot get it running within 100 snapshots
// we should give up
List<File> snapList = findNValidSnapshots(100);
if (snapList.size() == 0) {
return -1L;
}
File snap = null;
boolean foundValid = false;
for (int i = 0; i < snapList.size(); i++) {
snap = snapList.get(i);
InputStream snapIS = null;
CheckedInputStream crcIn = null;
try {
LOG.info("Reading snapshot " + snap);
snapIS = new BufferedInputStream(new FileInputStream(snap));
crcIn = new CheckedInputStream(snapIS, new Adler32());
InputArchive ia = BinaryInputArchive.getArchive(crcIn);
deserialize(dt, sessions, ia);
long checkSum = crcIn.getChecksum().getValue();
long val = ia.readLong("val");
if (val != checkSum) {
throw new IOException("CRC corruption in snapshot : " + snap);
}
foundValid = true;
break;
} catch(IOException e) {
LOG.warn("problem reading snap file " + snap, e);
} finally {
if (snapIS != null)
snapIS.close();
if (crcIn != null)
crcIn.close();
}
}
if (!foundValid) {
throw new IOException("Not able to find valid snapshots in " + snapDir);
}
dt.lastProcessedZxid = Util.getZxidFromName(snap.getName(), SNAPSHOT_FILE_PREFIX);
return dt.lastProcessedZxid;
}

对比已经解析出的最大 zxid,选择对应的 log 文件

// org.apache.zookeeper.server.persistence.FileTxnLog.FileTxnIterator#init
void init() throws IOException {
storedFiles = new ArrayList<File>();
List<File> files = Util.sortDataDir(FileTxnLog.getLogFiles(logDir.listFiles(), 0), LOG_FILE_PREFIX, false);
for (File f: files) {
if (Util.getZxidFromName(f.getName(), LOG_FILE_PREFIX) >= zxid) {
storedFiles.add(f);
}
// add the last logfile that is less than the zxid
else if (Util.getZxidFromName(f.getName(), LOG_FILE_PREFIX) < zxid) {
storedFiles.add(f);
break;
}
}
goToNextLog();
if (!next())
return;
while (hdr.getZxid() < zxid) {
if (!next())
return;
}
}

zk 文件存储的更多相关文章

  1. Kafka与RocketMq文件存储机制对比

    一个商业化消息队列的性能好坏,其文件存储机制设计是衡量一个消息队列服务技术水平和最关键指标之一. 开头问题 kafka文件结构和rocketMQ文件结构是什么样子?特点是什么? 一.目录结构 Kafk ...

  2. Android数据存储之Android 6.0运行时权限下文件存储的思考

    前言: 在我们做App开发的过程中基本上都会用到文件存储,所以文件存储对于我们来说是相当熟悉了,不过自从Android 6.0发布之后,基于运行时权限机制访问外置sdcard是需要动态申请权限,所以以 ...

  3. 深入理解Sqlserver文件存储之页和应用 (转)

    我们每天都在使用数据库,我们部门使用最多的关系数据库有Sqlserver,Oracle,有没有想过这些数据库是怎么存放到操作系统的文件中的?有时候为了能够设计出最优的表结构,写出高性能的Sqlserv ...

  4. app端上传文件至服务器后台,web端上传文件存储到服务器

    1.android前端发送服务器请求 在spring-mvc.xml 将过滤屏蔽(如果不屏蔽 ,文件流为空) <!-- <bean id="multipartResolver&q ...

  5. MongoDb gridfs-ngnix文件存储方案

          在各类系统应用服务端开发中,我们经常会遇到文件存储的问题. 常见的磁盘文件系统,DBMS传统文件流存储.今天我们看一下基于NoSQL数据库MongoDb的存储方案.笔者环境 以CentOS ...

  6. Hadoop中pid文件存储

    我的hadoop集群部署在自己电脑虚拟机上,有时候我是挂起虚拟机,第二天再打开发现有些线程就挂了,比如namenode,好奇怪,当时看了一些帖子说是和pid存储有关,找到log看到找不到pid.因为基 ...

  7. Android文件存储

    文件存储是Android中最基本的一种数据存储方式,它不读存储的内容进行任何的格式化处理,所有数据原封不动的保存在文件之中.如果想用文件存储的方式保存一些较为复杂的数据,就需要定义一套自己的格式规范, ...

  8. Kafka深入理解-1:Kafka高效的文件存储设计

    文章摘自:美团点评技术团队  Kafka文件存储机制那些事 Kafka是什么 Kafka是最初由Linkedin公司开发,是一个分布式.分区的.多副本的.多订阅者,基于zookeeper协调的分布式日 ...

  9. .Net平台下,分布式文件存储的实现

    遇到的问题 对于Web程序,使用一台服务器的时候,客户端上传的文件一般也都是存储在这台服务器上.但在集群环境中就行不通了,如果每个服务器都存储自己接受到的文件,就乱套了,数据库中明明有这个附件的记录, ...

随机推荐

  1. httpd统计的其他方法,awk,sed等

    1. https://stackoverflow.com/questions/345546/how-to-get-requests-per-second-for-apache-in-linux 2. ...

  2. 3.(基础)tornado的接口调用顺序与模板

    上一节介绍了tornado的请求与响应,这一节介绍tornado的接口调用顺序和模板 首先都有哪些接口呢?作用是什么呢?并且都有的时候,执行顺序是怎么样的呢? 接口 1.initialize,表示初始 ...

  3. 安装haroopad

    安装haroopad 1)官网下载安装包 http://pad.haroopress.com/user.html 2)执行安装命令: sudo dpkg -i haroopad-v0.13.1-x64 ...

  4. 手动写一个类支持foreach循环

    之前初学时看过可以实现Iterable接口实现Iterator迭代器的支持,并且也支持foreach循环.现在学习了数据结构,手动写一个单链表支持foreach循环吧. 手写foreach循环步骤: ...

  5. python django 重新安装不能创建项目

    这里仅给大家做个思路提醒: 1.如果在别的地方找到一样的问题那就按别的方法去解决 2.如果是创建startproject的时候 报错:no module named 'mysite'  这个的话就和 ...

  6. 转(static final 和final的区别)

    学习java的时候常常会被修饰符搞糊涂,这里总结下static final和final的区别. 1.static 强调只有一份,final 说明是一个常量,final定义的基本类型的值是不可改变的,但 ...

  7. 批处理清除svn版本信息

    for /r . %%a in (.) do @if exist "%%a\.svn" rd /s /q "%%a\.svn"

  8. JS转为number的四种方法

    // 1.Number() var num1 = Number(true); console.log(num1); var num2 = Number(" ") console.l ...

  9. 利用pipework为docker容器设置固定IP

    今天介绍如何在redhat/centos7系列机器上使用pipework为docker启动的容器指定一个固定ip,我们知道默认情况下,docker会使用 bridge网络模式为每一个启动的容器动态分配 ...

  10. Java GUI :Hello World

    public class Demo01 extends Frame{ public Demo01(){ super("Demo01");//标题 this.setSize(450, ...