Prometheus源码分析:基于GoClient自定义的Exporter,是如何在Loc。。。

更新时间:2023-07-04 03:11:30 阅读: 评论:0

Prometheus源码分析:基于GoClient⾃定义的Exporter,是如
何在Loc。。。
⽬录
1 背景
我们想要提⾼微服务系统的可观察性,因此在go语⾔写的微服务中,使⽤Prometheus提供的go client实现上报metrics的功能。
2 什么是Exporter?
⼴义上讲,所有可以向Prometheus提供监控样本数据的程序都可以被称为⼀个Exporter。
⽽Exporter的⼀个实例称为target,如下所⽰,Prometheus通过轮询的⽅式定期从这些target中获取样本数据。
例如我有个微服务是⽤go语⾔写的,并且这个微服务部署了两个实例,且在每个实例中都对外提供了⼀个HTTP接⼝"/Metrics",然后Prometheus可以通过这个HTTP接⼝访问到该实例上的Metrics信息。
在这个例⼦中,go代码⾥的HTTP接⼝"/Metrics"的相关代码就是⼀个Exporter,⽽每个微服务实例中的这个HTTP接⼝就是⼀个target。
3 Prometheus以轮询的⽅式Pull拉取Metrics
Prometheus如何获取target⾥的Metrics信息?
Prometheus整体架构是以Pull的形式获取Metrics信息,因此它会以轮询的⽅式,从target那获取Metrics信息,例如访问target对外暴露的HTTP接⼝获取Metrics信息。
4 Target是如何在本地存储Metrics的?
我们以Counter类型的Metric为例。
4.1 基于Go Client开发的Exporter
package main
辽阔的反义词是什么import (
"/prometheus/client_golang/prometheus"
"net/http"
"/prometheus/client_golang/prometheus/promhttp"
"time"
"math/rand"
"fmt"
)
// Counter类型的Metric火腿蛋炒饭
var httpRequestCount = prometheus.NewCounterVec(
prometheus.CounterOpts{
养獭兔
Name: "http_request_count", // Metric的name
Help: "http request count"}, // Metric的说明信息
[]string{"endpoint"}) // Metric有⼀个Label,名称是endpoint,Metric形如 http_request_count(endpoint="")
// Gauge类型的Metric
var orderNum = prometheus.NewGauge(
var orderNum = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "order_num",
Help: "order num"})
// Summary类型的Metric
var httpRequestDuration = prometheus.NewSummaryVec(
prometheus.SummaryOpts{
Name: "http_request_duration",
Help: "http request duration",
},
[]string{"endpoint"},
)
// 将Metric注册到本地的Prometheus
func init() {
prometheus.MustRegister(httpRequestCount)
prometheus.MustRegister(orderNum)
prometheus.MustRegister(httpRequestDuration)
}
func main() {
// Exporter
http.Handle("/metrics", promhttp.Handler()) // 对外暴露metrics接⼝,等待Prometheus来拉取 http.HandleFunc("/hello/", hello) // 处理业务请求,并变更Metric信息
ipport := "127.0.0.1:8888"
fmt.Println("服务器启动%s", ipport)
err := http.ListenAndServe(ipport, nil)
if err != nil {
fmt.Println(err)
}
}
func hello(w http.ResponWriter, r *http.Request) {
fmt.Printf("process one request = %s\n", r.URL.Path)
// Counter类型的Metric只能增
httpRequestCount.WithLabelValues(r.URL.Path).Inc()
start := time.Now()
画巨齿鲨
n := rand.Intn(100)
// Gauge类型的Metric可增可减
if n >= 90 {
orderNum.Dec()出发英文
time.Sleep(100 * time.Millicond)
} el {
orderNum.Inc()
time.Sleep(50 * time.Millicond)
}
// Summary类型Metric
elapd := (float64)(time.Since(start) / time.Millicond)
httpRequestDuration.WithLabelValues(r.URL.Path).Obrve(elapd)
w.Write([]byte("ok"))
}
4.2 Counter类型Metric源码分析
4.2.1 声明Counter类型变量
// Counter类型的Metric
var httpRequestCount = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_request_count", // Metric的name
Help: "http request count"}, // Metric的说明信息
[]string{"endpoint"}) // Metric有⼀个Label,名称是endpoint,Metric形如 http_request_count(endpoint="")
4.2.2 Counter类型定义
// Counter定义
type CounterVec struct {
*MetricVec
}
// MetricVec定义
type MetricVec struct {
*metricMap // Metric最终是存在这⾥
curry []curriedLabelValue
// hashAdd and hashAddByte can be replaced for testing collision handling.
hashAdd    func(h uint64, s string) uint64
hashAddByte func(h uint64, b byte) uint64
}
4.2. WithLabelValues⽅法
重点:
⼀个指标由Metric name + Labels共同确定。
若Metric name相同,但Label的值不同,则是不同的Metric。
例如:http_request_count(endpoint="hello"),http_request_count(endpoint="world")是两个不同的指标
// @Param lvs 表⽰label values
func (v *CounterVec) WithLabelValues(lvs ...string) Counter {
c, err := v.) // 根据label的值来找对应的Metric
if err != nil {
panic(err)
}
return c
}
4.2. GetMetricWithLabelValues⽅法
// 根据label的值来找对应的Metric
// @Param lvs表⽰label value
func (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
metric, err := v.MetricVec.)
if metric != nil {
return metric.(Counter), err
}
return nil, err
}
4.2. GetMetricWithLabelValues⽅法
孢子粉的吃法// 根据label值找对应的metric
func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) {
h, err := m.hashLabelValues(lvs) // 获取label对应的hash值,⾮重点不展开讲,这块的核⼼是,若hash值⼀样,则对应的Metric是同⼀个
if err != nil {
return nil, err
}
// 根据hash值从metricMap⾥get对应的metric
// 若不存在则新创建⼀个metric并放⼊到metricMap⾥
OrCreateMetricWithLabelValues(h, lvs, m.curry), nil
}
4.2.6 metricMap的结构,Metric最终存到⼀个map⾥,key=根据label值计算出的hash值,value=Metric元信息
// metricMap定义,Exporter的Metric都存在这个结构中
type metricMap struct {
mtx      sync.RWMutex // Protects metrics.
metrics  map[uint64][]metricWithLabelValues // Metric最终存到⼀个map⾥,key=根据label值计算出的hash值,value=Metric元信息
desc      *Desc
newMetric func(labelValues ...string) Metric
}
type metricWithLabelValues struct {
values []string // label的值
metric Metric // Metric的meta信息
}
5 Prometheus拉取Exporter的哪些数据?
// Prometheus拉取的⼊⼝
http.Handle("/metrics", promhttp.Handler())
// promhttp.Handler()
func Handler() http.Handler {
return InstrumentMetricHandler(
prometheus.DefaultRegisterer, HandlerFor(prometheus.DefaultGatherer, HandlerOpts{}),
深圳人才引进政策)
}
// HandlerFor
func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
// 省略部分代码
mfs, err := reg.Gather() // 收集Metric信息
// 省略部分代码
}
// prometheus.DefaultGatherer
//
var (
defaultRegistry              = NewRegistry() // DefaultGatherer就是defaultRegistry
DefaultRegisterer Registerer = defaultRegistry
DefaultGatherer  Gatherer  = defaultRegistry
)
//
/
/ Gather implements Gatherer. 负责收集metrics信息
func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
// 省略部分代码
// 声明Counter类型的Metric后,需要MustRegist注册到Registry,最终就是保存在collectorsByID⾥
for _, collector := llectorsByID {
checkedCollectors <- collector
checkedCollectors <- collector
}
// 省略部分代码
collectWorker := func() {
for {
lect {
ca collector := <-checkedCollectors:
collector.Collect(checkedMetricChan) // 执⾏Counter的Collect,见下⽂
ca collector := <-uncheckedCollectors:
collector.Collect(uncheckedMetricChan)
default:
return
}
祠堂大门对联wg.Done()
}
}
/
/ 省略部分代码
}
//
// Collect implements Collector.
func (m *MetricVec) Collect(ch chan<- Metric) { m.metricMap.Collect(ch) }
//
// Collect implements Collector.
// 返回metricMap⾥所有的Metric
func (m *metricMap) Collect(ch chan<- Metric) {
RUnlock()
for _, metrics := ics {
for _, metric := range metrics {
ch <- ic
}
}
}
⾄此,可见Prometheus拉取的就是Counter类型的metricMap⾥的 metric数据。这⾥有⼀点要注意:Prometheus拉取metric后并没有删除Local的metric信息。

本文发布于:2023-07-04 03:11:30,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1066816.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:信息   类型   拉取   服务   获取   实例   数据   代码
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图