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 {}
}
参考
完整代码请访问: