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

目录

前面的文章介绍了如何构建ecflow的GO语言客户端。本文介绍使用使用该客户端开发节点状态监控工具。

背景

在NWPC业务系统监控项目(NWPC Monitor Platform,NMP)中,使用celery定时收集业务系统运行状态。

采集程序是使用Python API构建的ecflow客户端(nwpc-oper/nwpc-ecflow-collector),部署在HPC的登录节点,NMP通过grpc远程调用采集程序。

虽然今年上半年更新的本地采集方式有效地解决ecflow API的延时问题,但还有一些问题。

监控ecflow服务最基本的操作就是获取所有节点的运行状态,但过多使用API查询ecflow服务状态会对整个服务带来繁重的负载,极端情况下会影响整个服务的稳定运行。 所以,如果后续需要进一步增加监控工具,就需要改变现有的数据获取方式,仅用运行一个采集程序,服务所有的后端程序。

perillaroc/ecflow-watchman是为实现上述想法而开发的ecflow节点状态监控工具。

该工具在一个进程中定时获取需要的ecflow服务状态,并将状态保存到redis中。 后续程序只需定时从redis中读取ecflow的状态,无需调用ecflow API重新获取节点状态。

架构

goroutine for one ecflow server
goroutine for one ecflow server
load config
load config
create timer
create timer
infinite loop
infinite loop
create goroutines
for each item
create goroutines<br>for each item
clock tick
clock tick
collect status
collect status

实现

使用ecflow-client-go获取节点状态列表。

func GetEcflowStatus(config EcflowServerConfig, redisUrl string) {
	client := ecflow_client.CreateEcflowClient(config.Host, config.Port)
	client.SetConnectTimeout(config.ConnectTimeout)
	defer client.Close()

	client.Sync()

	records := client.StatusRecords()

	ecflowServerStatus := EcflowServerStatus{
		StatusRecords: records,
		CollectedTime: client.CollectedTime,
	}

	StoreToRedis(config, ecflowServerStatus, redisUrl)
}

保存节点状态列表到redis中。

func StoreToRedis(config EcflowServerConfig, ecflowServerStatus EcflowServerStatus, redisUrl string) {
	b, _ := json.Marshal(ecflowServerStatus)
	key := config.Owner + "/" + config.Repo + "/status"

	redisClient := redis.NewClient(&redis.Options{
		Addr:     redisUrl,
		Password: "",
		DB:       0,
	})
	defer redisClient.Close()

	redisClient.Set(key, b, 0)
}

主程序中,根据提供的ecflow服务列表创建相应的goroutine。 每个goroutine使用time.Tick创建定时器,定时获取ecflow状态。 主程序使用select {}实现无限循环。

func main(){
	for _, job := range config.ScrapeConfigs {
		go func(job ScrapeJob, redisUrl string, scrapeInterval time.Duration) {
			c := time.Tick(scrapeInterval)
			for _ = range c {
				ecflow_watchman.GetEcflowStatus(job.EcflowServerConfig, redisUrl)
			}
		}(job, redisUrl, scrapeInterval)
		log.Info("new job loaded: ", job.Owner, "/", job.Repo)
	}

	// block forever in the main goroutine
	// see: https://blog.sgmansfield.com/2016/06/how-to-block-forever-in-go/
	select {}
}

参考

完整代码请访问:

perillroc/ecflow-watchman