一.n9e是什么

n9e的全称是Nightingale,与开发Open-falcon的是一拨人,起初这波人去了滴滴,开发了n9e成为滴滴开源的监控框架。

n9e在v5版本之前,连续了Open-falcon push的模式,在告警的业务逻辑和指标展示做了很多优化。

n9e在v5版本至今,应用prometheus作为后端的TSDB,并通过promQL作为告警表达式做告警断定。

本文次要关注最新的v5版本。

二.n9e的架构

  • server:后端服务,负责将指标写入Prometheus,以及告警业务逻辑的实现;
  • webapi:前端服务,负责前端业务逻辑;
  • mysql:保留告警策略,以及告警告诉配置;
  • redis:缓存用户登录信息;

指标的业务逻辑:

  1. 监控agent通过remote-write API,申请server;
  2. server对指标进行提取,存入Prometheus;

告警的业务逻辑:

  1. 用户通过webapi配置告警策略,server将策略保留至mysql;
  2. server依据告警周期,定期查问PromQL的值是否触发告警;
  3. 若触发告警,则将其存入mysql,同时进行告警告诉;

三.n9e的部署和应用

应用部署文档,部署单机版的n9e环境,次要部署以下组件:

  • prometheus
  • mysql
  • redis
  • n9e server & webapi

部署胜利后,n9e server监听在19000端口,webapi监听到18000端口;

通过http://ip:18000拜访WEB UI,默认用户:root/root.2020

四.prometheus作为后端TSDB

prometheus通常被用来拉取exporter的指标,而后存入本地磁盘;它既实现了拉取的逻辑,也实现TSDB的性能。

在2.25版本之前,prometheus不反对独自作为TSDB,即不反对通过API间接向prometheus写入时序数据。

在2.25版本之后,prometheus配置--enable-feature=remote-write-receiver参数后,反对通过REST接口向prometheus写入时序数据。

n9e应用prometheus 2.28版本,利用了prometheus这一个性,将其作为后端的TSDB。

prometheus提供的REST接口:POST /api/v1/write,能够向prometheus写入时序数据;
查看prometheus的源码:

// web/api/v1/api.gofunc (api *API) Register(r *route.Router) {    ...    r.Post("/write", api.ready(api.remoteWrite))    ......}func (api *API) remoteWrite(w http.ResponseWriter, r *http.Request) {    if api.remoteWriteHandler != nil {        api.remoteWriteHandler.ServeHTTP(w, r)    } else {    //未配置remote-write-receiver,返回谬误        http.Error(w, "remote write receiver needs to be enabled with --enable-feature=remote-write-receiver", http.StatusNotFound)    }}

五.telegraf作为监控agent并主动发现

Telegraf 是 InfluxData 开源的一款采集器,能够采集操作系统、各种中间件的监控指标等;

Telegraf是一个大一统的设计,即一个二进制能够采集CPU、内存、mysql、mongodb、redis、snmp等,不像Prometheus的exporter,每个监控对象一个exporter。

telegraf作为监控agent被部署到监控的指标主机上,同时配置telegraf,将其采集的指标输入到n9e server:

vi /opt/telegraf/telegraf.conf......[[outputs.opentsdb]]  host = "http://127.0.0.1"  port = 19000  http_batch_size = 50  http_path = "/opentsdb/put"  debug = false  separator = "_"

上述配置,telegraf采集的指标,通过http://127.0.01:19000/opentsd...发到n9e server,该配置中telegraf与n9e server部署在一台机器上。

n9e server实现了/opentsdb/put接口,相干的源码:

// src/server/router/router.gofunc configRoute(r *gin.Engine, version string) {    ...    r.POST("/opentsdb/put", handleOpenTSDB)    ...}func handleOpenTSDB(c *gin.Context) {    ...    bs, err = ioutil.ReadAll(c.Request.Body)    var arr []HTTPMetric    err = json.Unmarshal(bs, &arr)    for i := 0; i < len(arr); i++ {        pt, err := arr[i].ToProm()        host, has := arr[i].Tags["ident"]        // 有ident标签        if has {            // register host            ids[host] = ts        }        list = append(list, pt)    }    if len(list) > 0 {        if !writer.Writers.PushQueue(list) {    //将时序push到queu            msg = "writer queue full"        }        // 将host注册进去        idents.Idents.MSet(ids)    }    ...}

该API所做的事件:

  • 提供指标中的ident标签,其value作为新发现的host,被注册到已治理主机列表;
  • 将接管的指标push到本地的Queue,Queue中的数据前面被goroutine发送到prometheus;

六.grafana-agent作为监控agent并主动发现

grafana-agent能够拉取各种exporter的/metrics,并将其通过remote-write API写入n9e server。

grafana-agent还内置了罕用的exporter,比方node-exporter。

grafana-agent的配置文件:

# cat agent.yamlserver:  http_listen_port: 12345metrics:  wal_directory: /tmp/grafana-agent-wal  global:    scrape_interval: 15s    external_labels:      cluster: mycluster    remote_write:    - url: http://172.1.2.3:19000/api/v1/write    scrape_configs:    - job_name: "cadvisor"      static_configs:      - targets: ['192.168.1.2:19000']integrations:  agent:    enabled: true  node_exporter:    enabled: true

上述配置中:

  • grafana-agent集成了node_exporter;
  • grafana-agent拉取cadvisor工作的/metrics;
  • grafana-agent将采集的指标通过remote-write发送到n9e server;
  • n9e server接管到指标后,提取其中的instance label,其value作为新发现的host,增加到发现的主机列表中;

参考:

  1. 部署: https://n9e.github.io/quickst...
  2. prometheus remote-write-receiver: https://prometheus.io/docs/pr...
  3. grafana-agent docs: https://grafana.com/docs/graf...