持久化FileTxnLog

简介: 本文深入分析Zookeeper持久化机制的源码实现,重点解析TxnLog与FileTxnLog类。涵盖事务日志结构、append追加、commit提交、truncate截断等核心操作,详解日志格式、zxid管理及文件处理流程,揭示数据持久化的底层原理。

一、前言  前一篇已经分析了序列化,这篇接着分析Zookeeper的持久化过程源码,持久化对于数据的存储至关重要,下面进行详细分析。二、持久化总体框架  持久化的类主要在包org.apache.zookeeper.server.persistence下,此次也主要是对其下的类进行分析,其包下总体的类结构如下图所示。  

  · TxnLog,接口类型,读取事务性日志的接口。  · FileTxnLog,实现TxnLog接口,添加了访问该事务性日志的API。  · Snapshot,接口类型,持久层快照接口。  · FileSnap,实现Snapshot接口,负责存储、序列化、反序列化、访问快照。  · FileTxnSnapLog,封装了TxnLog和SnapShot。  · Util,工具类,提供持久化所需的API。  下面先来分析TxnLog和FileTxnLog的源码。三、TxnLog源码分析  TxnLog是接口,规定了对日志的响应操作。其中,TxnLog除了提供读写事务日志的API外,还提供了一个用于读取日志的迭代器接口TxnIterator。四、FileTxnLog源码分析  对于LogFile而言,其格式可分为如下三部分  LogFile:    FileHeader TxnList ZeroPad  FileHeader格式如下    FileHeader: {    magic 4bytes (ZKLG)    version 4bytes    dbid 8bytes  }  TxnList格式如下  TxnList:    Txn || Txn TxnList  Txn格式如下  Txn:    checksum Txnlen TxnHeader Record 0x42  Txnlen格式如下  Txnlen:    len 4bytes  TxnHeader格式如下  TxnHeader: {    sessionid 8bytes    cxid 4bytes      zxid 8bytes    time 8bytes    type 4bytes  }  ZeroPad格式如下  ZeroPad:    0 padded to EOF (filled during preallocation stage)  了解LogFile的格式对于理解源码会有很大的帮助。4.1 属性 4.2. 核心函数 1. append函数说明:append函数主要用做向事务日志中添加一个条目,其大体步骤如下  ① 检查TxnHeader是否为空,若不为空,则进入②,否则,直接返回false  ② 检查logStream是否为空(初始化为空),若不为空,则进入③,否则,进入⑤  ③ 初始化写数据相关的流和FileHeader,并序列化FileHeader至指定文件,进入④  ④ 强制刷新(保证数据存到磁盘),并获取当前写入数据的大小。进入⑤  ⑤ 填充数据,填充0,进入⑥  ⑥ 将事务头和事务序列化成ByteBuffer(使用Util.marshallTxnEntry函数),进入⑦  ⑦ 使用Checksum算法更新步骤⑥的ByteBuffer。进入⑧  ⑧ 将更新的ByteBuffer写入磁盘文件,返回trueappend间接调用了padLog函数,其源码如下 说明:padLog其主要作用是当文件大小不满64MB时,向文件填充0以达到64MB大小。2. getLogFiles函数 说明:该函数的作用是找出刚刚小于或者等于snapshot的所有log文件。其步骤大致如下。  ① 对所有log文件按照zxid进行升序排序,进入②  ② 遍历所有log文件并记录刚刚小于或等于给定snapshotZxid的log文件的logZxid,进入③    ③ 再次遍历log文件,添加zxid大于等于步骤②中的logZxid的所有log文件,进入④  ④ 转化后返回getLogFiles函数调用了sortDataDir,其源码如下说明:getLogFiles其用于排序log文件,可以选择根据zxid进行升序或降序。getLogFiles函数间接调用了getZxidFromName,其源码如下: 说明:getZxidFromName主要用作从文件名中解析zxid,并且需要从指定的前缀开始。3. getLastLoggedZxid函数 说明:该函数主要用于获取记录在log中的最后一个zxid。其步骤大致如下  ① 获取已排好序的所有log文件,并从最后一个文件中取出zxid作为候选的最大zxid,进入②  ② 新生成FileTxnLog并读取步骤①中zxid之后的所有事务,进入③  ③ 遍历所有事务并提取出相应的zxid,最后返回。其中getLastLoggedZxid调用了read函数,其源码如下 说明:read函数会生成一个FileTxnIterator,其是TxnLog.TxnIterator的子类,之后在FileTxnIterator构造函数中会调用init函数,其源码如下说明:init函数用于进行初始化操作,会根据zxid的不同进行不同的初始化操作,在init函数中会调用goToNextLog函数,其源码如下  说明:goToNextLog表示选取下一个log文件,在init函数中还调用了next函数,其源码如下  说明:next表示将迭代器移动至下一个事务,方便读取,next函数的步骤如下。  ① 读取事务的crcValue值,用于后续的验证,进入②  ② 读取事务,使用CRC32进行更新并与①中的结果进行比对,若不相同,则抛出异常,否则,进入③  ③ 将事务进行反序列化并保存至相应的属性中(如事务头和事务体),会确定具体的事务操作类型。  ④ 在读取过程抛出异常时,会首先关闭流,然后再尝试调用next函数(即进入下一个事务进行读取)。4. commit函数  说明:该函数主要用于提交事务日志至磁盘,其大致步骤如下  ① 若日志流logStream不为空,则强制刷新至磁盘,进入②  ② 遍历需要刷新至磁盘的所有流streamsToFlush并进行刷新,进入③  ③ 判断是否需要强制性同步,如是,则计算每个流的流式时间并在控制台给出警告,进入④  ④ 移除所有流并关闭。5. truncate函数 

