golang实现指标监控与Prometheus暴露的插件库metrics的使用

Golang实现指标监控与Prometheus暴露的插件库metrics的使用

关于

指标是用于比较和跟踪性能或生产的定量评估度量。这个库为Go编程语言提供了原子计数器、测量仪和直方图。用户可以选择以Prometheus文本格式公开快照。

API

使用

建议在包级别进行静态注册。这些声明也有助于记录代码中涵盖的功能。

// Package Metrics
var (
	ConnectCount = metrics.MustCounter("db_connects_total", "Number of established initiations.")
	CacheBytes   = metrics.MustInteger("db_cache_bytes", "Size of collective responses.")
	DiskUsage    = metrics.Must1LabelRealSample("db_disk_usage_ratio", "device")
)

更新方法设计为无错误操作,例如CacheBytes.Add(-72)DiskUsage(dev.Name).Set(1 - dev.Free, time.Now())

只需使用http.HandleFunc("/metrics", metrics.ServeHTTP)即可提供HTTP服务。

示例HTTP响应:

HTTP/1.1 200 OK
Content-Type: text/plain;version=0.0.4
Date: Sun, 07 Mar 2021 15:22:47 GMT
Content-Length: 351

# Prometheus Samples

# TYPE db_connects_total counter
# HELP db_connects_total Number of established initiations.
db_connects_total 4 1615130567389

# TYPE db_cache_bytes gauge
# HELP db_cache_bytes Size of collective responses.
db_cache_bytes 7600 1615130567389

# TYPE db_disk_usage_ratio gauge
db_disk_usage_ratio{device="sda"} 0.19 1615130563595

完整示例Demo

package main

import (
	"net/http"
	"time"

	"github.com/pascaldekloe/metrics"
)

// 定义指标
var (
	RequestCount = metrics.MustCounter("http_requests_total", "Total number of HTTP requests.")
	ResponseTime = metrics.MustRealSample("http_response_time_seconds", "HTTP response time in seconds.")
)

func main() {
	// 设置HTTP路由
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		
		// 处理请求
		w.Write([]byte("Hello, World!"))
		
		// 记录指标
		RequestCount.Add(1)
		ResponseTime.Set(time.Since(start).Seconds(), time.Now())
	})

	// 暴露指标端点
	http.HandleFunc("/metrics", metrics.ServeHTTP)

	// 启动服务器
	http.ListenAndServe(":8080", nil)
}

性能

以下结果是在Apple M1上使用Go 1.20测量的:

name                          time/op
Label/sequential/4-8            14.4ns ± 0%
Label/sequential/4x4-8          17.1ns ± 0%
Label/sequential/4x4x4-8        29.6ns ± 0%
Label/parallel/4-8              85.3ns ± 2%
Label/parallel/4x4-8            89.2ns ± 1%
Label/parallel/4x4x4-8           103ns ± 0%
Get/histogram5/sequential-8     45.0ns ± 0%
Get/histogram5/2routines-8      85.1ns ± 0%
Set/real/sequential-8           5.64ns ± 0%
Set/real/2routines-8            16.5ns ± 2%
Set/sample/sequential-8         13.6ns ± 1%
Set/sample/2routines-8          38.7ns ± 7%
Add/counter/sequential-8        6.88ns ± 0%
Add/counter/2routines-8         16.1ns ± 2%
Add/integer/sequential-8        6.88ns ± 0%
Add/integer/2routines-8         16.1ns ± 1%
Add/histogram5/sequential-8     16.1ns ± 1%
Add/histogram5/2routines-8      69.5ns ± 1%
ServeHTTP/32/counter-8           687ns ± 0%
ServeHTTP/32/real-8             1.87µs ± 0%
ServeHTTP/32/integer-8           694ns ± 0%
ServeHTTP/32/histogram5-8       6.05µs ± 0%
ServeHTTP/32/label5-8           1.97µs ± 0%
ServeHTTP/32/label2x3x5-8       1.98µs ± 0%
ServeHTTP/32/sample-8           2.06µs ± 0%
ServeHTTP/1024/counter-8        18.5µs ± 0%
ServeHTTP/1024/real-8           50.9µs ± 0%
ServeHTTP/1024/integer-8        18.8µs ± 0%
ServeHTTP/1024/histogram5-8      192µs ± 0%
ServeHTTP/1024/label5-8         54.4µs ± 0%
ServeHTTP/1024/label2x3x5-8     54.4µs ± 0%
ServeHTTP/1024/sample-8         57.6µs ± 0%

更多关于golang实现指标监控与Prometheus暴露的插件库metrics的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现指标监控与Prometheus暴露的插件库metrics的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 实现指标监控与 Prometheus 暴露

在 Go 中实现指标监控并暴露给 Prometheus,我们可以使用 prometheus/client_golang 这个官方库。下面我将详细介绍如何使用这个库来实现各种类型的指标监控。

安装依赖

首先需要安装 Prometheus 客户端库:

go get github.com/prometheus/client_golang/prometheus
go get github.com/prometheus/client_golang/prometheus/promhttp

基本使用示例

1. 计数器(Counter)

计数器用于累计值,通常用于记录请求数量、任务完成数等。

package main

import (
	"net/http"
	
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
	requestsCounter = prometheus.NewCounter(
		prometheus.CounterOpts{
			Name: "http_requests_total",
			Help: "Total number of HTTP requests",
		},
	)
)

