Zookeeper(四))持久化日志文件
Zookeeper(四))持久化日志文件
持久化用途
存储两种文件
- snapshot:内存快照
- log:事务日志,类似MySQL的binlog,存储数据节点的操作日志
问题
- 序列化的本质其实就是将原数据重新写入
- roll中的BufferedOutputStream.flush和commit中的FileChannel.force()都是强制刷新:有什么区别
基本术语
- FileTxnSnapLog,封装了TxnLog和SnapShot。 是操作数据文件和快照文件的对外API
- TxnLog,接口类型,读取事务性日志的接口。
- FileTxnLog,实现TxnLog接口,添加了访问该事务性日志的API。
- Snapshot,接口类型,持久层快照接口。
- FileSnap,实现Snapshot接口,负责存储、序列化、反序列化、访问快照。
- Util,工具类,提供持久化所需的API。
实现
TxnLog
public interface TxnLog {
/**
* Setter for ServerStats to monitor fsync threshold exceed
* @param serverStats used to update fsyncThresholdExceedCount
*/
void setServerStats(ServerStats serverStats);
// 滚动日志,从当前日志滚到下一个日志,不是回滚
void rollLog() throws IOException;
// 添加一个请求至事务性日志
boolean append(TxnHeader hdr, Record r) throws IOException;
// 读取事务性日志
TxnIterator read(long zxid) throws IOException;
// 事务性操作的最新zxid
long getLastLoggedZxid() throws IOException;
// 清空zxid以后的日志
boolean truncate(long zxid) throws IOException;
// 获取数据库的id
long getDbId() throws IOException;
// 提交事务并进行确认
void commit() throws IOException;
long getTxnLogSyncElapsedTime();
// 关闭事务性日志
void close() throws IOException;
}
FileTxnLog
实现TxnLog接口,提供操作事务日志的api
public class FileTxnLog implements TxnLog {
//最新的日志zxid
long lastZxidSeen;
//日志文件
volatile BufferedOutputStream logStream = null;
volatile OutputArchive oa;
//日志存储文件
File logFileWrite = null;
private FilePadding filePadding = new FilePadding();
private LinkedList<FileOutputStream> streamsToFlush =
new LinkedList<FileOutputStream>();
//重置日志文件
public synchronized void rollLog() throws IOException {
if (logStream != null) {
this.logStream.flush();
this.logStream = null;
oa = null;
}
}
//添加事务日志 hdr:事务标题 txn:事务本身
public synchronized boolean append(TxnHeader hdr, Record txn)
throws IOException {
if (hdr == null) {
return false;
}
//判断并更新最新的zxid
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()));
}
//1. 生成新的log文件
logFileWrite = new File(logDir, Util.makeLogName(hdr.getZxid()));
//2. 生成log文件输出流
fos = new FileOutputStream(logFileWrite);
//为写入给定的输出流而创建缓冲输出流
logStream=new BufferedOutputStream(fos);
//获取二进制序列化类 TODO
//BinaryOutputArchive内部维护一个DataOutput 根据值传递特性
//oa序列化写入时其实就是写入log文件
oa = BinaryOutputArchive.getArchive(logStream);
//3. 用TXNLOG_MAGIC VERSION dbId来生成事务日志文件头
FileHeader fhdr = new FileHeader(TXNLOG_MAGIC,VERSION, dbId);
//4. 将事务日志文件头序列化到文件上
fhdr.serialize(oa, "fileheader");
//确保文件扩展之前 魔数已被写入
logStream.flush();
filePadding.setCurrentSize(fos.getChannel().position());
streamsToFlush.add(fos);
}
//5. 剩余空间不足时 填充文件
filePadding.padFile(fos.getChannel());
//6. 将事务头部和本身序列化为字节数组
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");
//6. 将当前序列化的事务记录写入到oa
Util.writeTxnBytes(oa, buf);
return true;
}
//从给定的zxid开始读取日志文件
public TxnIterator read(long zxid, boolean fastForward) throws IOException {
return new FileTxnIterator(logDir, zxid, fastForward);
}
//提交日志 保存到磁盘
public synchronized void commit() throws IOException {
//刷到磁盘
if (logStream != null) {
logStream.flush();
}
//强刷到磁盘
for (FileOutputStream log : streamsToFlush) {
log.flush();
if (forceSync) {
long startSyncNS = System.nanoTime();
FileChannel channel = log.getChannel();
//会强制将所有未写入磁盘的数据都强制写入磁盘 比如还在缓冲区中的数据
channel.force(false);
syncElapsedMS = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startSyncNS);
if (syncElapsedMS > fsyncWarningThresholdMS) {
if(serverStats != null) {
serverStats.incrementFsyncThresholdExceedCount();
}
LOG.warn("fsync-ing the write ahead log in "
+ Thread.currentThread().getName()
+ " took " + syncElapsedMS
+ "ms which will adversely effect operation latency. "
+ "File size is " + channel.size() + " bytes. "
+ "See the ZooKeeper troubleshooting guide");
}
ServerMetrics.FSYNC_TIME.add(syncElapsedMS);
}
}
//移除流并关闭
while (streamsToFlush.size() > 1) {
streamsToFlush.removeFirst().close();
}
//当日志文件大小超过限制 强刷到磁盘并重置
if(txnLogSizeLimit > 0) {
long logSize = getCurrentLogSize();
if (logSize > txnLogSizeLimit) {
LOG.debug("Log size limit reached: {}", logSize);
rollLog();
}
}
}
}
FileTxnIterator:用于读取事务日志
public static class FileTxnIterator implements TxnLog.TxnIterator {
public FileTxnIterator(File logDir, long zxid, boolean fastForward)
throws IOException {
this.logDir = logDir;
this.zxid = zxid;
init();
if (fastForward && hdr != null) {
while (hdr.getZxid() < zxid) {
if (!next())
break;
}
}
}
void init() throws IOException {
storedFiles = new ArrayList<File>();
//找出大于等于snapshot中最大的zxid的logfile及后续logfile并升序
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();
next();
}
}
Zookeeper(四))持久化日志文件的更多相关文章
- MySQL5.7 四种日志文件
mysql 日志包括:错误日志,二进制日志,通用查询日志,慢日志等 一:通用查询日志: 记录建立的客户端连接和执行的语句 1)show variables like '%verision%'; 显示数 ...
- Zookeeper日志文件&事务日志&数据快照
Zookeeper持久化两类数据,Transaction以及Snapshot,logDir存储transaction命令,dataDir存储snap快照,其下子目录名称以version-2命名,子目录 ...
- zookeeper清除日志文件工具
zookeeper运行时间长了以后,日志会成为一个比较大的问题.比如作者压力测试hbase一周以后,zookeeper日志文件达到了10G的规模.由于zookeeper日志文件不能随意删除,因为一个长 ...
- 消费滚动滴log日志文件(flume监听,kafka消费,zookeeper协同)
第一步:数据源 手写程序实现自动生成如下格式的日志文件: 15837312345,13737312345,2017-01-09 08:09:10,0360 打包放到服务器,使用如下命令执行,模拟持续不 ...
- 四步搞定Zabbix 日志文件监控
Zabbix 日志文件监控 一.给运行Zabbix agent的用户授予要监控日志的读取权限. 1. 執行下面的命令,追加app的可讀權限: setfacl -m u:app:r-- /var/log ...
- nginx(四)初识nginx日志文件
nginx 日志相关指令主要有两条,一条是log_format,用来设置日志格式,另外一条是access_log,用来指定日志文件的存放路径.格式和缓存大小,通俗的理解就是先用log_format来定 ...
- 【lucene系列学习四】log4j日志文件实现多线程的测试
参考资料:http://nudtgk2000.iteye.com/blog/1716379 首先,在http://www.apache.org/dyn/closer.cgi/logging/log4j ...
- ELK+Filebeat+Kafka+ZooKeeper 构建海量日志分析平台(elk5.2+filebeat2.11)
ELK+Filebeat+Kafka+ZooKeeper 构建海量日志分析平台 参考:http://www.tuicool.com/articles/R77fieA 我在做ELK日志平台开始之初选择为 ...
- zookeeper(3) 持久化
zookeeper为了防止,系统宕机或重启导致的数据丢失,会对数据进行定时持久化.有两种持久化方式: 1.为每次事务操作记录到日志文件,这样就可以通过执行这些日志文件来恢复数据. 2.为了加快ZooK ...
随机推荐
- 18 Python之初识面向对象
1. 类与对象 class Car: #类名首字母大写,严格遵守驼峰命名规范 pass #造车 c = Car() #类名() #创建对象 ##出场之后进行改装 c.color = "红色& ...
- 第二十二篇 jQuery 学习4 内容和属性
jQuery 内容和属性 这节课,我们学习使用jQuery来控制元素的内容.值和属性. html() 控制所选元素的内容(包括HTML标记): text() 控制所选元素的内容: val() ...
- mySql 的常用命令
一.数据库操作 1.创建数据库 create database <数据库名>: -- 例如,创建test数据库,create database test; 2.查询所有的数据库 show ...
- ShuffleNet系列学习笔记
ShuffleNet是旷世提出的高效轻量化网络,是一款很值得一提的轻量化网络,其相关论文也是很有价值的. ShuffleNet V1 该网络提出于2017年,论文为<ShuffleNet: An ...
- CI/CD----jenkins+gitlab+django(内网)
1.py第三方包获取 ./pip3 ./pip3 -i "http://pypi.douban.com/simple/" --trusted-host pypi.douban.co ...
- Linux下的启动oracle服务 启动监听 开放端口操作
尝试登录oracle 使用root用户将没有sqlplus命令 [root@localhost ~]# sqlplus /nolog bash: sqlplus: 未找到命令... [root ...
- https://github.com/zabbix/zabbix-docker 安装
docker-compose -f ./docker-compose_v3_centos_mysql_latest.yaml up -d 解压文件,运行即可
- 字符串类QString
采用Unicode编码,所以一个QChar占用两个字节使用隐式共享技术来节省内存和减少不必要的数据拷贝跨平台使用,不用考虑字符串的平台兼容性QString直接支持字符串和数字之间的相互转换QStrin ...
- Django+BootstrapTable实现表格分页
models.py: from django.db import models # Create your models here. class Article(models.Model): titl ...
- http的get与post
1.http请求 http有两种报文,请求报文 (发送请求,可能包含数据)和响应报文(服务器响应请求获取数据).一个http请求报文由请求行,请求头部,空行和请求正文(数据)四个部分组成. HTTP请 ...