首页
/ ScyllaDB Task Manager 深度指南:用 REST API 与 Nodetool 追踪、诊断和终止后台任务

ScyllaDB Task Manager 深度指南:用 REST API 与 Nodetool 追踪、诊断和终止后台任务

2026-09-14 15:29:38作者:盛欣凯Ernestine

导读

ScyllaDB 的 Task Manager 是一套统一的长时运行后台任务追踪框架:无论 compaction(压缩)、repair(修复)、还是 decommission / bootstrap / replace / rebuild 等节点运维操作,都被抽象为"任务"(task),以树状结构组织,并通过 REST API 与 nodetool 命令对外暴露。阅读完本文,你将掌握 Task Manager 的核心概念(模块、任务树、节点任务与集群任务、内部任务、TTL 生命周期),熟悉 task_stats / task_status 两种数据结构,能够熟练使用 /task_manager/* 系列 REST 端点查询任务状态、等待任务完成、中止可中止任务并调整 TTL,还能通过 nodetool tasks 系列命令把同步操作转成可异步追踪的版本。


一、Task Manager 是什么:模块与任务树

Task Manager 追踪 ScyllaDB 中的长时运行后台操作。它被划分为若干模块(module),每个模块负责追踪一类用途相近的操作(例如 compaction)。操作及其组成部分用任务表示:

  • 任务形成一棵:根任务(root task)覆盖整个操作(如一次 compaction),其子任务覆盖子操作(如单个表的 compaction),以此类推。

从源码结构看,任务树的父子关系由 tasks/task_manager.hh 中的 children 类承载:_children 保存仍在运行的子任务(foreign_task_map),_finished_children 保存已结束子任务的摘要(task_essentials),并用 rwlock 保护并发访问;父任务的进度由 get_progress() 递归聚合所有子任务的进度得出(tasks/task_manager.cc 第 69-85 行)。

模块的注册与查找由 task_manager::make_module() / find_module() 实现(tasks/task_manager.cc 第 721-733 行),每个模块维护自己的本地任务表 _local_tasks 和虚拟任务表 _virtual_tasks。从 compaction/task_manager_module.cc 可以看到 compaction 模块用 make_and_start_task<..._task_impl>(parent_info, ...) 创建并立即启动任务——父任务信息(parent_info)会决定新任务挂在任务树的哪个位置,并继承父任务的 sequence number(tasks/task_manager.cc 第 617-642 行的 make_task)。

任务类型:node 与 cluster

任务分为两类:

  • Node 任务:只在单个节点上执行的操作。查看其统计信息时,需要向特定节点请求状态。
  • Cluster 任务:横跨多个节点的操作,从集群中所有节点上都可见。

两类任务的重要规则:

  • Cluster 任务不能有父任务(即不能成为任务树中的子节点);
  • Cluster 任务可以在多个节点上拥有子任务;
  • 即使集群操作仍在运行,某个 cluster 任务的子任务状态也可能暂时无法访问(例如子任务所在的节点与当前查询节点通信受限时)。

在代码层面,任务种类由 tasks/task_manager.hh 中的 enum class task_kind { cluster, node } 表示;cluster 任务通常以"虚拟任务(virtual_task)"的形式实现——例如 node_ops 模块的虚拟任务通过 RPC(ser::tasks_rpc_verbs::send_tasks_get_children)向集群各节点收集子任务(tasks/task_manager.cc 第 399-433 行)。

内部任务(internal task)

任务可能是内部任务,意味着:

  • 它有父任务,或
  • 由某个内部进程启动。

默认情况下,API 调用会跳过内部任务(只有显式传入 internal=true 参数时才列出)。Cluster 任务不能是内部任务。

内部任务的特殊生命周期:

  • 结束后立即从 task manager 注销;
  • 如果它有非 cluster 的父任务,其状态会被折叠(fold)进父任务,只能通过父任务访问;
  • 已结束任务的间接后代(如子任务的子任务)的状态不可见,除非它们失败了——失败子任务会保留下来以便诊断。

折叠逻辑见 tasks/task_manager.cc 第 225-245 行的 maybe_fold_into_parent():当任务是内部任务、父任务为本节点任务且所有子任务均结束时,会把自身的 task_essentials(含状态、进度、失败子任务链)合并进父任务,然后注销。get_failed_children()(第 186-195 行)则递归收集失败的子任务,保证"失败信息不丢失"。


二、任务的 TTL 与保留时间

非内部、非 cluster 的任务在结束后会在 task manager 中保留一段时间:

  • 内部启动的任务保留 task_ttl 秒;
  • 用户启动的任务保留 user_task_ttl 秒;
  • Cluster 任务在 task manager 中的可见时长未作规定

task_ttl 的取值方式有两种:

  1. 通过配置参数 task_ttl_in_seconds
  2. 通过 REST API /task_manager/ttl

user_task_ttl 对应 user_task_ttl_in_seconds 参数与 /task_manager/user_ttl API。

默认值与动态更新:在 db/config.cc 中定义:

  • task_ttl_in_seconds:默认 0liveness::LiveUpdate,支持热更新),注释为"内部启动的已结束任务信息在内存中保留的时间";
  • user_task_ttl_in_seconds:默认 3600 秒(1 小时),同样支持热更新。

从实现看,task manager 构造函数用这两个配置值初始化 _task_ttl / _user_task_ttltasks/task_manager.cc 第 644-653 行);而任务结束后的注销时机在 task::start() 中处理(第 310-337 行):任务完成后,会 sleep_abortable(user_task ? user_task_ttl : task_ttl) 等待 TTL 到期再调用 unregister_task 注销任务——用户任务默认保留 1 小时,内部任务默认(TTL=0)完成后立即注销。

TTL 的运行时更新通过 api/task_manager.cc 第 218-246 行实现:cfg.task_ttl_seconds.set_value_on_all_shards(ttl, config_source::API) 将新值同步到所有 shard,实现无重启生效。


三、Task Manager REST API 详解

Task Manager 提供一组 REST 端点,Swagger 规范见 api/api-doc/task_manager.json,实现见 api/task_manager.cc。先介绍返回的数据结构,再逐一讲解端点。

3.1 数据结构

API 返回的任务数据存放在两种结构中:task_statstask_status

task_stats(轻量统计)

字段定义于 tasks/types.hhtask_stats

字段 说明
task_id 唯一任务 ID(UUID)
type 任务类型,如 offstrategy compaction
kind 任务种类:per node(节点级)或 cluster(集群级)
scope 操作范围,如 keyspace、range
state 任务状态之一:createdrunningdonefailed
sequence_number 操作序号(按模块递增),同一棵树中的所有任务共享;对 cluster 任务无意义
keyspace 可选,任务作用的 keyspace 名称
table 可选,任务作用的表名称
entity 可选,任务相关的附加信息
shard 可选,任务作用的 shard ID
start_time 仅当 state != created 时有意义
end_time 仅当任务已结束(statedonefailed)时有意义

注意:任务状态枚举在源码中实际上还有第五个取值 suspendedtasks/task_manager.hh 第 105-111 行 enum class task_state),Swagger 规范同样列出 created / running / done / failed / suspended 五种,文档正文列出的四种是 API 常用状态。

task_status(完整状态)

包含 task_stats 的全部字段,并额外增加:

字段 说明
is_abortable 该任务是否可通过 API 中止
error 仅当任务失败时有意义,存放错误信息
parent_id 仅当任务有父任务时有意义
progress_units 进度单位描述
progress_total 以 progress_units 计的总工作量
progress_completed 以 progress_units 计的当前完成量
children_ids 子任务 ID 及所在节点的配对列表

task_status 的 JSON 序列化在 api/task_manager.cc 第 38-73 行 make_status() 中完成:子任务列表会通过 gossiper 的地址映射把 host_id 翻译成节点地址(ident.node),parent_id 为空时输出字符串 "none"。进度数据(progress_total / progress_completed)来自 tasks/task_manager.hh 中的 task::progress 结构(completed / total 两个 double 值)。

3.2 API 端点速查

端点 方法 说明
/task_manager/list_modules GET 列出 task manager 支持的所有模块
/task_manager/list_module_tasks/{module} GET 列出某模块下的任务
/task_manager/task_status/{task_id} GET 获取单个任务的状态
/task_manager/abort_task/{task_id} POST 中止任务(不可中止时返回 403)
/task_manager/wait_task/{task_id} GET 等待任务结束并返回其状态
/task_manager/task_status_recursive/{task_id} GET 以 BFS 顺序返回该任务及其所有后代的状态
/task_manager/ttl GET/POST 读取或设置新的 task ttl
/task_manager/user_ttl GET/POST 读取或设置新的 user ttl
/task_manager/drain/{module} POST 注销模块内所有已结束的本地任务

注意:cluster 任务不会通过 API 调用从 task manager 注销(其生命周期由集群拓扑状态机管理)。

下面逐个说明关键端点的参数与行为。

/task_manager/list_modules

无参数,返回模块名称数组。实现上直接取 tm.local().get_modules() 的所有 key(api/task_manager.cc 第 93-96 行)。

/task_manager/list_module_tasks/{module}

查询参数:

  • internal:布尔值,设为 true 时列出内部任务,默认 false
  • keyspace:若设置,仅返回作用于该 keyspace 的任务;
  • table:若设置,仅返回作用于该表的任务。

对应实现(第 98-148 行):先通过 find_module(module) 找到模块(模块不存在时抛出 bad_param_exception),再调用 module->get_stats(internal, filter) 聚合所有 shard 上的任务;过滤逻辑同时匹配 keyspace 与 table。注意 tasks/task_manager.cc 第 543-575 行 get_stats 的实现细节:内部任务默认被跳过,且模块的虚拟任务(如 node_ops、repair 的集群级任务)只在 shard 0 上聚合。

/task_manager/task_status/{task_id}

路径参数 task_id 为任务 UUID。任务不存在时返回参数错误(bad_param_exception)。实现经由 task_handler::get_status()(见 tasks/task_handler.hh 中的 task_handler 类)完成。

/task_manager/abort_task/{task_id}

POST 中止任务。若任务不可中止,返回 403 Forbiddenapi/task_manager.cc 第 162-173 行捕获 tasks::task_not_abortable 并映射为 http::reply::status_type::forbidden)。中止是可递归的:task::impl::abort()tasks/task_manager.cc 第 170-176 行)在请求自身 abort source 后,会调用 abort_children()所有 shard 上查找并中止所有直接子任务(第 151-168 行),形成级联中止。

/task_manager/wait_task/{task_id}

等待任务完成并返回其最终状态。查询参数:

  • timeout:等待超时秒数;若设置了且等待超时,返回 408 Request Timeout

实现(第 175-191 行):未设置 timeout 时无限等待;超时异常 timed_out_error 被映射为 408。源码中 task::impl::done() 通过 shared_promise<> _done 的 future 让调用方等待任务终结(tasks/task_manager.hh 第 212-214 行)。

/task_manager/task_status_recursive/{task_id}

BFS 顺序返回任务本身及所有后代(含跨节点子任务)的状态数组。实现调用 task_handler::get_status_recursively(true)api/task_manager.cc 第 193-216 行),输出流式 JSON 数组。对于 cluster 虚拟任务,后代收集会通过 RPC 向集群中相关节点递归查询(见 tasks/task_manager.cc 第 403-433 行)。

/task_manager/ttl/task_manager/user_ttl

  • GET:返回当前 TTL 值;
  • POST:设置新 TTL(分别通过查询参数 ttl / user_ttl 传入秒数),并返回旧值

两个端点都调用 cfg.task_ttl_seconds / cfg.user_task_ttl_secondsset_value_on_all_shards() 将新值广播到所有 shard(api/task_manager.cc 第 218-246 行)。POST 成功即表示新 TTL 已全局生效,无需重启节点。

/task_manager/drain/{module}

POST 注销指定模块内所有已结束的本地任务is_complete() 为 true 的任务),相当于手动清理内存中的历史记录;对仍在运行的任务无影响。实现见第 248-272 行:在 invoke_on_all 中遍历模块本地任务表,只注销 done / failed 状态的任务,并 maybe_yield() 避免阻塞事件循环。该端点不作用于 cluster 任务。


四、node_ops 模块:追踪节点运维操作

Task Manager 中有一个名为 node_ops 的模块,专门追踪节点级运维操作:

  • decommission(节点下线)
  • removenode(移除节点)
  • bootstrap(节点引导/加入集群)
  • replace(替换节点)
  • rebuild(重建数据)

关于该模块的关键行为:

  • type 字段标识具体操作,取值为 decommissionremove nodebootstrapreplacerebuild 之一;
  • scopekind 字段均设置为 cluster(即 node_ops 任务是集群级任务);
  • entity 字段在操作未结束前保存被操作节点的 host id;对 replace 操作,保存的是替换节点的 host id;
  • decommissionremove node 任务是可中止的,但仅限在它们完成 tablet 迁移之前

源码印证(node_ops/task_manager_module.cc):

  • request_type_to_task_type()(第 24-45 行)把拓扑请求映射为任务类型:join → "bootstrap"remove → "remove node"leave → "decommission"
  • get_task_stats()(第 63-79 行)明确把 kind 置为 task_kind::clusterscope 置为 "cluster",并把 entity 设为 hint 中的 node_id;
  • is_abortable()(第 148-150 行)返回 is_abortable(hint.node_id.has_value())——即只有携带了明确节点标识(尚未完成 tablet 迁移)的请求才可中止,与文档描述一致。

node_ops 以虚拟任务(virtual_task)形式实现:它不把任务常驻在单节点内存中,而是每次查询时从系统 keyspace 的拓扑请求记录(system_keyspace::topology_requests_entry)动态还原任务状态(第 47-57 行的 get_state()),从而保证集群内所有节点都能看到同一份 cluster 任务视图。这也解释了为什么"cluster 任务不会被 API 注销"——它们的生命周期与集群拓扑状态机绑定,而非单节点内存。


五、Tasks API:把同步命令变成异步任务

借助 task manager,ScyllaDB 还提供了同步调用的异步版本,其中一部分通过 nodetool tasks 命令暴露。这些调用与对应的同步版本工作方式类似,区别在于:它们不等待操作完成,而是立即返回关联任务的 ID;之后你可以用 task manager API 查询该操作的状态、进度,甚至中止它。

相关的 nodetool 子命令文档位于 docs/operating-scylla/nodetool-commands/tasks/index.rst,包含:

  • nodetool tasks list —— 列出任务(对应 /task_manager/list_module_tasks/{module});
  • nodetool tasks status —— 查看任务状态(对应 /task_manager/task_status/{task_id});
  • nodetool tasks wait —— 等待任务完成(对应 /task_manager/wait_task/{task_id});
  • nodetool tasks tree —— 查看任务及其后代状态(对应 /task_manager/task_status_recursive/{task_id});
  • nodetool tasks abort —— 中止任务(对应 /task_manager/abort_task/{task_id});
  • nodetool tasks drain —— 清理已结束任务(对应 /task_manager/drain/{module});
  • nodetool tasks modules —— 列出模块(对应 /task_manager/list_modules);
  • nodetool tasks ttl / nodetool tasks user-ttl —— 读写 TTL(对应 /task_manager/ttl / /task_manager/user_ttl)。

使用建议:对耗时长、适合后台化的操作(例如大规模 compaction、repair、节点运维),优先使用这些异步命令拿到 task_id,再配合 nodetool tasks status / tree 观察进度,必要时用 abort 中止——避免长时间阻塞客户端连接。如果希望直接以 JSON 方式与 Task Manager 交互,可参考 REST API 的使用方式(见 docs/operating-scylla/rest.rst 对 REST API 的整体介绍)。


六、一次完整的排查实践

综合上述内容,一个典型的长任务追踪流程如下:

  1. 列出模块,确认要查询的功能模块名:

    curl -X GET http://<node>:10000/task_manager/list_modules
    
  2. 列出任务(默认不含内部任务):

    # 列出 compaction 模块全部任务
    curl -X GET "http://<node>:10000/task_manager/list_module_tasks/compaction"
    # 过滤指定 keyspace/table,并包含内部任务
    curl -X GET "http://<node>:10000/task_manager/list_module_tasks/compaction?keyspace=ks1&table=t1&internal=true"
    
  3. 查看任务完整状态与进度

    curl -X GET "http://<node>:10000/task_manager/task_status/<task_id>"
    
  4. 递归查看任务树(含所有跨节点后代,BFS 顺序):

    curl -X GET "http://<node>:10000/task_manager/task_status_recursive/<task_id>"
    
  5. 等待任务结束(可带超时,超时返回 408):

    curl -X GET "http://<node>:10000/task_manager/wait_task/<task_id>?timeout=60"
    
  6. 中止任务(仅当 is_abortable=true,否则 403):

    curl -X POST "http://<node>:10000/task_manager/abort_task/<task_id>"
    
  7. 调整保留时长并清理历史:

    # 用户任务保留 2 小时
    curl -X POST "http://<node>:10000/task_manager/user_ttl?user_ttl=7200"
    # 立即清理 compaction 模块所有已结束任务
    curl -X POST "http://<node>:10000/task_manager/drain/compaction"
    

需要注意的边界行为(来自文档与源码双重确认):

  • 默认 API 响应不含内部任务,需要显式传 internal=true
  • 已结束的内部任务状态会被折叠进父任务,间接后代只有失败时才可见;
  • cluster 任务(如 node_ops)不会被 drain 或 TTL 机制注销,其可见时长未作规定;
  • abort 是递归的:中止父任务会级联中止所有后代,但只有 is_abortable 为 true 的任务才允许发起。

总结

Task Manager 是 ScyllaDB 运维体系的中枢神经系统:它以"模块 + 任务树"的模型统一了 compaction、repair、节点运维等所有长时后台操作的可观测性与控制面。通过 task_stats / task_status 两种数据结构,配合 /task_manager/* REST 端点与 nodetool tasks 命令,运维人员可以精确地查看任务进度、等待完成、中止失控操作,并按需调整任务保留时长——而这一切背后,是 tasks/task_manager.cc 中任务注册/注销、子任务折叠、跨节点 RPC 收集与递归中止等机制的精密协作。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
34
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.21 K
2.81 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
945
1.86 K
docsdocs
暂无描述
Markdown
906
5.84 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
537
607
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
864
1.36 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
4.28 K
1.03 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.39 K
1.48 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
550
401
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.19 K
347