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

目录

警告:本文介绍的工具有严重的内存泄漏问题,请浏览《ecflow学习笔记:节点状态监控工具V2》,使用 c++ 版的 ecflow-watchman。

前面的文章介绍了如何构建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 servergoroutine for one ecflow serverload configload configcreate timercreate timerinfinite loopinfinite loopcreate goroutinesfor each itemcreate goroutines<br>for each itemclock tickclock tickcollect statuscollect 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