ecFlow笔记:基于ecFlow构建后台服务监控系统

目录

本文介绍如何使用 ecFlow 定时检查后台程序运行情况,实现对 HPC 登录节点上后台服务的监控,并在程序退出时实现自动重启。

背景

前两年笔者开发的监控程序通常部署在 HPC 外的 Linux 服务器上,使用 SSH 协议或者 TCP 端口远程连接 HPC 获取监控数据。 但这类程序存在不少问题。

比如下面两个近期没有更新的项目:

nwpc-hpc-exporter

nwpc-oper/nwpc-hpc-exporter 项目为 Prometheus 提供 HPC 监控指标。 该项目运行在 Linux 服务器上,通过 SSH 协议使用账户名和密码远程连接到 HPC 执行命令行程序,定时获取 HPC 的运行状态。

保持与高性能计算的 SSH 长时间连接并不是百分之百可靠的。 所以,需要设置重新连接机制。

nwpc-ecflow-collector

nwpc-oper/nwpc-ecflow-collector 项目使用 ecFlow 的 Python API 获取系统的运行状态。

该项目在 NWPC 监控平台 (NWPC Monitor Platform, NMP) 中应用时,从 Linux 服务器远程连接 ecFlow 服务绑定的 TCP 端口,获取节点运行状态。

但 ecFlow 的 API 没有对数据进行压缩,对于挂载任务数比较多的服务(例如集合预报和产品后处理系统等),整个获取过程速度很慢。

为此,笔者开发 nwpc-oper/ecflow-client-cpp 项目,将 ecFlow 的采集程序放到高性能计算机的登陆节点上,使用 gRPC 向外提供服务。

详情请参看以下文章:

ecflow学习笔记:节点状态监控工具V2

但上述程序缺乏像 ecflow 程序一样稳定性,可能会因为不明原因退出。 笔者已对工具进行了优化,详情请参看以下文章:

ecFlow笔记:优化节点状态监控工具

但仍不能保证程序可以一直提供服务。 所以,需要类似 Supervisor 一样监视程序运行情况的机制。

NWPC 的核心业务系统都运行在 HPC 上,但只是 HPC 的普通用户,无法启动操作系统级的守护进程。

NWPC 使用 ecFlow 调度和监控数值天气预报业务系统。 根据多年使用经验,ecFlow 进程很少因为异常原因而退出,能一直保持运行。 所以,笔者使用 ecFlow 构建 HPC 登陆节点上后台服务的监控系统。

方案

监控系统定时启动任务,检查后台服务是否运行,如果没有找到后台服务,会重新启动后台服务。

下图是监控系统运行流程的示意图。

基于 ecFlow 的服务监控系统运行流程示意图

假设之前已在 time0 时刻启动后台服务 service,服务的日志写入 log.time0 文件中。

在 time1 时刻,ecFlow 服务运行作业 job1,检测到 service 已运行,作业 job1 运行结束。

假设某一时刻因某种原因,后台服务 service 异常结束。

在之后的 time2 时刻,ecFlow 服务运行作业 job2,检测到 service 没有运行,作业 job2 会重新运行后台服务 service,并让服务的日志写入新的 log.time2 文件中。

实现

后台运行程序

使用 nohup 命令实现将程序在当前节点的后台运行。

下面的代码在后台运行 nwpc_message_client 程序,并将标准输出和标准错误输出打印到同一个日志文件中。

nohup ${message_client_base}/bin/nwpc_message_client \
    broker \
    --address=${message_address} \
    >${message_broker_data}/log/log.${current_log_name} 2>&1 &

NWPC 的 ecFlow 服务运行在高性能计算机的登陆节点上,所以 ecFlow 运行的本地任务中启动的后台服务也同样运行在登录节点中。

检查进程

检测后台服务是否运行可以检查服务进程是否存在。

pgrep 会返回所有符合筛选条件的进程号,如果没有匹配的进程,退出码为 1。

pgrep -f "ecflow_watchman"
168710

如果后台服务同时只可能有 一个 程序在运行时,就可以使用 pgrep 实现进程检查的功能。

下面代码检查是否有包含 ecflow_watchman 的进程,如果不存在则重启,如果存在则忽略。