Java

运行代码复制代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

public boolean truncate(long zxid) throws IOException {

FileTxnIterator itr = null;

try {

// 获取迭代器

itr = new FileTxnIterator(this.logDir, zxid);

PositionInputStream input = itr.inputStream;

long pos = input.getPosition();

// now, truncate at the current position

// 从当前位置开始清空

RandomAccessFile raf = new RandomAccessFile(itr.logFile, "rw");

raf.setLength(pos);

raf.close();

while (itr.goToNextLog()) { // 存在下一个log文件

if (!itr.logFile.delete()) { // 删除

LOG.warn("Unable to truncate {}", itr.logFile);

}

}

} finally {

// 关闭迭代器

close(itr);

}

return true;

}

说明:该函数用于清空大于给定zxid的所有事务日志。五、总结  对于持久化中的TxnLog和FileTxnLog的源码分析就已经完成了,本章节需重点记住:append函数实现日志追加,记录通过事务的crcValue验证,决定是否更新通过getLogFiles获取全部日志文件并排序通过getLastLoggedZxid找到最大的zxid,保证后续函数决定下一个日志文件id通过commit提交,真正生成日志文件通过trancate清空指定事务日志


相关文章
|
8月前
|
缓存
QLExpress使用及源码分析
本文介绍基于QLExpress的规则引擎实现方案,涵盖实体构建、接口定义与脚本编写。通过@QLAlias注解映射字段别名,结合YAML配置规则表达式,实现逻辑解耦。运行时动态解析AST语法树,支持汉化变量与上下文绑定,并提供缓存与延迟执行机制,提升性能与灵活性。
163 0
QLExpress使用及源码分析
|
8月前
|
存储 关系型数据库 MySQL
微服务原理篇(XXLJOB-幂等-MySQL)
本文介绍了XXL-JOB任务调度的优势、组成结构及热点商品缓存更新任务的实现,涵盖幂等性概念与解决方案,并深入解析了MySQL存储引擎特性、索引失效场景、回表与覆盖索引原理以及SQL调优和分库分表策略。
364 0
微服务原理篇(XXLJOB-幂等-MySQL)
|
8月前
|
canal 缓存 关系型数据库
微服务原理篇(Canal-Redis)
本文介绍了ES索引同步的常见方案,重点讲解Canal+MQ数据同步机制。通过解析MySQL的binlog日志,Canal模拟slave伪装接入主库,实现增量数据捕获,并结合RabbitMQ保证消息顺序性地同步至Elasticsearch。同时探讨了缓存一致性问题,提出使用分布式锁(如Redis)控制并发写操作,避免双写不一致。还涵盖Redis持久化、集群模式、过期淘汰策略及缓存三剑客(穿透、雪崩、击穿)的解决方案,系统梳理了高并发场景下的数据同步与缓存保障技术体系。
936 0
 微服务原理篇(Canal-Redis)
|
8月前
|
人工智能 机器人 Java
黑马最新项目
AIGC项目涵盖大模型私有化部署、聊天机器人、RAG知识库及代码提示工具;天机AI集成SpringAI与多模型工作流;云岚到家聚焦微服务与分布式架构;四方保险构建统一支付与时序数据应用;星辰WMS与Dify项目即将发布。
438 0
黑马最新项目
|
8月前
|
机器学习/深度学习 人工智能 自然语言处理
大模型专业名词解释手册
本手册由油炸小波设计提示词、Manus创作,系统梳理大语言模型核心概念,涵盖基础原理、训练技术、优化压缩、推理应用、评估调试及伦理安全六大模块,深入浅出解析LLM关键技术术语。
748 0
|
8月前
|
Arthas 存储 运维
记Arthas实现一次CPU排查与代码热更新
本文介绍使用Arthas排查Java应用CPU占用过高问题的完整流程,涵盖线程分析、阻塞定位、watch命令追踪异常、jad反编译实现热更新及火焰图分析,实现无需重启应用的高效故障排查与代码修复。
274 0
|
8月前
|
消息中间件 人工智能 NoSQL
RocketMQ:A2A协议实现多智能体优化
Apache RocketMQ推出专为AI场景设计的轻量级通信模型LiteTopic,助力多智能体高效协作。通过百万级队列支持、会话状态持久化、断点续传与动态订阅等能力,解决AI应用中长时交互、上下文管理难、资源浪费等问题。结合A2A协议与AgentScope框架,实现高可靠、低延迟的Agent-to-Agent通信,构建稳定可扩展的企业级AI系统架构。(238字)
344 0
|
8月前
|
人工智能 NoSQL 前端开发
面试真题
汇总多套AI与后端技术面试题,涵盖RAG、微服务、JVM、分布式锁、MySQL优化、大模型部署等核心技术点,深入考察候选人项目经验、系统设计能力及对AI工程化的理解。
415 0
|
8月前
|
人工智能 自然语言处理 API
全面认识MCP:大模型连接真实世界的“USB-C接口”
MCP(模型上下文协议)是Anthropic推出的开放标准,被誉为AI时代的“USB-C”。它统一了大模型与工具、数据源的连接方式,简化集成,提升安全与扩展性,推动AI智能体实现复杂任务自动化,正重塑全球AI应用生态。
1330 0
|
8月前
|
XML 算法 安全
详解RAG五种分块策略,技术原理、优劣对比与场景选型之道
RAG通过检索与生成结合,提升大模型在企业场景的准确性与可控性。分块策略是其核心,直接影响检索效果与生成质量。本文系统解析五种主流分块方法:固定大小、语义、递归、基于结构及LLM分块,对比其优缺点与适用场景,并提出组合优化建议,助力构建高效、可信的RAG系统。
352 0

热门文章

最新文章