ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ScyllaDB 视图构建协调器(View Building Coordinator):tablet keyspace 集群级视图构建与 group0 任务状态机

ScyllaDB 视图构建协调器(View Building Coordinator):tablet keyspace 集群级视图构建与 group0 任务状态机 ScyllaDB 视图构建协调器View Building Coordinatortablet keyspace 集群级视图构建与 group0 任务状态机【免费下载链接】scylladbNoSQL data store using the Seastar framework, compatible with Apache Cassandra and Amazon DynamoDB项目地址: https://gitcode.com/GitHub_Trending/sc/scylladb本文以 ScyllaDB 仓库中的开发文档 view-building-coordinator.md 为主体系统讲解 tablet 型 keyspace 中物化视图/索引的集群级构建机制视图构建协调器view building coordinator如何运行在 Raft leader 上、如何把整个构建过程拆分为build_range与process_staging两类持久化任务、任务在 group0 状态system.view_building_tasks表中的完整生命周期、针对 tombstone 告警的 GC 优化以及节点本地的 view building worker 如何执行任务并回应 RPC。读完后你可以掌握 tablet 模式下视图构建的端到端调用链work_on_view_building_tasksRPC、staging sstable 决策逻辑并能在 db/view/ 源码中定位到每个环节的实现与对应测试。1. 为什么需要集群级的视图构建协调器在 vnode虚拟节点模式下视图由节点本地的 view builder 各自构建而在 tablet表片模式下一个分片的所有权由(host_id, shard, tablet_id)三元组精确定位视图必须针对 tablet 副本逐段构建。为此ScyllaDB 引入了视图构建协调器它是整个集群中唯一的单一实体运行在 Raft leader 上与 topology coordinator拓扑协调器位于同一个 leader 节点上与 vnode 模式的节点本地视图构建形成对比tablet 模式的视图构建是中心调度 分布式执行的架构。从源码结构看协调器类view_building_coordinator定义于 db/view/view_building_coordinator.hh其构造参数直接绑定了raft::server、service::raft_group0group0、db::system_keyspace、gossiper、messaging service、视图构建状态机view_building_state_machine和拓扑状态机service::topology_state_machine印证了它骑在 Raft/group0 之上的定位。它同时实现了service::endpoint_lifecycle_subscriber通过on_up()在节点加入时触发状态机事件见 db/view/view_building_coordinator.cc以便在节点变更时重新评估任务。两个关键前提协调器状态持久化在 group0 表中并在 group0 状态被应用时加载进view_building_state_machine定义于 db/view/view_building_state.hh包含building_state、views_state与事件条件变量event当前协调器同一时刻最多只处理一张基表base table并为该基表构建其全部视图。当前正在处理的基表记录在system.scylla_local的view_building_processing_base键下由 group0 统一管理。2. 视图构建任务View building task整个视图构建过程被拆分为若干更小的视图构建任务。每个任务关联某个基表的特定 tablet 副本(host_id, shard, tablet_id)。2.1 两种任务类型build_range从基表的 tablet 副本生成视图更新用于构建视图process_staging处理生成视图更新并移入基目录所有与该 tablet 副本相关联的 staging sstable。对应地源码中的任务结构体为见 db/view/view_building_state.hhstruct view_building_task { enum class task_type { build_range, process_staging, }; utils::UUID id; task_type type; bool aborted; table_id base_id; std::optionaltable_id view_id; // nullopt when task_type is process_staging locator::tablet_replica replica; dht::token last_token; };原文档给出的结构体以locator::tablet_id tid标识 tablet在当前仓库源码中该字段演进为dht::token last_token即该任务负责处理到该 token 为止的区间view_building_state还专门提供collect_tasks_by_last_token()按 token 归并任务见 db/view/view_building_state.cc。这一演进使同一 tablet 上多个视图的任务能够按 token 边界批量执行且任务类型在表中的字符串取值由task_type_to_sstring()定义为BUILD_RANGE/PROCESS_STAGING见 db/view/view_building_state.cc。状态在内存中的组织是四层嵌套的映射building_tasks maptable_id(base), maplocator::tablet_replica, replica_tasks replica_tasks { maptable_id(view), mapUUID, task // 每个视图一份 mapUUID, task staging_tasks } // 基表整体一份见 db/view/view_building_state.hh2.2 任务何时被创建build_range任务创建视图/索引时tablet 操作过程中tablet 迁移migration/ 合并merge或分裂split/ keyspace RF 变更的结束阶段操作失败回滚过程中keyspace RF 被调大时process_staging任务有 staging sstable 被注册到view_building_worker时。3. 任务生命周期group0 持久化、批量清理与回滚状态存储范围group0 状态中只保存尚未完成、或已中止但尚未被清理的任务。任务创建后立即写入 group0 状态system.view_building_tasks表等待后续处理。之后协调器择机发送work_on_view_building_tasksRPC 给 worker 执行。只要任务未被中止worker 最终都会回复任务完成。协调器收到响应后先把完成的任务 id 暂存到内存再按200ms 间隔批量从 group0 状态中删除这些任务永久标记为完成——这种批量删除的目的是减少 group0 操作次数。对应源码finished_task_gc_fiber()在协调器主循环启动时随路启动内部task_gc_interval 200ms的循环反复调用clean_finished_tasks()见 db/view/view_building_coordinator.cc。clean_finished_tasks()的语义值得注意只有当任务仍存在于状态中且aborted false时才会被删除——如果任务在中途被 tablet 操作中止了则不能删除因为中止任务的信息还要用来派生新的调整任务或回滚任务见 db/view/view_building_coordinator.cc。任务的两种中止原因keyspace 或视图被 drop —— 此时直接删除相关任务无需保留tablet 操作 —— 此时先把任务的aborted标志置为true。之所以不直接删除是因为操作成功时需要任务信息来创建调整后的新任务操作失败时需要它来回滚。一旦aborted被置位就不可撤销所谓回滚任务实际是用新 ID 创建一份副本、再删除原任务。完成信息的丢失与幂等性从协调器得知任务完成RPC 响应到任务被真正标记完成之间存在时间窗。在此期间如果发生 Raft leader 切换协调器可能丢失这些信息。缓解机制是每个 view building worker在本地记录已完成任务的 id当新协调器携带同样的任务 id 再发 RPC 时worker 会立即回复这些任务已完成。最坏情况下协调器与 worker 节点都重启完成信息彻底丢失、工作会被重做——但视图构建任务天然是幂等的重做是安全的。原文档给出的任务状态机mermaid 图可概括为任务创建进入NORMAL协调器发送 RPC 后进入执行子状态worker 执行 → 本地保存完成记录随后要么收到响应而终结要么因 keyspace/视图 drop 直接删除终结tablet 操作则把任务转入ABORTED之后再以新建调整任务或以新 ID 回滚两种方式终结。4. Schema 与 tombstone 规避4.1system.view_building_tasks表最重要的表是system.view_building_tasks存储所有未完成的视图构建任务CREATE TABLE system.view_building_tasks ( key text, id timeuuid, min_task_id timeuuid STATIC, -- 任务扫描下界见Tombstone avoidance type text, aborted boolean, base_id uuid, view_id uuid, -- process_staging 任务为 NULL base_tablet_id bigint, host_id uuid, -- tablet 副本所在主机 shard int, -- tablet 副本所在 shard PRIMARY KEY (key, id) )整个表是单分区key恒为固定值。源码中mutation 由view_building_task_mutation_builder统一构造构造时即以data_value(view_building)作为分区键见 db/view/view_building_task_mutation_builder.hh。4.2 Tombstone avoidance范围墓碑 有界扫描单分区表有一个固有风险当finished_task_gc_fiber()批量删除已完成任务时被删行会以 tombstone 形式残留在 SSTable 中直到压缩在大集群上重新加载时会触发tombstone_warn_threshold告警。ScyllaDB 用两个机制解决机制一GC 时打范围墓碑range tombstone而非逐行墓碑。协调器不再为每条被删任务生成一个 row tombstone而是计算所有存活任务中最小的 timeuuidmin_alive_uuid然后发出一条[before_all, min_alive_uuid)的范围墓碑高于该边界的极少数任务仍逐个生成 row tombstone若所有任务都被删除则用一条覆盖整个分区的范围墓碑。源码实现对应view_building_task_mutation_builder::del_tasks_before()与del_all_tasks()见 db/view/view_building_task_mutation_builder.hhclean_finished_tasks()中正是遍历全部存活任务求出min_alive_uuid后调用这两者之一见 db/view/view_building_coordinator.cc。机制二重载时的有界扫描。物理行在压缩前仍然存在、仍计为 dead cell。为此每批 GC 之后min_task_id min_alive_uuid会作为静态列static cell原子写入与范围墓碑在同一条 Raft 批次中提交对应set_min_task_id()且受特性开关view_building_tasks_min_task_id保护见 db/view/view_building_coordinator.cc。重载时min_task_id用仅静态分片切片空_row_rangesalways_return_static_content读取——SSTable 读器在读完静态行后立即停止不会碰到任何 clustering tombstone因此计数的 dead cell 为零随后该值作为AND id min_task_id条件让主扫描跳过所有已被墓碑覆盖的行。配套的 ID 生成器也围绕单调递增设计task_uuid_generator每次调用返回比上一次时间戳严格多 1 微秒的 timeuuidview_building_state::make_task_uuid_generator()还会确保新 UUID 大于min_alive_uuid见 db/view/view_building_state.cc从而保证新任务总在扫描下界之上范围墓碑边界永不失效。4.3system.built_views视图构建完成后会在system.built_views建条目。该表过去是节点本地的引入协调器后它部分由 group0 管理tablet 型 keyspace 的条目由 group0 管理vnode 型 keyspace 的条目仍然是节点本地的。5. 对 tablet 操作的响应协调器必须响应三类 tablet 操作协调器类暴露的generate_tablet_migration_updates()、generate_tablet_resize_updates()、abort_tasks()、rollback_aborted_tasks()即对应入口见 db/view/view_building_coordinator.hhtablet 操作协调器动作tablet 迁移 /move_tabletREST API对每个满足base_id 操作表且replica 源副本且 tablet id 匹配的任务中止该任务并在目标副本上创建新任务tablet 分裂split对每个满足base_id 操作表的任务中止并创建新任务tablet id 映射n - (2n, 2n1)tablet 合并merge中止并创建新任务tablet id 映射n - n/2若该任务尚不存在keyspace RF 变更 /add_tablet_replica/del_tablet_replicaRF 降低中止被放弃副本上的任务RF 升高为新副本创建任务原文档标注此处可能依数据复制方式进一步优化统一原则所有情况下任务在操作开始时被中止新任务在操作结束时创建若操作失败则在回滚过程中创建被中止任务的副本。6. 视图构建 worker 与work_on_view_building_tasksRPC视图构建 worker 是节点本地服务负责执行视图构建任务处理下述 RPC、在任务完成后回复协调器并持续观察 group0 状态以感知任务被中止无论是被删除还是被置aborted标志。批处理语义worker 会把多个视图构建任务聚合成一个 batch且每个 shard 同时只能执行一个 batch保证同一 tablet 副本上每时刻只有一个批次是协调器的调度职责。只有满足以下全部条件的任务才能同批任务类型相同base_id相同tablet 副本相同tablet id 相同。源码中view_building_worker::batch的注释与文档一致并补充了两点细节批次内任意任务可被中止此时除非它是批次内最后一个存活任务否则批次不中断只从_tasks_ids移除该任务另外即使 RPC 连接断开例如 Raft leader 变更导致当前协调器被中止worker 上的工作会在后台继续新协调器可以 attach 到进行中的任务见 db/view/view_building_worker.hh。职责边界worker不把任务标记为完成不发起 group0 操作文档注明有一个例外。它只保存已完成任务的 id由协调器通过 RPC 询问任务结果。RPC 定义见 idl/view.idl.hhverb [[cancellable]] work_on_view_building_tasks(raft::term_t term, shard_id shard, std::vectorutils::UUID tasks_ids) - std::vectorutils::UUIDworker 注册的 handler 行为attach 到对应任务上并等待结果任务完成时返回结果。term参数用于让 worker 校验请求是否仍来自当前 Raft term 的协调器。7. Staging sstableprocess_staging任务与写入路径决策协调器还能处理 staging sstable这正是process_staging任务存在的意义在写入开始指向新副本之前不希望过早地基于 staging sstable 生成视图更新原文档引用了上游 issue #19149 描述该约束。实现上db::view::check_needs_view_update_path()的返回值由原先的布尔值升级为三态枚举sstable_destination_decision定义于 db/view/view_update_checks.hh函数实现于 db/view/view.ccenum class sstable_destination_decision { normal_directory, // 使用正常 sstable 目录 staging_directly_to_generator, // 使用 staging 目录并通知 view building worker staging_managed_by_vbc // 使用 staging 目录并注册到 view update generator };对 vnode 型 sstable函数行为与旧版一致对tablet 型sstable决策逻辑为该表是否有任何视图——无用正常目录所有视图是否都未开始或尚未构建——是用正常目录是否有视图已启动但未完成——是为该 sstable 创建视图构建任务所有视图均已构建完成流式复制streaming原因是 repair为该 sstable 创建视图构建任务否则用正常目录。worker 侧的闭环包括register_staging_sstable_tasks()注册 staging sstable、run_staging_sstables_registrator()定期把本地 staging sstable 转化为process_staging任务create_staging_sstable_tasks()需跨 shard 加锁见 db/view/view_building_worker.hh、以及在 tablet 迁移/cleanup 阶段通过load_sstables()与cleanup_staging_sstables()管理节点内 tablet 迁移携带过来的 staging 数据。8. 小结与延伸阅读视图构建协调器体现了 ScyllaDB 在 tablet 模式下把分布式状态收敛到 group0的工程思路任务定义、完成与中止全部持久化为 group0 表中的 mutation协调器可随 Raft leader 迁移无损接管worker 端则以幂等执行和本地完成记录兜底崩溃窗口。围绕本文主题可继续阅读的材料协调器主循环与 GC 实现db/view/view_building_coordinator.cc任务结构与状态机数据模型db/view/view_building_state.hh、db/view/view_building_state.cc任务 mutation 工厂范围墓碑、min_task_id静态列db/view/view_building_task_mutation_builder.hhworker 与批次执行db/view/view_building_worker.hh、db/view/view_building_worker.ccstaging 目录决策db/view/view.cc集群级测试test/cluster/test_view_building_coordinator.py、test/cluster/test_view_build_status.py【免费下载链接】scylladbNoSQL data store using the Seastar framework, compatible with Apache Cassandra and Amazon DynamoDB项目地址: https://gitcode.com/GitHub_Trending/sc/scylladb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表