ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

DiceDB 多线程分片架构设计解析:Store 抽象、Shard 管理与跨分片命令协调(2024-08-19 架构讨论纪要)

DiceDB 多线程分片架构设计解析:Store 抽象、Shard 管理与跨分片命令协调(2024-08-19 架构讨论纪要) DiceDB 多线程分片架构设计解析Store 抽象、Shard 管理与跨分片命令协调2024-08-19 架构讨论纪要【免费下载链接】dicedbOpen-source, low-latency key/value engine built on Valkey with query subscriptions and hierarchical storage tiers.项目地址: https://gitcode.com/GitHub_Trending/dic/dicedb导读本文基于仓库 docs/src/content/updates/2024-08-19.md 这一份架构设计讨论纪要展开它是 DiceDB 从单线程迈向多线程、从单一 Store 迈向多分片架构的关键设计节点。文中记录了关注点分离Separation of Concerns、IOLayer 协调策略、Store 保持简单原则以及一整套分片化改造任务清单。读完本文你将理解 DiceDB 的分片模型、跨分片命令MGET/MSET与 QWATCH 的协调方案以及这些设计在当前仓库源码中的落地形态。一、文档背景一次决定架构走向的设计讨论2024-08-19.md并不是一篇完整的发布日志而是一次架构会议的设计纪要以 Discussed 开头。它讨论的核心问题是当 DiceDB 从单 Store 演进为多 Shard分片 多线程架构时命令执行、数据存储与订阅通知三层之间应该如何切分职责。结合仓库现状看这次讨论的直接产物是internal/shard、internal/shardmanager、internal/shardthread三个包的出现以及internal/store中 Store 抽象的重构。因此这篇纪要可视为理解 DiceDB 当前多线程分片架构的设计蓝图。二、核心议题一Keep Store Dumb —— 让存储层保持简单纪要中提出了一条贯穿始终的原则Keep store dumb. All ops on store as atomic as possible. Add complexity to IOLayer / Coordinator in future if optimisations are needed in future.即Store 只做最原子的数据操作所有跨分片的编排复杂度都上移给 IOLayer / Coordinator。这是典型的分层设计思想——先保证正确性再谈优化。从当前源码可以看到这一原则的落地internal/store/store.go 中的Store结构体职责非常收敛持有数据表store、过期表expires、键计数numKeys、命令监听通道cmdWatchChan和淘汰策略evictionStrategy并通过ShardID标识自己属于哪个分片Store 对外暴露的操作接口基本限定在Putstore.go、PutAll、Getstore.go、GetAllstore.go、Delstore.go等原子读写方法与纪要中Limit Store operations to Put / Get / Delete Scan的任务方向一致数据表底层采用sync.Map封装的RegMapstore.go避免在热点路径上引入显式Mutex这与纪要中Removing all Mutex from Store的目标相符。也就是说Store 保持简单意味着像 MGET/MSET 这类跨分片命令绝不能在单个 Store 内完成全部逻辑而必须由上层协调。三、核心议题二Shard 与 ShardManager —— 分片模型如何落地纪要讨论的核心前提是数据会被拆分到多个分片。当前仓库中分片模型由三层构成组件文件职责Shardinternal/shard/main.go极简结构体仅包含ID与一个ShardThread引用ShardThreadinternal/shardthread/main.go每个分片独立的执行线程持有自己的Store与 cron 周期ShardManagerinternal/shardmanager/main.go管理全部Shard负责生命周期与 key 路由关键实现细节key 路由ShardManager.GetShardForKey使用xxhash.Sum64String(key) % shardCount将任意 key 稳定映射到某个分片shardmanager/main.go。这决定了跨分片命令的本质难点一个命令涉及多个 key而这些 key 可能落在不同分片上独立 Store每个ShardThread通过dstore.NewStore(nil, evictionStrategy, id)创建自己专属的Storeshardthread/main.go分片之间数据天然隔离后台任务ShardThread.Start以config.ShardCronFrequency为周期运行 cron 任务如DeleteExpiredKeys清理过期键并响应 context 取消做清理shardthread/main.go生命周期管理ShardManager.Run监听 SIGINT/SIGTERM 与父 context统一启停所有分片 goroutineshardmanager/main.go。这套结构与纪要中Skeleton for multithreaded mode的任务直接对应——每个分片一个线程、一份 Store为后续多线程执行打下骨架。四、核心议题三跨分片命令与事务 —— 需要 Coordinator 抽象层纪要明确指出了一个设计缺口Transactional commands like MGET/MSET - We need an abstraction layer outside shards that can manage the transaction across the shards.即 MGET、MSET 这类命令的 key 分散在多个分片需要分片之外的抽象层Coordinator来跨分片管理事务与一致性。纪要还给出了后续任务Extract Coordinator from IO Tasks。从当前源码可以看到相关的过渡性设计。在 internal/eval/execute.go 中有一段关键注释dealing with store object is not recommended for all commands. These operations are specialised for the commands which requires transferring data across multiple shards. e.g. COPY, RENAME, PFMERGE也就是说部分跨分片命令通过StoreObjectEval在 Store 层面取对象、评估、修改、写回来处理这正是Coordinator 抽象层尚未完全成型前为跨分片操作保留的特殊通道。另外在命令执行入口 internal/cmd/cmds.go 中Cmd.Execute通过CommandRegistry查找CommandMeta并调用c.Meta.Execute(c, sm)——注意它接收的是*shardmanager.ShardManager而非单个 Store说明命令层天然被设计为面向多分片执行与纪要中抽象层位于分片之外的思路一致。五、核心议题四QWATCH 的扇出 —— 模式跨分片时的订阅协调纪要对 QWATCH 的讨论非常具体Qwatch: each io thread launches a qwatch command, this fans out to every shard. Each shard now maintains records for which io threads are listening to which queries.moar thoughts - the watchlist can be maintained at the said coordinator level.问题的本质是QWATCH 监听的是 key 模式pattern而非单个 key而符合模式的 key 可能分布在所有分片上。纪要给出的两种方案扇出Fanout方案每个 IO 线程发起 QWATCH 命令后把查询扇出到每个分片每个分片记录哪些 IO 线程在监听哪些查询Coordinator 集中维护方案watchlist 统一维护在 Coordinator 层。从当前仓库的 internal/server/ironhawk/watch_manager.go 看订阅关系目前由三层映射维护keyFPMapkey → 命令指纹集合记录某个 key 被哪些查询订阅fpClientMap命令指纹 → 客户端 ID 集合记录某个查询被哪些客户端订阅fpCmdMap命令指纹 → 原始命令当数据变化时需要重放该命令获取最新结果。命令指纹由 internal/cmd/cmds.go 中的farm.Fingerprint64([]byte(c.String()))计算——指纹化的意义正是让同一查询在不同位置可被唯一识别与去重。而NotifyWatcherswatch_manager.go在数据变更后重新执行订阅命令并推送结果实现了查询结果实时刷新。关于 QWATCH 命令本身的语法与行为可参见 docs/src/content/docs/QWATCH.md它支持SELECT $key, $value WHERE ... ORDER BY ... LIMIT n的 DSQL 语法。六、核心议题五IOLayer 的协调策略与一致性纪要对 IOLayer 提出了一个待定问题IOLayer - Should it wait for all shards to complete the tasks, proceed only after all shards have responded.即IOLayer 是否应该等待所有分片完成任务后再响应客户端。这是一个典型的强一致 vs 低延迟权衡若等待全部 shard 响应能保证结果一致尤其对 MGET/MSET 这类跨分片命令但延迟取决于最慢的分片若部分响应即返回延迟更低但可能返回不完整或中间状态的数据。纪要同时记下了Fanout commands that require consistency作为后续任务说明需要一致性的扇出命令如跨分片事务必须协调好聚合时机。从 internal/server/ironhawk/iothread.go 可以看到 IOLayer 的雏形IOThread.Start循环接收wire.Command封装为cmd.Cmd后调用_c.Execute(shardManager)执行再依据命令是否以WATCH/UNWATCH结尾交由WatchManager处理或直接回包。这个IO 线程执行 → 分片路由 → 订阅管理的链路正是纪要中 IOLayer 与 Coordinator 职责分工的早期实现。七、后续任务清单纪要原文要点2024-08-19.md最后列出的 next step 任务完整记录了那次讨论确定的演进方向任务负责人纪要对应现状/源码线索Remove locks and provide atomic operations—Store 底层使用sync.Mapstore.goAddress review comments and merge Store abstraction refactorYashinternal/store已重构为独立包Watch to move out of store / implement a scan operator in storeJyotinderWatch 逻辑位于 internal/server/ironhawk/watch_manager.go已从 Store 移出Limit Store operations to Put / Get / Delete ScanPratikStore 当前核心方法即Put/Get/GetAll/Delstore.goMove from unsafe pointer to empty struct/interface, use genericsAshwin KulkarniStore 数据表为泛型接口common.ITable[string, *object.Obj]Removing all Mutex from Store after shards and channels createdsoumyaRegMap基于sync.Map无显式 MutexSkeleton for multithreaded modeYashinternal/shardthreadinternal/shardmanager已落地Extract Coordinator from IO TasksGaurav跨分片命令暂通过StoreObjectEval通道处理execute.goQwatch fanout per-shard listening recordsJyotinderWatchManager 三层映射watch_manager.goFanout commands that require consistencysoumya一致性聚合策略仍在演进这些任务中多线程分片骨架、Store 抽象、Watch 移出 Store三项在现有代码中已有清晰落地其余Coordinator 提取、一致性扇出属于持续演进中的设计方向。八、实践启示如何基于此设计使用 DiceDB对于使用 DiceDB 的开发者这份纪要的价值在于理解其架构行为边界单 key 操作SET/GET/DEL由GetShardForKey哈希路由到唯一分片天然原子、无跨分片开销多 key 命令MGET/MSET涉及多个分片属于纪要讨论的需要协调层的命令类别使用时应关注其跨分片语义与一致性保证QWATCH 模式订阅监听的是跨分片的 key 模式由 WatchManager 统一维护订阅关系并在数据变更时重放查询参见 QWATCH.md 的 DSQL 语法与实时排行榜示例过期清理由每个ShardThread的 cron 任务独立执行shardthread/main.go因此不同分片的过期删除节奏是并行、独立的。九、总结2024-08-19.md虽然篇幅简短却浓缩了 DiceDB 架构演进中最关键的一次职责切分决策Store 保持原子与简单、分片按哈希隔离、跨分片命令交由上层协调、QWATCH 以扇出方式跨分片监听。透过当前仓库的internal/shard、internal/shardmanager、internal/shardthread、internal/store、internal/server/ironhawk等实现可以看到这份纪要并非纸上谈兵——大部分设计已经转化为可运行的代码骨架为后续的多线程执行、Coordinator 抽象与一致性扇出提供了清晰的演进起点。【免费下载链接】dicedbOpen-source, low-latency key/value engine built on Valkey with query subscriptions and hierarchical storage tiers.项目地址: https://gitcode.com/GitHub_Trending/dic/dicedb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表