博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Zookeeper原理分析之存储结构ZkDatabase
阅读量:5116 次
发布时间:2019-06-13

本文共 3365 字,大约阅读时间需要 11 分钟。

ZKDatabase在内存中维护了zookeeper的sessions, datatree和commit logs集合。 当zookeeper server启动的时候会将txnlogs和snapshots从磁盘读取到内存中。核心逻辑主要在方法ZkDatabase.loadDataBase()中实现,其代码如下:

/**     * 将数据从磁盘加载到内存中,并将事物添加到内存中的提交日志中     * @return 磁盘上最后一个有效的zxid     * @throws IOException     */    public long loadDataBase() throws IOException {        PlayBackListener listener=new PlayBackListener(){            public void onTxnLoaded(TxnHeader hdr,Record txn){                Request r = new Request(null, 0, hdr.getCxid(),hdr.getType(),                        null, null);                r.txn = txn;                r.hdr = hdr;                r.zxid = hdr.getZxid();                addCommittedProposal(r);            }        };                long zxid = snapLog.restore(dataTree,sessionsWithTimeouts,listener);        initialized = true;        return zxid;    }

loadDataBase的流程如下:

  • 构建一个PlayBackListener对象
  • snapshot的反序列,倒叙排目录下的snapshot文件,遍历查找出最新的那个有效snapshot文件进行反序列化到内存。snapshot的反序列后我们会知道snapshot最新的zxid叫做lastProcessedZxid, 这个lastProcessedZxid之前的事务操作,都成功执行并序列到snapshot中可恢复到内存,lastProcessedZxid之后的操作只有事务日志,不能直接通过snapshot恢复。

snapLog.restore实现如下:

public long restore(DataTree dt, Map
sessions, PlayBackListener listener) throws IOException { //从最近的快照中对数据树进行反序列化 snapLog.deserialize(dt, sessions); //lastProcessedZxid+1从事务日志文件txnLog读取事务操作 FileTxnLog txnLog = new FileTxnLog(dataDir); TxnIterator itr = txnLog.read(dt.lastProcessedZxid+1); long highestZxid = dt.lastProcessedZxid; TxnHeader hdr; try { while (true) { //遍历TxnIterator,执行processTransaction方法,就是把事务操作在内存中在执行一遍把丢失的操作补回来 hdr = itr.getHeader(); if (hdr == null) { //empty logs return dt.lastProcessedZxid; } if (hdr.getZxid() < highestZxid && highestZxid != 0) { LOG.error("{}(higestZxid) > {}(next log) for type {}", new Object[] { highestZxid, hdr.getZxid(), hdr.getType() }); } else { highestZxid = hdr.getZxid(); } try { processTransaction(hdr,dt,sessions, itr.getTxn()); } catch(KeeperException.NoNodeException e) { throw new IOException("Failed to process transaction type: " + hdr.getType() + " error: " + e.getMessage(), e); } // 同时将事务操作通过PlayBackListener添加到commitedLog集合,commitedLog的事务操作在服务恢复的时候会同步到其他leaner server, 因为很有可能其他leaner server也没有及时的takesnapshot listener.onTxnLoaded(hdr, itr.getTxn()); if (!itr.next()) break; } } finally { if (itr != null) { itr.close(); } } //返回最后的事务日志zxid给database,作为ZKDatabase的最新事物id return highestZxid; }

在zookeeperServer成功loadDatabase后,会及时主动的做一次takesnapshot操作来得到一份最新的内存影像。snapshot是内存数据的某个点一份影像,takeSnapshot操作还是很耗时,为了性能根据一下算法操作:

  • 创建在同步处理器SyncRequestProcessor
  • 100000/2 + random.nextInt(100000/2),这个十万是一个默认值可配置)计算出一个值,如果logCount大于这个值,就进行takeSnapshot操作

上面的算法存在一个问题, 那就是在非正常关机情况下,最新有效的那个snapshot并不是内存中最新的数据,所以需要利用txnLogs来把没有生成snapshot的操作在内存重新执行一边来恢复到非正常关闭服务那一刻内存情况。

转载于:https://www.cnblogs.com/senlinyang/p/8416515.html

你可能感兴趣的文章
Android 获取网络链接类型
查看>>
linux中启动与终止lnmp的脚本
查看>>
gdb中信号的处理[转]
查看>>
LeetCode【709. 转换成小写字母】
查看>>
如何在Access2007中使用日期类型查询数据
查看>>
Jzoj4757 树上摩托
查看>>
CF992E Nastya and King-Shamans(线段树二分+思维)
查看>>
第一个Java Web程序
查看>>
树状数组_一维
查看>>
如果没有按照正常的先装iis后装.net的顺序,可以使用此命令重新注册一下:
查看>>
linux install ftp server
查看>>
嵌入式软件设计第8次实验报告
查看>>
算法和数据结构(三)
查看>>
Ubuntu下的eclipse安装subclipse遇到没有javahl的问题...(2天解决了)
查看>>
alter database databasename set single_user with rollback IMMEDIATE 不成功问题
查看>>
Repeater + Resources 列表 [原创][分享]
查看>>
WCF揭秘——使用AJAX+WCF服务进行页面开发
查看>>
【题解】青蛙的约会
查看>>
IO流
查看>>
mybatis调用存储过程,获取返回的游标
查看>>