ecFlow笔记:获取任务节点数
每天运行的任务数量是衡量系统规模的关键指标。
ecFlow UI 界面中可以设置显示 Server 或 Suite 节点的子节点个数,如下图所示。
但显示的节点个数包括 Family 等所有节点类型,而我们通常关心的仅仅是会实际提交任务的 Task 节点。
本文介绍如何使用 ecFlow 的 Python API 获取 Task 节点个数。
基本方法
ecFlow API 中的 ecflow.Defs
对象提供 get_all_tasks()
函数,返回 ecFlow 服务中所有的任务节点个数。
import ecflow
client = ecflow.Client(host, port)
client.sync_local()
defs = client.get_defs()
print(len(defs.get_all_tasks()))
81674
返回的任务节点数(81674)比界面中的子节点数(83992)略少。
进一步
上述方法返回的服务中所有 suite 的任务节点数。
从上面的图中可以看到,ecFlow 服务中可能会有处于挂起状态(suspended)的系统。
这些系统不会提交任务,但也会被 get_all_tasks()
函数计入到返回结果中。
注:笔者不建议在业务级别的 ecFlow 服务中保留挂起状态的历史系统。
如果想要获取实际运行的任务节点个数,需要采用另外的方法。
首先,获取 ecFlow 服务的所有节点运行状态,即 ecflow.Defs
对象。
client = ecflow.Client(args.host, args.port)
client.sync_local()
defs = client.get_defs()
然后遍历 defs
的所有 suite。
- 如果 suite 处于挂起状态,则直接跳过;
- 如果 suite 处于其它状态,则检查 suite 中的所有子节点。如果节点是任务节点(
ecflow.Task
),则任务节点数(task_count
)加 1。
for suite in defs.suites:
if suite.get_dstate() == ecflow.DState.suspended:
print(suite.get_abs_node_path(), ": ignored")
continue
nodes = suite.get_all_nodes()
task_count = 0
for node in nodes:
if isinstance(node, ecflow.Task):
task_count += 1
print(suite.get_abs_node_path(), ": ", task_count)
/grapes_geps_v2_2 : 27797
/grapes_reps_v3_4 : 13041
/grapes_reps_v3_3 : ignored
/grapes_geps_v2_1 : ignored
有效系统的节点个数相加和为 40838,约等于上一节节点数的一半。
思考
统计 NWPC 所有业务 ecFlow 服务的任务节点数为 104133,其中一半任务由产品后处理系统提交。
当前产品后处理和集合预报的 ecFlow 服务在业务高峰期已出现明显的 UI 界面通讯延迟现象,而任务节点数偏少的确定性模式 ecFlow 服务的延迟现象则不是很明显。
我们正在寻找可行的方法来解决这一问题。 但无论采用何种方案,都需要面临任务颗粒度的问题:
- 为了降低系统的负载,作业数越少越好,尽可能将任务合并到单一的作业中
- 为了增加系统灵活性和可维护性,任务分拆得越细越好,尽可能为每个任务都生成一个作业
从业务系统开发和维护角度来看,笔者倾向于分拆任务,方便维护的系统才能真正提高工作效率。 至于任务数量爆发式增长给 HPC 带来的额外负担,可以通过限制同时运行的作业数等方式进行平衡。
但我们尚未找到合适的方式,后续可能会有其它变更。 或许明年我们将产品后处理系统迁移到气象大数据云平台上,就不会再遇到类似的问题。