0.前言
之前我们部署了夜莺,并且通过夜莺平台完成了监控指标的采集,仪表盘的指标演示,并且将监控告警通知发送给了企业微信。categraf集成了许多插件,可以采集许多种类的数据指标,包括mysql、redis和kafka,夜莺平台也集成了许多的仪表盘,只需要简单的操作就可以将采集的中间件数据展示出来。但是在日常工作中,很多时候要采集的数据并不能通过categraf或者其他探针直接采集到,这个时候就需要自行开发exporter来进行指标采集,今天我们就用go来开发一个exporter采集一些有趣的数据并集成到夜莺,然后再自制一个仪表盘展示采集的数据。
1.指标说明
下面有一条比较有趣的命令,用来采集今天测试用的指标,具体命令如下:
ss -tan | grep "^ESTAB" | grep -v "\[" | awk '{M[$NF]++}END{for(k in M){print(k, M[k])}}' | sort -nr
输出信息如下:
223.98.103.132:3856 1
223.160.228.8:54043 1
223.160.161.196:40056 1
223.160.161.196:40055 1
223.160.161.196:40054 1
223.160.161.196:39712 1
223.104.79.65:63968 1
223.104.74.188:63788 1
223.104.74.188:63787 1
223.104.74.188:63786 1
223.104.74.188:63785 1
223.104.74.188:63784 1
223.104.74.188:63783 1
223.104.69.177:4915 1
223.104.69.177:4914 1
223.104.69.177:4913 1
223.104.69.177:4912 1
.............
大家能看出来这个命令是做什么用的吗?
如果大家感兴趣的话,可以慢慢拆解命令,一点点的执行,就可以看出其中奥秘了,这个命令的主要作用是统计有哪些IP端口对该服务器的某些端口发起了请求,执行以下部分可以看的比较清楚:
ss -tan | grep "^ESTAB" | grep -v "\["
ESTAB 0 0 172.30.206.89:443 163.179.229.41:34300
ESTAB 0 0 172.30.206.89:443 218.59.236.18:50247
ESTAB 0 0 172.30.206.89:443 116.147.252.46:45995
ESTAB 0 0 172.30.206.89:443 116.147.252.46:58842
ESTAB 0 0 172.30.206.89:443 163.179.229.39:63710
显示结果里面,前面的IP端口是请求方,后面是接收方。
所以我们今天要采集的指标就是服务器接收的请求总量。
2.资源准备
IP | CPU | 内存 | 用途 |
---|---|---|---|
10.173.100.15 | 8核 | 32G | 夜莺平台、exporter所在服务器 |
172.30.206.89 | 8核 | 32G | 用于数据采集 |
为了运行exporter,还需要在10.173.100.15上搭建好go语言环境。
3.exporter开发详解
接下来我们对exporter核心代码进行讲解,帮助大家理解。
3.1 核心依赖
prometheus为了让大家可以自行开发exporter,官方开发了对接模块,开发过程中需要导入的依赖有:
- "github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/promhttp"
3.2 核心代码
type insCollector struct {
reqMetric *prometheus.Desc
countMetric *prometheus.Desc
}
以上代码为采集指标,当前需要采集两个指标,分别为:
(1)请求方详情(主要为每次请求的IP端口、请求数)
(2)请求总量。
func newInsCollector() *insCollector {
return &insCollector{
reqMetric: prometheus.NewDesc(
fqName:"request_metrics",
help:"collect request metrics from user",
variableLabels:[]string{"ip", "val"},
constLabels:nil,
),
countMetric: prometheus.NewDesc("request_count",
"collect request count from user",
nil, nil),
}
}
初始化采集指标,分别指定了指标名称(fqName)、指标帮助信息(help)、可变标签(variableLabels)和常量标签(constLabels)。
func (ic *insCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- ic.reqMetric
ch <- ic.countMetric
}
func (ic *insCollector) Collect(ch chan<- prometheus.Metric) {
collector := newInsCollector()
instances, err := getRequestProcess()
if err != nil {
log.Fatal(err)
}
for _, instance := range instances {
v, err := strconv.Atoi(instance.Value)
if err != nil {
log.Fatal(err)
}
metricValue := float64(v)
m1 := prometheus.MustNewConstMetric(collector.reqMetric, prometheus.GaugeValue,
metricValue, instance.IpAddr, instance.Value)
ch <- m1
}
countValue := float64(len(instances))
m2 := prometheus.MustNewConstMetric(collector.countMetric, prometheus.GaugeValue, countValue)
ch <- m2
}
以上两个方法是每个采集器必须实现的,将指标的解释说明和具体数据传递给通道(channel),collect方法中的getRequestProcess函数用来采集具体指标,该函数返回的instances是一个Instance类型的列表,Instance类型和getRequestProcess函数具体代码如下:
type Instance struct {
IpAddr string
Value string
}
func getRequestProcess() ([]Instance, error) {
hostPort := fmt.Sprintf("%s:%s", sshHost, sshPort)
client, err := ssh.Dial("tcp", hostPort, &ssh.ClientConfig{
User: sshUser,
Auth: []ssh.AuthMethod{ssh.Password(password)},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
})
if err != nil {
return nil, err
}
defer client.Close()
session, err := client.NewSession()
if err != nil {
return nil, err
}
defer session.Close()
instanceList := []Instance{}
cmd := "/usr/sbin/ss -tan | grep "^ESTAB" |grep -v "\[" | awk '{M[$NF]++}END{for(k in M){print(k, M[k])}}' | sort -nr"
result, err := session.Output(cmd)
if err != nil {
return nil, err
}
for _, line := range strings.Split(string(result), "\n") {
i := strings.Split(line, " ")
if len(i) > 1 {
instanceList = append(instanceList, Instance{i[0], i[1]})
}
}
return instanceList, nil
}
在getRequestProcess中还用到了ssh模块,用来到指定服务器上运行命令,并获取命令结果。
var (
sshUser = "xxxxx"
sshHost = "172.30.206.89"
sshPort = "22"
password = "xxxxxxxxxxx"
)
这个是ssh远程服务器会用到的配置,建议放到环境变量中。
http.Handle("/metrics", promhttp.Handler())
log.Println("Listening on :9091")
log.Fatal(http.ListenAndServe(":9091", nil))
代码的主函数,运行一个server服务,指定端口为9091。
import (
"fmt"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"golang.org/x/crypto/ssh"
"log"
"net/http"
"strconv"
"strings"
)
代码的整体依赖,如果用goland编程工具的话,可以自动生成。
到此,所有的代码都过了一遍,整体还是很简单的,主要就是采集数据那一步,大家如果要采集其他指标,主要就是修改该部分逻辑,当然指标详情也得修改。
3.3 运行exporter
这里默认大家已经装了go语言环境,可以通过以下命令运行exporter:
cd /data/go/gopath/src/request_exporter (项目地址)
go mod init
go mod tidy
nohup go run main.go > server.log &
3.4 验证exporter服务
exporter正常运行之后,会暴露指标,上述代码上请求路径为http://主机IP:9091/metrics,我们可以请求一下,看能否获取想要的指标数据,我们可以先在exporter所在主机测试一下,命令如下:
curl 127.0.0.1:9091/metrics
....................
request_count 313
# HELP request_metrics collect request metrics from user
# TYPE request_metrics gauge
request_metrics{ip="100.100.30.25:80",val="1"} 1
request_metrics{ip="101.251.238.170:44607",val="1"} 1
request_metrics{ip="101.70.217.165:30454",val="1"} 1
request_metrics{ip="101.70.217.165:30558",val="1"} 1
request_metrics{ip="101.70.217.165:30659",val="1"} 1
request_metrics{ip="101.70.217.165:30702",val="1"} 1
request_metrics{ip="101.70.217.165:31069",val="1"} 1
request_metrics{ip="101.70.217.165:31269",val="1"} 1
.......................
可以看到确实获取到了我们需要的两个指标,request_count和request_metrics。
4.exporter接入prometheus
上面我们已经采集到了指标数据,接下来只需要将exporter接入prometheus,就可以在夜莺展示数据了。
4.1 修改prometheus配置
如果要将exporter接入prometheus,就需要修改prometheus配置,将exporter信息写入其中,如下所示:
static_configs:
- targets: ["localhost:9090"]
# The label name is added as a label `label_name=<label_value>` to any timeseries scraped from this config.
labels:
app: "prometheus"
- targets: ["10.173.100.15:9091"]
labels:
app: "request-exporter"
env: "test"
4.2 重启prometheus
修改完配置之后记得重启prometheus服务,命令如下:
kill -9 $PROPID(当前prometheus)
nohup ./prometheus --config.file=prometheus.yml --web.enable-remote-write-receiver &
4.3 指标查询
exporter接入prometheus之后,就可以在prometheus提供的简易界面查询指标了,promQL语句为:request_count和request_metrics,查询结果分别如下图所示:
可以看到以上两个指标数据都能查到。
5.夜莺添加仪表盘
之后就可以根据查询到的指标在夜莺新建仪表盘,如下图所示:
创建了两个图表,一个是时序图用来查看请求总数,一个是表格用来查看每条请求的具体信息。
6.总结
今天带大家开发了一个exporter,并接入夜莺,并通过夜莺的仪表盘展示数据。虽然篇幅不长,但是涉及的内容还是比较多的,需要掌握一些编程知识,还得熟悉prometheus和夜莺的使用。