深入拆解Nightingale_alert上(二)

概述

这篇打算从夜莺的alert告警引擎这个大的模块开始,逐步揭秘,告警的相关流程和组成,以及最关键的Nightingale如何生成告警如何实现,之前博客简单了解过其中关于,多实例组成集群方式如何均分告警,听介绍是用到一致性哈希——一致性哈希(哈希环)解决数据分布问题,本文参考的结构是V6版本(main分支,Version: v6.0.0-da9f5fbb12ce2c291448e3d9a7c5282c911463f4)。

目录介绍

tree -LF 3 .
./
├── aconf/  //告警配置
│   └── conf.go
├── alert.go //告警初始化入口
├── astats/ //统计信息
│   └── stats.go
├── common/ //通用方法或结构体
│   ├── conv.go //转换成异常点结构体
│   └── key.go //规则key序列化和标签判断
├── dispatch/ //发送告警
│   ├── consume.go //消费者
│   ├── dispatch.go //生产者
│   ├── log.go //日志记录
│   ├── notify_channel.go //通知通道的map
│   └── notify_target.go //通知目标结构体,维护发送目标
├── eval/ //评估
│   ├── alert_rule.go //告警调度
│   └── eval.go //查询时序库评估告警,查询promql
├── mute/ //屏蔽
│   └── mute.go //告警屏蔽
├── naming/ //告警命名
│   ├── hashring.go //数据源对应哈希环
│   └── heartbeat.go //告警心跳维护
├── process/ //告警处理
│   ├── alert_cur_event.go //告警发生的事件的map
│   └── process.go //告警处理
├── queue/ //告警队列
│   └── queue.go //Gauge类型的告警队列
├── record/ //记录规则
│   ├── prom_rule.go //将记录规则写入时序库
│   ├── sample.go //样本,转换记录用
│   └── scheduler.go //记录规则调度
├── router/ //告警路由
│   ├── router.go //告警路由
│   └── router_event.go //告警事件路由
└── sender/ //告警通知发送渠道
    ├── callback.go //回调
    ├── dingtalk.go //钉钉
    ├── email.go //邮件
    ├── feishu.go //飞书
    ├── mm.go //mm
    ├── plugin.go //脚本
    ├── plugin_cmd_unix.go //linux脚本
    ├── plugin_cmd_windows.go //window脚本
    ├── sender.go //发送通知
    ├── telegram.go //telegram
    ├── webhook.go //webhook
    └── wecom.go //企业微信

13 directories, 35 files

初步分析

从目录结构我们通过配置,统计,发送,评估,屏蔽,命名,处理,队列,记录规则,路由,通知渠道等构成了完整的告警引擎模块。
它的入口函数在同名的alert.go,只有两个函数Initialize(configDir string, cryptoKey string) (func(), error)Start(alertc aconf.Alert, pushgwc pconf.Pushgw, ...lots of arg... isCenter bool) ,打包的n9e程序通过Start函数接入告警引擎,n9e-alert通过Initialize函数完成一些配置工作,然后也是调用Start函数来实现调用。

其中n9e-alert程序有三个参数,其中configs和crypto-key是Initialize函数需要的参数。

  • configs 配置文件路径,优先读取环境变量中N9E_CONFIGS的值没有设置为默认值etc,
  • crypto-key 加密密钥,默认’’
  • version 是否输出版本,默认false,如果是true,打印在输出到控制台上后立即结束程序
./n9e-alert --help                                        

Usage of ./n9e-alert:
  -configs string
    	Specify configuration directory.(env:N9E_CONFIGS) (default "etc")
  -crypto-key string
    	Specify the secret key for configuration file field encryption.
  -version
    	Show version.

接下来我们看看Initialize的代码如何实现