func init() {
	// 注册指标
	prometheus.MustRegister(requestsCounter)
}

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		requestsCounter.Inc()
		w.Write([]byte("Hello, World!"))
	})
	
	// 暴露指标端点
	http.Handle("/metrics", promhttp.Handler())
	http.ListenAndServe(":8080", nil)
}

2. 仪表盘(Gauge)

仪表盘用于表示可以增减的数值,如内存使用量、当前连接数等。

var (
	memoryUsage = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "memory_usage_bytes",
			Help: "Current memory usage in bytes",
		},
	)
)

func init() {
	prometheus.MustRegister(memoryUsage)
}

// 在代码中更新指标
func updateMemoryUsage() {
	// 模拟获取内存使用量
	mem := getMemoryUsageFromSystem()
	memoryUsage.Set(float64(mem))
}

3. 直方图(Histogram)

直方图用于观察值分布,如请求延迟、响应大小等。

var (
	requestDuration = prometheus.NewHistogram(
		prometheus.HistogramOpts{
			Name:    "http_request_duration_seconds",
			Help:    "Duration of HTTP requests in seconds",
			Buckets: prometheus.DefBuckets, // 使用默认桶
		},
	)
)

func init() {
	prometheus.MustRegister(requestDuration)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	timer := prometheus.NewTimer(requestDuration)
	defer timer.ObserveDuration()
	
	// 处理请求
	// ...
}

4. 摘要(Summary)

摘要类似于直方图,但直接在客户端计算分位数。

var (
	responseSizes = prometheus.NewSummary(
		prometheus.SummaryOpts{
			Name: "http_response_size_bytes",
			Help: "Size of HTTP responses in bytes",
			Objectives: map[float64]float64{
				0.5:  0.05,  // 50th percentile with 5% tolerance
				0.9:  0.01,  // 90th percentile with 1% tolerance
				0.99: 0.001, // 99th percentile with 0.1% tolerance
			},
		},
	)
)

func init() {
	prometheus.MustRegister(responseSizes)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	// 处理请求
	// ...
	
	// 记录响应大小
	responseSizes.Observe(float64(len(responseData)))
}

带标签的指标

Prometheus 支持为指标添加标签,用于区分不同维度的数据。

var (
	httpRequests = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "http_requests_total",
			Help: "Number of HTTP requests",
		},
		[]string{"method", "path", "status"},
	)
)

func init() {
	prometheus.MustRegister(httpRequests)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	// 处理请求
	status := 200 // 假设请求成功
	
	// 记录带标签的指标
	httpRequests.WithLabelValues(
		r.Method,
		r.URL.Path,
		strconv.Itoa(status),
	).Inc()
	
	// ...
}

自定义注册表

默认情况下,指标会注册到全局注册表中。你也可以创建自定义注册表:

func main() {
	// 创建自定义注册表
	registry := prometheus.NewRegistry()
	
	// 创建指标
	counter := prometheus.NewCounter(prometheus.CounterOpts{
		Name: "my_counter",
		Help: "This is my counter",
	})
	
	// 注册指标
	registry.MustRegister(counter)
	
	// 暴露自定义注册表的指标
	http.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
	http.ListenAndServe(":8080", nil)
}

最佳实践

  1. 指标命名:使用下划线分隔单词,以单位作为后缀(如_seconds_bytes
  2. 标签选择:避免使用高基数标签(如用户ID、IP地址等)
  3. 初始化:在程序启动时注册所有指标
  4. 文档:为每个指标提供清晰的Help信息
  5. 性能:避免在关键路径上进行昂贵的指标计算

完整示例

package main

import (
	"math/rand"
	"net/http"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
	httpRequests = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "http_requests_total",
			Help: "Total number of HTTP requests",
		},
		[]string{"method", "path"},
	)

	httpDuration = prometheus.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    "http_request_duration_seconds",
			Help:    "Duration of HTTP requests",
			Buckets: []float64{0.1, 0.5, 1, 2, 5},
		},
		[]string{"path"},
	)

	activeRequests = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "http_active_requests",
			Help: "Number of active HTTP requests",
		},
	)
)

func init() {
	prometheus.MustRegister(httpRequests)
	prometheus.MustRegister(httpDuration)
	prometheus.MustRegister(activeRequests)
}

func main() {
	// 模拟业务处理函数
	handler := func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		activeRequests.Inc()
		defer activeRequests.Dec()

		// 随机延迟模拟处理时间
		time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)

		// 记录请求
		httpRequests.WithLabelValues(r.Method, r.URL.Path).Inc()

		// 记录延迟
		duration := time.Since(start)
		httpDuration.WithLabelValues(r.URL.Path).Observe(duration.Seconds())

		w.Write([]byte("OK"))
	}

	http.HandleFunc("/", handler)
	http.HandleFunc("/api", handler)
	http.Handle("/metrics", promhttp.Handler())

	http.ListenAndServe(":8080", nil)
}

这个示例展示了如何同时使用计数器、直方图和仪表盘来监控HTTP服务。你可以通过访问 http://localhost:8080/metrics 查看暴露的指标数据。

要集成到Prometheus中,只需在Prometheus配置中添加这个端点即可:

scrape_configs:
  - job_name: 'my_go_app'
    static_configs:
      - targets: ['localhost:8080']
回到顶部