Apache BookKeeper Ledger 的底层存储机制解析
Apache BookKeeper 的 ledger(账本)是其核心数据存储单元,底层存储机制结合了日志追加(append-only)、分布式存储和容错设计。Ledger 的数据存储在 Bookie 节点的磁盘上,具体实现涉及 Journal(日志)和 Ledger Storage(账本存储)两个部分。以下是 ledger 底层存储数据的详细机制:
Ledger 存储的整体架构
- 分布式存储:
- 一个 ledger 的数据分布在多个 Bookie 节点上(由 ensembleSize 定义,例如 3 个节点)。
- 每个 Bookie 负责存储 ledger 的一部分或全部数据(取决于 writeQuorum 配置)。
- 两阶段存储:
- Journal:实时记录写入操作的事务日志,确保数据持久化。
- Ledger Storage:长期存储账本数据,优化读取性能。
- 文件系统:
- 数据直接存储在 Bookie 节点的本地文件系统中(例如 ext4、XFS),没有额外的数据库层。
底层存储的实现细节
1. Journal(日志)
- 作用:
- Journal 是 ledger 数据写入的第一步,用于保证数据持久性和一致性。
- 每次写入条目(entry)时,先追加到 Journal,确保即使系统崩溃也能恢复。
- 存储位置:
- 配置项 journalDirectory 指定路径(例如 /bookkeeper/journal)。
- 每个 Bookie 节点独立维护自己的 Journal。
- 文件结构:
- Journal 由多个日志文件组成,按时间或大小滚动(rollover)。
- 文件名格式:journal.<timestamp>(例如 journal.1698765432100)。
- 每个文件是一个顺序追加的二进制文件。
- 写入过程:
- 客户端发送条目到 Bookie。
- Bookie 将条目序列化为二进制格式,包含:
- Ledger ID:账本标识。
- Entry ID:条目序列号。
- Data:实际数据内容。
- 追加到当前 Journal 文件。
- 可配置 journalSyncData=true(默认),调用 fsync 强制刷盘,确保数据持久化。
- 返回确认(ACK)给客户端。
- 性能优化:
- Journal 使用顺序写入,适合高吞吐量。
- 建议将 journalDirectory 放在高速磁盘(例如 SSD)上。
2. Ledger Storage(账本存储)
- 作用:
- Journal 确认后,数据异步写入 Ledger Storage,用于长期存储和读取。
- 存储位置:
- 配置项 ledgerDirectories 指定路径(例如 /bookkeeper/ledgers)。
- 可以配置多个目录(例如 /disk1/ledgers, /disk2/ledgers),分散 I/O 负载。
- 文件结构:
- Ledger 数据按 ledger 分片存储,目录结构:
-
/bookkeeper/ledgers/ ├── current/ # 当前活跃的账本文件 │ ├── 00000001.log # Ledger ID 1 的数据文件 │ ├── 00000002.log # Ledger ID 2 的数据文件 ├── recovered/ # 崩溃恢复后的文件 └── compacted/ # 压缩后的文件(可选) - 每个 .log 文件对应一个 ledger,包含该 ledger 的所有条目。
- 写入过程:
- Journal 写入成功后,条目放入内存缓冲区(EntryLogger)。
- 缓冲区满或达到刷新间隔(ledgerStorage_flushInterval)时,异步写入 .log 文件。
- 数据按 Entry ID 顺序存储,文件格式为二进制。
- 索引:
- 为了快速定位条目,BookKeeper 维护一个索引。
- 配置项 indexDirectories 指定路径(默认与 ledgerDirectories 相同)。
- 默认使用文件系统索引(FileInfo),可选配置 RocksDB(dbStorage_rocksDB_* 参数)提高性能。
- 索引记录每个 Entry ID 在 .log 文件中的偏移量。
3. 数据分布
- Ensemble:
- 一个 ledger 的数据分布在 ensembleSize 个 Bookie 上。
- 例如,ensembleSize=3,数据可能存储在 bookie1、bookie2、bookie3。
- Write Quorum:
- 每次写入,数据完整存储在 writeQuorumSize 个 Bookie 上。
- 如果 writeQuorum < ensembleSize,不同条目可能分布在不同的 Bookie 子集。
- 副本:
- 每个条目在多个 Bookie 上有副本(由 writeQuorum 控制),提供容错性。
数据写入的完整流程
以 ensembleSize=3, writeQuorum=3, ackQuorum=2 为例:
- 客户端:
- 创建 ledger,分配 Ledger ID=1,选择 bookie1、bookie2、bookie3 作为 ensemble。
- 发送条目 entry1 到 3 个 Bookie。
- Bookie:
- bookie1:写入 /journal/journal.<timestamp>,返回 ACK。
- bookie2:写入 /journal/journal.<timestamp>,返回 ACK。
- bookie3:写入 /journal/journal.<timestamp>,返回 ACK(可能稍慢)。
- 客户端收到 2 个 ACK(满足 ackQuorum=2),写入成功。
- 异步存储:
- 每个 Bookie 将 entry1 从 Journal 移到 /ledgers/current/00000001.log。
- 更新索引,记录 entry1 的偏移量。
数据读取
- 读取流程:
- 客户端指定 Ledger ID 和 Entry ID。
- Bookie 从索引查找条目位置。
- 从 .log 文件读取数据返回。
- 容错:
- 如果某个 Bookie 不可用,客户端从其他副本读取(需要至少 ackQuorum 个副本可用)。
存储特性
- 追加式存储:
- Ledger 只支持追加写入(append-only),不支持修改或删除。
- 删除 ledger 需要关闭并通过 ZooKeeper 删除元数据。
- 纠删码(Erasure Coding):
- 默认不使用纠删码,而是完整副本存储。
- 可通过配置启用纠删码(实验性功能),减少存储开销。
- 持久性:
- Journal 的 fsync 保证写入持久化。
- Ledger Storage 异步写入,依赖 Journal 恢复一致性。
崩溃恢复
- Journal 回放:
- Bookie 重启时,检查 Journal 文件,恢复未写入 Ledger Storage 的条目。
- 恢复后,数据移到 recovered/ 目录。
- 一致性:
- 只要 ackQuorum 个 Bookie 存活,数据不会丢失。
性能优化
- 分离存储:
- 将 journalDirectory 和 ledgerDirectories 放在不同磁盘(例如 SSD 和 HDD),提高 I/O 性能。
- 批量写入:
- Journal 支持批量 fsync,减少磁盘同步开销。
- 索引优化:
- 使用 RocksDB 替代默认文件索引,加速查找。
总结
Ledger 的底层存储机制:
- Journal:顺序写入事务日志,保证持久性,存储在 journalDirectory。
- Ledger Storage:异步存储账本数据,分布在 ledgerDirectories 的 .log 文件中。
- 索引:记录条目偏移量,存储在 indexDirectories。
- 分布式:数据按 ensembleSize 分布在多个 Bookie,副本数由 writeQuorum 控制。
这种设计结合了高吞吐量(顺序写入)、低延迟(异步存储)和容错性(多副本),非常适合分布式日志存储需求。你的 Go Demo 数据最终存储在 3 个 Bookie 的 Journal 和 Ledger 文件中,具体路径取决于 Docker Compose 的卷配置
相关文章:
Apache BookKeeper Ledger 的底层存储机制解析
Apache BookKeeper 的 ledger(账本)是其核心数据存储单元,底层存储机制结合了日志追加(append-only)、分布式存储和容错设计。Ledger 的数据存储在 Bookie 节点的磁盘上,具体实现涉及 Journal(日…...
从代码上深入学习GraphRag
网上关于该算法的解析都停留在大概流程上,但是具体解析细节未知,由于代码是PipeLine形式因此阅读起来比较麻烦,本文希望通过阅读项目代码来解析其算法的具体实现细节,特别是如何利用大模型来完成图谱生成和检索增强的实现细节。 …...
通俗地讲述DDD的设计
通俗地讲述DDD的设计 前言为什么要使用DDDDDD架构分层重构实践关键问题解决方案通过领域事件机制解耦服务依赖:防止逻辑下沉 领域划分电商场景下的领域划分 结语完结撒花,如有需要收藏的看官,顺便也用发财的小手点点赞哈,…...
【Redis】通用命令
使用者通过redis-cli客户端和redis服务器交互,涉及到很多的redis命令,redis的命令非常多,我们需要多练习常用的命令,以及学会使用redis的文档。 一、get和set命令(最核心的命令) Redis中最核心的两个命令&…...
网络安全技术文档
网络安全技术文档 1. 概述 网络安全是指通过技术手段和管理措施,保护网络系统的硬件、软件及其数据不受偶然或恶意破坏、更改、泄露,确保系统连续可靠运行,网络服务不中断。 2. 常见网络威胁 2.1 攻击类型 DDoS攻击:分布式拒…...
微前端随笔
✨ single-spa: js-entry 通过es-module 或 umd 动态插入 js 脚本 ,在主应用中发送请求,来获取子应用的包, 该子应用的包 singleSpa.registerApplication({name: app1,app: () > import(http://localhost:8080/app1.js),active…...
【36期获取股票数据API接口】如何用Python、Java等五种主流语言实例演示获取股票行情api接口之沪深A股当天逐笔大单交易数据及接口API说明文档
在量化分析领域,实时且准确的数据接口是成功的基石。经过多次实际测试,我将已确认可用的数据接口分享给正在从事量化分析的朋友们,希望能够对你们的研究和工作有所帮助,接下来我会用Python、JavaScript(Node.js&…...
C++中的浅拷贝和深拷贝
浅拷贝只是将变量的值赋予给另外一个变量,在遇到指针类型时,浅拷贝只会把当前指针的值,也就是该指针指向的地址赋予给另外一个指针,二者指向相同的地址; 深拷贝在遇到指针类型时,会先将当前指针指向地址包…...
二叉树与红黑树核心知识点及面试重点
二叉树与红黑树核心知识点及面试重点 一、二叉树 (Binary Tree) 1. 基础概念 定义:每个节点最多有两个子节点(左子节点和右子节点) 术语: 根节点:最顶层的节点 叶子节点:没有子节点的节点 深度…...
GitHub 趋势日报 (2025年04月01日)
GitHub 趋势日报 (2025年04月01日) 本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ 📈 今日整体趋势 Top 10 排名项目名称项目描述今日获星语言1punkpeye/awesome-mcp-serversA collection of MCP servers.⭐ 3280未指定2th-ch/youtube-musicYouTu…...
Java的SeleniumChromeDriver的常用方法
启动和关闭浏览器: driver.get(url):打开指定的URL。driver.quit():关闭浏览器并结束ChromeDriver会话。 元素定位: driver.findElement(By.id("elementId")):通过元素的ID定位。driver.findElement(By.cl…...
字符串、列表、元组、字典
字符串 双引号或者单引号中的数据,就是字符串 字符串输入 之前在学习input的时候,通过它能够完成从键盘获取数据,然后保存到指定的变量中; 注意:input获取的数据,都以字符串的方式进行保存,即…...
【GEE学习笔记】报错解决:“Image.select: Band pattern ‘QA60‘ did not match any bands”
【GEE学习笔记】报错解决:“Image.select: Band pattern ‘QA60’ did not match any bands” 【GEE学习笔记】报错解决:“Image.select: Band pattern ‘QA60’ did not match any bands” 文章目录 【GEE学习笔记】报错解决:“Image.selec…...
AI可以赋能的三农产品、机械与服务
三农赛道涵盖农业、农村和农民相关的产品与服务,涉及农资、农业机械、智能设备、农产品加工及数字化服务等多个领域。随着人工智能(AI)技术的飞速发展,AI正在通过赋能农业的生产、管理、销售等各个环节,推动传统农业向…...
ngx_timezone_update
定义在 src\os\unix\ngx_time.c void ngx_timezone_update(void) { #if (NGX_FREEBSD)if (getenv("TZ")) {return;}putenv("TZUTC");tzset();unsetenv("TZ");tzset();#elif (NGX_LINUX)time_t s;struct tm *t;char buf[4];s tim…...
车载诊断架构 --- 整车重启先后顺序带来的思考
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…...
GESP C++三级 知识点讲解
C编程三级标准 (一)知识点详述 (1)了解二进制数据编码:原码、反码、补码。 (2)掌握数据的进制转换:二进制、八进制、十进制、十六进制。 (3)掌握位运算:与(&)、或(|)、非(~)、异或(^)、左移(<<)、右移(>>)的基本使用方法及原理。 (4)了解算法的概念与描述&…...
前端 vs 后端:技术分工详解——从用户界面到系统逻辑的全解析
前端(Frontend) 和 后端(Backend) 是软件开发中两个核心概念,分别对应用户直接交互的部分和系统背后的逻辑处理部分。它们共同构成完整的应用程序,但分工不同。 目录 一、前端(Frontend…...
Redis 除了数据类型外的核心功能 的详细说明,包含事务、流水线、发布/订阅、Lua 脚本的完整代码示例和表格总结
以下是 Redis 除了数据类型外的核心功能 的详细说明,包含事务、流水线、发布/订阅、Lua 脚本的完整代码示例和表格总结: 1. Redis 事务(Transactions) 功能描述 事务通过 MULTI 和 EXEC 命令将一组命令打包执行,保证…...
JavaScript智能对话机器人——企业知识库自动化
引言 内部知识管理常面临信息分散、查找困难的问题。本文将使用Node.js和虎跃办公的智能对话API,构建企业级知识问答机器人,支持自然语言查询和自动学习。 核心技术 自然语言处理(NLP)意图识别机器学习模型微调REST API集成 代…...
JS实现AES和DES
目录 目标 概述 DES AES 实战 JS实现DES JS实现AES 目标 了解AES和DES的特点并用JS实现。 概述 DES 翻译过来叫数据加密标准。它有5种加密模式(CTR、OFB、CFB、CBC、ECB),在JS中,不同加密模式语法结构几乎一致,…...
【C++11(下)】—— 我与C++的不解之缘(三十二)
前言 随着 C11 的引入,现代 C 语言在语法层面上变得更加灵活、简洁。其中最受欢迎的新特性之一就是 lambda 表达式(Lambda Expression),它让我们可以在函数内部直接定义匿名函数。配合 std::function 包装器 使用,可以…...
Windows 10/11系统优化工具
家庭或工作电脑使用时间久了,会出现各种各样问题,今天给大家推荐一款专为Windows 10/11系统设计的全能优化工具,该软件集成了超过40项专业级实用程序,可针对系统性能进行深度优化、精准调校、全面清理、加速响应及故障修复。通过系…...
浅谈在HTTP中GET与POST的区别
从 HTTP 报文来看: GET请求方式将请求信息放在 URL 后面,请求信息和 URL 之间以 ?隔开,请求信息的格式为键值对,这种请求方式将请求信息直接暴露在 URL 中,安全性比较低。另外从报文结构上来看,…...
LightRAG实战:轻松构建知识图谱,破解传统RAG多跳推理难题
作者:后端小肥肠 🍊 有疑问可私信或评论区联系我。 🥑 创作不易未经允许严禁转载。 姊妹篇: 2025防失业预警:不会用DeepSeek-RAG建知识库的人正在被淘汰_deepseek-embedding-CSDN博客 从PDF到精准答案:Coze…...
C++多线程编码二
1.lock和try_lock lock是一个函数模板,可以支持多个锁对象同时锁定同一个,如果其中一个锁对象没有锁住,lock函数会把已经锁定的对象解锁并进入阻塞,直到多个锁锁定一个对象。 try_lock也是一个函数模板,尝试对多个锁…...
垃圾回收——三色标记法(golang使用)
三色标记法(tricolor mark-and-sweep algorithm)是传统 Mark-Sweep 的一个改进,它是一个并发的 GC 算法,在Golang中被用作垃圾回收的算法,但是也会有一个缺陷,可能程序中的垃圾产生的速度会大于垃圾收集的速度,这样会导…...
Linux学习笔记——零基础详解:什么是Bootloader?U-Boot启动流程全解析!
零基础详解:什么是Bootloader?U-Boot启动流程全解析! 一、什么是Bootloader?📌 举个例子: 二、U-Boot 是什么?三、U-Boot启动过程:分为两个阶段🔹 第一阶段(汇…...
Windows环境下开发pyspark程序
Windows环境下开发pyspark程序 一、环境准备 1.1. Anaconda/Miniconda(Python环境) 如果不怕包的版本管理混乱,可以直接使用已有的Python环境。 需要安装anaconda/miniconda(python3.8版本以上):Anaconda…...
thinkphp8.0上传图片到阿里云对象存储(oss)
1、开通oss,并获取accessKeyId、accessKeySecret <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><tit…...