func Initialize(configDir string, cryptoKey string) (func(), error) {
	config, err := conf.InitConfig(configDir, cryptoKey) //通过从配置文件路径和密钥,读取配置文件
	if err != nil {
		return nil, fmt.Errorf("failed to init config: %v", err)
	}

	logxClean, err := logx.Init(config.Log)
    //logxClean 为了性能使用bufio,bufferSize为256kB。log库会自己定期Flush到文件。在主程序退出之前需要调用dlog.Close(),否则可能会丢失部分log。
	if err != nil {
		return nil, err
	}

	db, err := storage.New(config.DB)//连接数据库,底层用的gorm
	if err != nil {
		return nil, err
	}
	ctx := ctx.NewContext(context.Background(), db)

	redis, err := storage.NewRedis(config.Redis)//连接redis
	if err != nil {
		return nil, err
	}

	syncStats := memsto.NewSyncStats()//同步状态监控指标,类型是Gauge
	alertStats := astats.NewSyncStats()//告警的各种监控指标

    //设置各种Cache
	targetCache := memsto.NewTargetCache(ctx, syncStats, redis)
	busiGroupCache := memsto.NewBusiGroupCache(ctx, syncStats)
	alertMuteCache := memsto.NewAlertMuteCache(ctx, syncStats)
	alertRuleCache := memsto.NewAlertRuleCache(ctx, syncStats)
	notifyConfigCache := memsto.NewNotifyConfigCache(ctx)
	dsCache := memsto.NewDatasourceCache(ctx, syncStats)

	promClients := prom.NewPromClient(ctx, config.Alert.Heartbeat)//创建prom查询客户端

	externalProcessors := process.NewExternalProcessors()//创建告警对象处理器

	Start(config.Alert, config.Pushgw, syncStats, alertStats, externalProcessors, targetCache, busiGroupCache, alertMuteCache, alertRuleCache, notifyConfigCache, dsCache, ctx, promClients, false)//启动告警

	r := httpx.GinEngine(config.Global.RunMode, config.HTTP)//使用gin框架启动http服务
	rt := router.New(config.HTTP, config.Alert, alertMuteCache, targetCache, busiGroupCache, alertStats, ctx, externalProcessors)
	rt.Config(r)

	httpClean := httpx.Init(config.HTTP, r)//http清理

	return func() {
		logxClean()
		httpClean()
	}, nil
}

配置文件可支持 toml, json, yaml三种类型;
由于告警配置Alert.Heartbeat中IP属性建议设置一个唯一值,配置文件没有填写会自动填充,其逻辑如下:

  1. 首先通过AliDNS获取本机ip
  2. 没有获取到有效值会尝试获取hostname,获取失败会直接退出程序
  3. 获取hostname中包含localhost会打印一个提示建议用一个唯一值
  4. 在填充完 config.Alert.Heartbeat.IP 后会再根据配置文件HTTP.Port的配置(17000)组合一起设置 config.Alert.Heartbeat.Endpoint 属性

配置文件中属性存在前缀{{cipher}},则代表是加密过的属性,需根据公钥解密,使用BASE64和AES解密。

logx底层是logger使用的是 pkg 的logger,通过readme看到更多详细解释,日志保存在文件是可以按照不同日志等级,设置保存时间(循环写一个文件),或者自动切分日志。

redis可支持单机模式,哨兵模式,cluster集群,不过我了解到redis集群除了上面两种集群方式应该还有个主从模式,不过我想这里应该不会去写redis,只是读如果是主从,应该是同单机模式即可。

syncStats是两个用于监控同步状态的Exporter,duration和sync_number,duration是定时任务使用时长,sync_number是定时任务同步数量。
alertStats是6个用于监控告警状态的Exporter

  • samples_received_total 从各个接收接口接收到的监控数据总量
  • alerts_total 产生的告警总量
  • alert_queue_size 内存中的告警事件队列的长度
  • sample_queue_size 数据转发队列,各个队列的长度
  • http_request_duration_seconds 一些重要的请求,比如接收数据的请求,应该统计一下延迟情况
  • forward_duration_seconds 发往后端TSDB,延迟如何

这篇只是一起看了下告警入口的初始化函数,代码中添加了一些注释,后续我们下篇继续。

参考资料

log for golang

redis三种集群模式–主从、哨兵、cluster集群的区别

为go应用添加prometheus监控指标

码一个完整的prometheus exporter!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值