if ! pgrep -f "ecflow_watchman" &> /dev/null 2>&1; then
    echo "checking ecflow_watchman...failed"
    # restart program
else
    echo "checking ecflow_watchman...successful"
fi

如果单个节点中可能同时运行 多个 后台服务程序,则无法使用上述方法。

检查 TCP 端口

如果服务使用 TCP 端口,可以通过检查端口是否被占用判断后台服务是否运行。

lsof 可以列出打开的 TCP 端口。

下面的程序查找 33384 端口是否被占用,输出结果表明该端口已被占用。

lsof -i :33384 -sTCP:LISTEN
COMMAND      PID   USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
nwpc_mess 216353 nwp_pd    3u  IPv6 73939062      0t0  TCP *:33384 (LISTEN)

如果端口没有被占用,上述命令输出结果为空。

下面代码根据 lsof 返回结果的行数是否为 0 判断后台服务 nwpc_message_client broker 是否运行。

check_result=$(lsof -i :${message_port} -sTCP:LISTEN | wc -l)
if [ ${check_result} -eq 0 ]; then
    echo "checking nwpc_message_client...failed"
    # restarting nwpc_message_client...
else
    echo "checking nwpc_message_client...successful"
fi

这种方法适合同一节点上同时运行多个相同程序的情况。

定时检查

ecFlow 提供的 Cron 可以实现定时检查后台服务的功能。

NWPC 数值预报业务系统的 ecFlow 每天滚动循环。 整个系统所有任务都完成后,日期才会增加 1 天。

但 ecFlow 中设置 Cron 的任务永远不会完成,所以不能使用上述的日期滚动机制。 不过检查程序不依赖于具体时间,可以直接使用系统时间。

下面代码创建一个定时检查的任务,从 00:01 到 23:58 每 5 分钟运行一次。

with suite.add_family("message") as fm_message:
    with fm_message.add_task("check_broker") as tk_broker:
        cron = Cron("00:01 23:58 00:05")
        tk_broker.add_cron(cron)
        tk_broker.add_variable(common.sjob())
        tk_broker.add_variable(
            "ECF_SCRIPT_CMD", 
            "cat {ecf_files}/check_message_broker.ecf".format(
                ecf_files=self.suite_attrs['ECF_FILES']
            )
        )

日志

为了方便查看自动重启的情况,服务监控系统在每次启动程序时,将程序的输出重定向到一个新的日志文件中。

文件名包含启动程序的时间,例如:

current_log_name=${broker_user}.${broker_host}.${broker_port}.$(date "+%%Y-%%m-%%d.%%H-%%M-%%S")

nohup ${message_client_base}/bin/nwpc_message_client \
    broker \
    --address="[::]:${message_port}" \
    >${message_broker_data}/log/log.${current_log_name} 2>&1 &

生成的日志文件名类似

log.nwp_pd.login_b06.33384.2020-07-24.13-16-47

当然,这只是一种折衷方案。 服务的日志不应该只写入到一个文件中。 从文件名判断后台服务运行情况也不够精确。 后续笔者计划在重启服务时向 NWPC 消息平台发送一种通知消息,无需对日志的文件名进行约束。

运行情况

服务监控系统 (service_checker) 已在 NWPC 实时运行,处于评估阶段。

业务技术研发的不同阶段:

构建 -> 评估 -> 测试 -> 运行

系统的 ecFlow UI 截图如下所示:

服务监控系统 service_checker

监控的后台服务包括:

  • ecFlow 节点运行状态监控程序 (checker_watchman)
  • ecFlow 运行状态 gRPC 服务 (checker_grpc_server)
  • NWPC 消息平台 HPC 代理服务 (checker_broker)

从日志目录可以看到,除了 7 月份 HPC 用户目录迁移期间外,各个后台服务均稳定运行。 迁移目录期间因为找不到链接库而导致服务无法正常启动时,监控系统也能一直尝试重启。

总体来说,基于 ecFlow 构建的服务监控系统能满足业务需求,能有效保障后台服务的持续运行。

参考

ecflow学习笔记:节点状态监控工具V2

ecFlow笔记:优化节点状态监控工具

ecFlow 的 cron 文档:

https://confluence.ecmwf.int/display/ECFLOW/cron