作者:Jessica_猪猪到_697 | 来源:互联网 | 2024-12-06 20:33
作者:赵一霖
在前文中,我们详细讨论了 Pump Server 的启动流程、gRPC API 的实现、服务下线及相关辅助机制,期间多次提及 Pump Storage。本文将聚焦于 Pump Storage 的具体实现,其源代码主要位于 pump/storage 目录下。
Pump Storage 是由 Pump Server 调用的一个模块,主要职责是实现 binlog 的持久化存储,并支持数据的排序与配对。接下来,我们将从 Storage 接口入手,逐步解析 Pump Storage 的内部工作原理。
Storage 接口概述
Storage 接口定义了 Pump Storage 对外提供的主要操作方法,其中包括重要的 WriteBinlog
、GC
和 PullCommitBinlog
方法。以下是 Storage 接口的定义:
type Storage interface { // 写入 binlog 数据到 Storage WriteBinlog(binlog *pb.Binlog) error // 清理 tso 小于指定 ts 的 binlog GC(ts int64) // 返回最近一次触发 GC 指定的 ts GetGCTS() int64 // 判断所有 P-binlog 是否都与 C-binlog 匹配 AllMatched() bool // 返回最大 CommitTS,在此 TS 之前的数据已完整可同步 MaxCommitTS() int64 // 根据指定 ts 获取 binlog GetBinlog(ts int64) (binlog *pb.Binlog, err error) // 按序拉取 commitTs 大于 last 的 binlog PullCommitBinlog(ctx context.Context, last int64) <-chan []byte // 安全关闭 Storage Close() error }
Append 持久化实现
Append 是基于文件系统的持久化实现,主要负责将 binlog 数据追加写入到 Valuelog 中。考虑到单条 binlog 可能非常大,为了提升性能,我们采用了 Key 和 Value 分离的设计策略,使用 goleveldb 存储 Key(binlog 的时间戳),并设计了专门用于存储 binlog 数据的 Valuelog 组件。
初始化过程
Append 的初始化逻辑在 NewAppendWithResolver
函数中实现,主要包括初始化 Valuelog、goleveldb 等组件,并启动多个 goroutine 以处理 binlog 写入、GC 和状态维护等工作。
WriteBinlog 方法解析
WriteBinlog
方法由 Pump Server 调用,用于将 binlog 数据写入本地持久化存储。在 Append 实现中,binlog 数据在编码后会被送入 Append.writeCh
通道,由专门的 goroutine 处理:
toKV := append.writeToValueLog(writeCh) go append.writeToSorter(append.writeToKV(toKV))
binlog 数据进入 Append.writeCh
后,将依次经过以下几个处理阶段:
- ValueLog:主要由
writeToValueLog
函数实现,将 binlog 数据批量写入 ValueLog 组件中。ValueLog 是一种持久化的键值存储实现,具体将在后续文章中详细介绍。 - Metadata:由
writeBatchToKV
函数实现,将 binlog 的时间戳作为 Key,valuePointer
作为 Value 批量写入 Metadata 存储中。当前 Pump 使用 goleveldb 作为 Metadata 存储数据库,其底层数据结构为 LSM-Tree,确保了 binlog 相关信息按时间戳自然排序。 - Sorter:尽管 binlog 元数据在写入过程中已经排序,但仍需
writeToSorter
进行进一步处理。这是因为 TiDB 事务采用 2PC 算法,每个成功事务包含 Prewrite 和 Commit 两条 binlog;若事务失败,则会生成一条 Rollback binlog。为了准确还原事务,必须对 Prewrite 和 Commit binlog 进行配对。Sorter 负责读取 binlog 并进行配对,对于长时间未找到匹配项的 Prewrite binlog,Sorter 会查询 TiKV 以确认其状态。
PullCommitBinlog 方法解析
PullCommitBinlog
方法用于从客户端指定的时间戳开始拉取 Commit binlog。其实现较为直接,Append 会扫描 Metadata,仅关注 Commit binlog,并根据 StartTs 查找对应的 Prewrite binlog,从而确保拉取到的均为已提交的 binlog。
GC 机制分析
GC 机制是 Pump Storage 中不可或缺的部分,旨在定期清理不再需要的 binlog 数据,以释放存储空间。GC 的触发条件包括:binlog 已同步至下游或其时间戳距离当前时间已超过预设时间。GC 过程分为两个阶段:一是扫描并删除 Metadata 中的旧数据;二是根据删除的 KVS 数量触发 Valuelog 的 GC,最终表现为删除文件系统中的文件。
在实际应用中,为避免 GC 过程对系统性能造成负面影响,我们对 GC 进行了限速处理,例如通过监控 goleveldb 中 L0 文件的数量来决定是否暂停 GC。
总结
本文深入探讨了 Pump Storage 的初始化过程及其核心功能的实现,希望对读者理解 TiDB Binlog 系统有所帮助。下一篇文章将重点介绍 Valuelog 和 SlowChaser 等辅助机制。