ecFlow笔记:获取任务节点数

目录

每天运行的任务数量是衡量系统规模的关键指标。

ecFlow UI 界面中可以设置显示 Server 或 Suite 节点的子节点个数,如下图所示。

nwpc_qu_eps 服务,包含全球和区域集合预报系统

但显示的节点个数包括 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 带来的额外负担,可以通过限制同时运行的作业数等方式进行平衡。

但我们尚未找到合适的方式,后续可能会有其它变更。 或许明年我们将产品后处理系统迁移到气象大数据云平台上,就不会再遇到类似的问题。

参考

ecFlow python API