的 Log 与 KV 架构)
Garnet 存储引擎解析TsavoriteFASTER C# 分支的 Log 与 KV 架构【免费下载链接】garnetGarnet is a remote cache-store from Microsoft Research that offers strong performance (throughput and latency), scalability, storage, recovery, cluster sharding, key migration, and replication features. Garnet can work with existing Redis clients.项目地址: https://gitcode.com/GitHub_Trending/garnet4/garnet导读Garnet 的持久化与存储能力并不直接构建在裸磁盘之上而是依托于一个独立演进的高性能存储引擎——Tsavorite。它是微软 FASTER 项目的 C# 库在 Garnet 仓库中的深度优化分支由 FASTER Log高性能并发持久化日志与 FASTER KV支持大于内存数据的并发键值存储与缓存两个核心构件组成。本文以 libs/storage/Tsavorite/README.md 为主线结合 Tsavorite 源码目录 中的真实实现讲解 Tsavorite 的日志、键值存储、设备抽象、检查点恢复机制以及它们在 Garnet 中的应用方式。读完本文你将理解 Garnet 底层存储引擎的架构全貌、核心机制背后的源码依据以及如何沿着仓库路径继续深入研读。从 FASTER 到 TsavoriteGarnet 的存储地基根目录 README 开门见山地指出在云环境中以高性能、高弹性地管理大规模应用状态是最困难的问题之一。FASTER 项目为此提供两个构件来解决该问题FASTER Log一个 C# 编写的高性能并发持久化可恢复日志、迭代器与随机读取器库支持极低延迟的高频提交操作可快速占满磁盘带宽同时提供同步与异步接口、磁盘错误处理与校验和。FASTER KV一个 C# 与 C 双语言实现的并发键值存储 缓存面向点查询point lookups与高频更新heavy updates场景设计。通过借助快速外部存储本地或云端FASTER 支持承载大于内存的数据并利用快速非阻塞检查点技术实现一致性恢复允许应用在性能与提交延迟之间做取舍。而 libs/storage/Tsavorite/cs/README.md 则给出了 Tsavorite 的正确定位Tsavorite is a fork of the FASTER C# library that we have significantly extended and optimized to support Garnets requirements.这句话包含两个关键事实其一Tsavorite 是 FASTER C# 库的分支fork其二它并非简单复刻而是为满足 Garnet 的需求被显著扩展和优化significantly extended and optimized。从源码结构看这一扩展优化体现在多个维度分配器从 blittable 记录扩展出支持任意长度对象的SpanByte/ObjectAllocator体系、日志层面新增了面向 AOF/复制场景的TsavoriteLog提交机制、设备层引入了 Linux 原生 AIO 支持、检查点机制演化出流式快照Streaming Snapshot等。本文后续小节即围绕这些展开。构件一TsavoriteLog——高并发持久化可恢复日志README 中 FASTER Log 的能力描述在源码中对应 TsavoriteLog.cs。这个类被定位为Tsavorite Log是一个独立于 KV 存储的日志库供需要只追加、可恢复、可随机读取的场景使用。提交Commit与恢复语义从 TsavoriteLog.cs 类定义L21 可以看到TsavoriteLog维护了beginAddress、TailAddress、FlushedUntilAddress等地址水位BeginAddress日志逻辑起始地址其下方数据可以被物理回收TailAddress日志尾部地址即下一个写入位置FlushedUntilAddress已落盘flush的最大地址。值得注意的设计是 L81-L83 的注释TsavoriteLog 层维护一个软 BeginAddress仅在该层被所有访问者观察到但并未真正作用到分配器上——这是为了确保任何物理删除physical delete都只发生在提交commit之后从而保证崩溃恢复的一致性。这与 README 强调的持久化可恢复persistent recoverable直接对应。大对象的 Chunked 写入TsavoriteLog.cs L26-L30 定义了MinPartialAllocSize 1 201 MB当一个键/值/对象的大小超过该阈值即被视为大对象large必须拆分为多个 chunk 记录写入。对应的实现位于 TsavoriteLog.Chunked.cs 与分配器侧PartialSlots机制见 TsavoriteLogAllocatorImpl.cs通过 ObjectSerialization 目录 中的ChunkedObjectSerializer、ChunkHeader、DiskReadBuffer/DiskWriteBuffer等组件实现跨页分块读写。这一机制解决了日志中单个记录可能大于单个页的问题是 FAQ 中处理磁盘错误、支持校验和之外的又一个工程细节。校验和与提交策略TsavoriteLog通过LogChecksumType见 TsavoriteLog.cs L39支持可选的校验和对应 README 中supports checksums的表述同时内置LogCommitPolicyLogCommitPolicy.cs与ILogCommitManager抽象允许将提交记录落到不同介质并支持快速提交fast commit与只读模式readOnlyMode等变体见 TsavoriteLog.cs L42-L44。这些设计共同支撑了非常频繁的提交操作 低延迟这一 README 宣称的能力。构件二TsavoriteKV——支持大于内存的并发键值存储README 中 FASTER KV 的定位并发 KV 存储 缓存、面向点查询与重更新、数据可大于内存、非阻塞检查点恢复在源码中对应 TsavoriteKV.cs。混合日志Hybrid Log核心架构从 TsavoriteKV 类定义L20 可见一个 KV 实例内部持有两条日志hlog主混合日志数据的主存放地热数据留在内存页冷数据按需落盘readcache读缓存日志可选的读缓存将频繁读取的磁盘记录提升到内存。这种混合日志设计正是数据大于内存的实现基础索引hash index常驻内存指向日志地址而记录本身可以在内存页与磁盘页之间流动从而让总数据规模突破内存上限。README 中leveraging fast external storage的表述对应 Device 目录 中的多种设备实现见下一节。哈希索引与内存度量Tsvavorite.cs L44-L83 提供了观察索引与内存消耗的指标接口例如EntryCount哈希索引中的活跃条目数因哈希冲突不完全等同于记录总数IndexSize/IndexSizeBytes主哈希表大小按 64 字节缓存行计见Constants.kCacheLineBytesOverflowBucketCount溢出桶数量配合主桶共同容纳哈希冲突IndexTotalSizeBytes主表 溢出桶的总索引内存。索引以缓存行为单位组织HashBucket.cs、HashBucketEntry.cs这是为多线程无锁并发访问做缓存行对齐优化的重要细节。并发控制Epoch 与 RevivificationTsavorite 的并发安全不依赖大粒度的全局锁而是基于 LightEpoch.csepoch 防护机制来安全地回收内存页保证正在被某线程访问的记录不会在页回收时被释放。这一点在 PauseRevivification/ResumeRevivificationL116-L149 的代码中也有体现暂停/恢复 revivification记录复活即删除后复用记录槽位时需要先通过 epoch 同步所有线程。Revivification槽位复用是 Tsavorite 相对传统 FASTER 的增强方向之一相关实现集中在 Implementation/Revivification 目录RevivificationManager、FreeRecordPool、RevivificationSettings它能显著减少高删除率工作负载下的内存碎片与分配开销。会话Session与函数式扩展Tsavorite KV 通过 ClientSession 目录 提供IClientSession/ITsavoriteContext等接口支持同步、异步与unsafe绕过同步开销三种操作模式用户通过实现IStoreFunctionsStoreFunctions.cs注入键比较、序列化与操作逻辑。Garnet 正是通过定义自己的存储函数与键类型把 Redis 语义如字符串、哈希、列表等对象的 RMW 操作映射到 Tsavorite KV 之上。持久化落地设备抽象层README 提到的本地或云端外部存储在代码中被抽象为IDevice接口Device/IDevice.cs仓库中至少包含以下实现见 Device 目录LocalStorageDevice/NativeStorageDevice本地文件设备。其中NativeStorageDevice通过平台原生库见 Device/runtimes 下各平台目录中的libnative_device.so/native_device.dll在 Linux 上使用 libaio 等原生异步 IO追求更高吞吐ManagedLocalStorageDevice托管实现便于调试与跨平台兜底TieredStorageDevice分层设备可将日志的不同区段路由到不同性能等级的存储ShardedStorageDevice分片设备把一条日志按扇区范围分散到多个底层设备LocalMemoryDevice/NullDevice内存模拟与空设备主要用于测试与纯内存场景云端实现位于 devices/AzureStorageDevice提供 Azure Blob 上的设备与检查点命名方案AzureStorageDevice、AzureCheckpointNamingScheme。底层写入都遵循扇区对齐要求sectorSize见 Tsavorite.cs L33并由StorageDeviceBase统一管理 IO 提交与回调。这一层让快速占满磁盘带宽从口号变成了可插拔的工程能力。检查点与恢复非阻塞一致性快照README 强调的fast non-blocking checkpointing在 Index/Checkpointing 目录中有完整实现其核心是一套状态机驱动的检查点框架FullCheckpointSM/IndexCheckpointSM/HybridLogCheckpointSM分别对应全量检查点、仅索引检查点与仅混合日志检查点支持将索引与日志分开持久化以缩短恢复时间SnapshotCheckpointSM/StreamingSnapshotCheckpointSM快照检查点其中 Streaming流式变体可在不阻塞前台写入的前提下持续生成一致性快照这正是非阻塞的关键——通过 LightEpoch.cs 与FoldOverSMTask协同把检查点工作拆分为后台任务TsavoriteStateMachineProperties.csStateMachineDriver/StateMachineBase驱动与基类定义任务转换StateTransitions.cs。检查点的落盘位置由ICheckpointManagerIndex/Recovery/ICheckpointManager.cs与命名方案DefaultCheckpointNamingScheme、LocalStorageNamedDeviceFactory决定恢复逻辑则集中在 Index/Recovery/Recovery.cs。通过索引检查点 日志检查点 截断日志的组合Tsavorite 可以在秒级内恢复到一个一致状态同时把前台提交的额外延迟降到最低——这正是 README 所说trade-off performance for commit latency的含义。Tsavorite 在 Garnet 中的落位Tsavorite 并非孤立存在的库它是 Garnet 数据面的地基。从仓库结构可以确认以下对应关系AOF 与复制日志Garnet 的ShardedLog/SingleLogserver/AOF建立在 TsavoriteLog 之上利用其提交、校验和与 chunked 写入能力承载追加式日志GarnetLog中的记录读取/恢复依赖 TsavoriteLog 的扫描迭代器。主存储StoreWrapperserver/StoreWrapper.cs与GarnetDatabase封装了 TsavoriteKV 的KVSettings/LogSettings配置混合日志的内存页数、读缓存与 revivification 等参数GarnetCheckpointManagerserver/GarnetCheckpointManager.cs则对接上述检查点状态机为 Garnet 提供索引/日志检查点与启动恢复能力。存储函数Garnet 通过 Storage/Functions 下的 32 个函数文件把 Redis 各数据类型的操作字符串、哈希、列表、集合、有序集合、Bitmap、对象容器等编译进 TsavoriteKV 的 RMW/Read/Upsert 流程。换言之Garnet 的强性能、可恢复、集群分片、键迁移与复制能力很大程度上是站在 Tsavorite 这层存储引擎的肩膀上实现的而 Tsavorite 也因 Garnet 的需求反向获得了持续的性能与功能演进。性能与适用性说明README 原文明示Both FASTER KV and FASTER Log offer orders-of-magnitude higher performance than comparable solutions, on standard workloads这是 FASTER 项目自身的表述。作为技术文档我们应当如实引用该说法同时建议读者以仓库内的 benchmark 目录 与 test 目录 中的实测程序为准在自身硬件与工作负载上验证。需要明确的是Tsavorite 的目标场景是点查询与高频更新、数据规模大于内存、需要快速恢复的服务端存储而非通用键值缓存或分析型负载。总结与深入路径以 libs/storage/Tsavorite/README.md 为索引本文把 FASTER 的两大构件映射到了 Tsavorite 的具体实现上README 描述的能力Tsavorite 源码对应高性能并发持久化日志、迭代器、随机读TsavoriteLog.cs、TsavoriteLogScanIterator.cs校验和、磁盘错误处理、同步/异步接口LogChecksumType、ILogCommitManager、Async 目录并发 KV 存储 缓存、数据大于内存TsavoriteKV.cs、hlog/readcache双日志快速外部存储本地/云端Device 目录、AzureStorageDevice非阻塞检查点与一致恢复Checkpointing 目录、Recovery 目录若想继续深入推荐按以下顺序阅读仓库源码先看 TsavoriteLog.cs 理解日志提交语义再看 Tsavorite.cs 把握 KV 总体结构随后进入 Allocator 与 Checkpointing 两个核心目录最后回到 Garnet 的 StoreWrapper 观察两者如何组装成生产级的远程缓存存储服务。这套阅读路径能让你把Garnet 为什么快、为什么可靠这两个问题从架构描述落实到每一行关键实现。【免费下载链接】garnetGarnet is a remote cache-store from Microsoft Research that offers strong performance (throughput and latency), scalability, storage, recovery, cluster sharding, key migration, and replication features. Garnet can work with existing Redis clients.项目地址: https://gitcode.com/GitHub_Trending/garnet4/garnet创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考