您的位置:首頁(yè) > 軟件教程 > 教程 > Go 監(jiān)控告警入門 Opentelemetry

Go 監(jiān)控告警入門 Opentelemetry

來(lái)源:好特整理 | 時(shí)間:2024-08-16 10:16:54 | 閱讀:163 |  標(biāo)簽: T GO El   | 分享到:

探索 Go 語(yǔ)言中 Opentelemetry 與 Prometheus 集成,導(dǎo)出 HTTP 服務(wù)指標(biāo)監(jiān)控,并最終將 Prometheus 指標(biāo)可視化到 Grafana 中。

前言

Opentelemetry

分布式鏈路跟蹤( Distributed Tracing )的概念最早是由 Google 提出來(lái)的,發(fā)展至今技術(shù)已經(jīng)比較成熟,也是有一些協(xié)議標(biāo)準(zhǔn)可以參考。目前在 Tracing 技術(shù)這塊比較有影響力的是兩大開源技術(shù)框架:Netflix 公司開源的 OpenTracing 和 Google 開源的 OpenCensus 。兩大框架都擁有比較高的開發(fā)者群體。為形成統(tǒng)一的技術(shù)標(biāo)準(zhǔn),兩大框架最終磨合成立了 OpenTelemetry 項(xiàng)目,簡(jiǎn)稱 otel 。otel 有鏈路追蹤和監(jiān)控告警兩大塊,關(guān)于監(jiān)控告警,可以查看另一篇文章: Go 鏈路追蹤入門 Opentelemetry

Prometheus

Prometheus 源自 SoundCloud,擁有一整套開源系統(tǒng)監(jiān)控和警報(bào)工具包,是支持 OpenTelemetry 的系統(tǒng)之一,是 CNCF 的第二個(gè)項(xiàng)目。

Grafana

Grafana 是一個(gè)開源的分析和可視化平臺(tái),它允許你查詢、可視化和警報(bào)來(lái)自各種數(shù)據(jù)源的數(shù)據(jù)。它提供了一個(gè)用戶友好的界面,用于創(chuàng)建和共享儀表板、圖表和警報(bào)。Grafana 支持廣泛的數(shù)據(jù)源,其中就包括 Prometheus

Go 監(jiān)控告警入門 Opentelemetry

基礎(chǔ)概念

這里為了簡(jiǎn)單入門,盡量簡(jiǎn)單的介紹一些抽象概念,結(jié)合著代碼理解,如果不能理解也沒(méi)關(guān)系,代碼寫著寫著自然就明白了:

Meter Provider
用于接口化管理全局的 Meter 創(chuàng)建,相當(dāng)于全局的監(jiān)控指標(biāo)管理工廠。

Meter
用于接口化創(chuàng)建并管理全局的 Instrument ,不同的 Meter 可以看做是不同的程序組件。

Instrument
用于管理不同組件下的各個(gè)不同類型的指標(biāo),例如 http.server.request.total

Measurements
對(duì)應(yīng)指標(biāo)上報(bào)的具體的 DataPoint 指標(biāo)數(shù)據(jù),是一系列的數(shù)值項(xiàng)。

Metric Reader
用于實(shí)現(xiàn)對(duì)指標(biāo)的數(shù)據(jù)流讀取,內(nèi)部定義了具體操作指標(biāo)的數(shù)據(jù)結(jié)構(gòu)。 OpenTelemetry 官方社區(qū)提供了多種靈活的 Reader 實(shí)現(xiàn),例如 PeridRader、ManualReader 等。

Metric Exporter
Exporter 用于暴露本地指標(biāo)到對(duì)應(yīng)的第三方廠商,例如: Promtheus、Zipkin 等。

指標(biāo)類型

OpenTelemetry metrics 有許多不同指標(biāo)類型,可以把它想象成類似于 int, float 這種的變量類型:

Counter: 只增不減的指標(biāo),比如 http 請(qǐng)求總數(shù),字節(jié)大小;

Asynchronous Counter: 異步 Counter;

UpDownCounter: 可增可減的指標(biāo),比如 http 活動(dòng)連接數(shù);

Asynchronous UpDownCounter: 異步 Counter;

Gauge: 可增可減的指標(biāo),瞬時(shí)計(jì)量的值,比如 CPU 使用,它是異步的;

Histogram :分組聚合指標(biāo),這個(gè)較為難以理解一些,可以移步 此處 查看,當(dāng)然,后文也會(huì)有一個(gè)詳細(xì)的例子來(lái)使用它。

實(shí)戰(zhàn):采集指標(biāo)

廢話了一堆,終于可以實(shí)戰(zhàn)了。我們先以 http 請(qǐng)求總數(shù)為例來(lái)走一遍整個(gè)采集指標(biāo)流程。安裝擴(kuò)展:

go get github.com/prometheus/client_golang
go get go.opentelemetry.io/otel/exporters/prometheus
go get go.opentelemetry.io/otel/metric
go get go.opentelemetry.io/otel/sdk/metric

打開 main.go ,編寫以下代碼:

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"

	"github.com/prometheus/client_golang/prometheus/promhttp"
	"go.opentelemetry.io/otel/exporters/prometheus"
	api "go.opentelemetry.io/otel/metric"
	"go.opentelemetry.io/otel/sdk/metric"
)

const meterName = "oldme_prometheus_testing"

var (
	requestHelloCounter api.Int64Counter
)

func main() {
	ctx := context.Background()

	// 創(chuàng)建 prometheus 導(dǎo)出器
	exporter, err := prometheus.New()
	if err != nil {
		log.Fatal(err)
	}

	// 創(chuàng)建 meter
	provider := metric.NewMeterProvider(metric.WithReader(exporter))
	meter := provider.Meter(meterName)

	// 創(chuàng)建 counter 指標(biāo)類型
	requestHelloCounter, err = meter.Int64Counter("requests_hello_total")
	if err != nil {
		log.Fatal(err)
	}

	go serveMetrics()

	ctx, _ = signal.NotifyContext(ctx, os.Interrupt)
	<-ctx.Done()
}

func serveMetrics() {
	log.Printf("serving metrics at localhost:2223/metrics")
	http.Handle("/metrics", promhttp.Handler())

	http.Handle("/index", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 記錄 counter 指標(biāo)
		requestHelloCounter.Add(r.Context(), 1)

		_, _ = w.Write([]byte("Hello, Otel!"))
	}))

	err := http.ListenAndServe(":2223", nil) //nolint:gosec // Ignoring G114: Use of net/http serve function that has no support for setting timeouts.
	if err != nil {
		fmt.Printf("error serving http: %v", err)
		return
	}
}

在我們的代碼中,我們定義一個(gè)名字為 requests_hello_total Int64Counter 指標(biāo)類型, Int64Counter 代表這是一個(gè)只增不減的 int64 數(shù)值,用作記錄請(qǐng)求總數(shù)正好合適。運(yùn)行我們的程序,如果不出錯(cuò)的話,訪問(wèn) http://localhost:2223/index 可以看到 Hello, Otel! 。并且我們?cè)L問(wèn) http://localhost:2223/metrics 可以看到指標(biāo)數(shù)據(jù):

Go 監(jiān)控告警入門 Opentelemetry

這里數(shù)據(jù)還沒(méi)有進(jìn)行可視化,我們先把流程走通,多訪問(wèn)幾次 http://localhost:2223/index 可以看到 requests_hello_total 會(huì)增加:

Go 監(jiān)控告警入門 Opentelemetry

Histogram

接下來(lái)我們采集一下 Histogram 指標(biāo),統(tǒng)計(jì)在 0.1, 0.2, 0.5, 1, 2, 5 秒以內(nèi)的 http 請(qǐng)求數(shù),在 main.go 中加上相關(guān)代碼,可以直接復(fù)制過(guò)去:

package main

import (
	"context"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"os"
	"os/signal"
	"time"

	"github.com/prometheus/client_golang/prometheus/promhttp"
	"go.opentelemetry.io/otel/exporters/prometheus"
	api "go.opentelemetry.io/otel/metric"
	"go.opentelemetry.io/otel/sdk/metric"
)

const meterName = "oldme_prometheus_testing"

var (
	requestHelloCounter      api.Int64Counter
	requestDurationHistogram api.Float64Histogram
)

func main() {
	ctx := context.Background()

	// 創(chuàng)建 prometheus 導(dǎo)出器
	exporter, err := prometheus.New()
	if err != nil {
		log.Fatal(err)
	}

	// 創(chuàng)建 meter
	provider := metric.NewMeterProvider(metric.WithReader(exporter))
	meter := provider.Meter(meterName)

	// 創(chuàng)建 counter 指標(biāo)類型
	requestHelloCounter, err = meter.Int64Counter("requests_hello_total")
	if err != nil {
		log.Fatal(err)
	}

	// 創(chuàng)建 Histogram 指標(biāo)類型
	requestDurationHistogram, err = meter.Float64Histogram(
		"request_hello_duration_seconds",
		api.WithDescription("記錄 Hello 請(qǐng)求的耗時(shí)統(tǒng)計(jì)"),
		api.WithExplicitBucketBoundaries(0.1, 0.2, 0.5, 1, 2, 5),
	)
	if err != nil {
		log.Fatal(err)
	}

	go serveMetrics()
	go goroutineMock()

	ctx, _ = signal.NotifyContext(ctx, os.Interrupt)
	<-ctx.Done()
}

func serveMetrics() {
	log.Printf("serving metrics at localhost:2223/metrics")
	http.Handle("/metrics", promhttp.Handler())

	http.Handle("/index", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 記錄 counter 指標(biāo)
		requestHelloCounter.Add(r.Context(), 1)

		// 計(jì)算請(qǐng)求處理時(shí)間
		startTime := time.Now()
		// 模擬請(qǐng)求處理時(shí)間
		time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
		defer func() {
			duration := time.Since(startTime).Seconds()
			requestDurationHistogram.Record(r.Context(), duration)
		}()

		_, _ = w.Write([]byte("Hello, Otel!"))
	}))

	err := http.ListenAndServe(":2223", nil) //nolint:gosec // Ignoring G114: Use of net/http serve function that has no support for setting timeouts.
	if err != nil {
		fmt.Printf("error serving http: %v", err)
		return
	}
}

// 隨機(jī)模擬若干個(gè)協(xié)程
func goroutineMock() {
	for {
		go func() {
			// 等待若干秒
			var s = time.Duration(rand.Intn(10))
			time.Sleep(s * time.Second)
		}()
		time.Sleep(1 * time.Millisecond)
	}
}

走到這里,代碼層面結(jié)束了,已經(jīng)成功一半了,代碼開源在 Github 。之后我們就可以安裝 Prometheus 服務(wù)端和 Grafana 來(lái)進(jìn)行數(shù)據(jù)可視化。

安裝 Prometheus

Prometheus 有多種安裝方式,我這里依舊采用 Docker 安裝,當(dāng)然,你也可以使用其他方式安裝,具體安裝方式可以參考其他文章,后續(xù) Grafana 同理,不在贅述,在 Prometheus.yml 中填寫 targets 我們的地址:

scrape_configs:
  - job_name: "prometheus"

    static_configs:
      - targets: ["localhost:2223"]

Prometheus 會(huì)自動(dòng)去 {{target}}/metrics 中拉取我們的指標(biāo)。之后在瀏覽器打開 Promethues 的地址,例如我的是:http://localhost:9090,如果全部正常的話可以在 status:targets 中看見我們的指標(biāo):

Go 監(jiān)控告警入門 Opentelemetry

Promethues 的首頁(yè)查詢 requests_hello_total 指標(biāo)可以看到可視化的圖表:

Go 監(jiān)控告警入門 Opentelemetry

安裝 Grafana

我的 Grafana 安裝好了,登錄進(jìn)去后是這樣的(我更改后默認(rèn)顏色):

Go 監(jiān)控告警入門 Opentelemetry

Data source 中添加 Prometheus 服務(wù)器,然后在 Dashboard 中添加我們想要監(jiān)控的指標(biāo),即可看到更美觀的圖表:

Go 監(jiān)控告警入門 Opentelemetry Go 監(jiān)控告警入門 Opentelemetry

小編推薦閱讀

好特網(wǎng)發(fā)布此文僅為傳遞信息,不代表好特網(wǎng)認(rèn)同期限觀點(diǎn)或證實(shí)其描述。

Go v1.62
Go v1.62
類型:動(dòng)作冒險(xiǎn)  運(yùn)營(yíng)狀態(tài):正式運(yùn)營(yíng)  語(yǔ)言:中文   

游戲攻略

游戲禮包

游戲視頻

游戲下載

游戲活動(dòng)

GoEscape是一款迷宮逃脫休閑闖關(guān)游戲。在這款游戲中,玩家可以挑戰(zhàn)大量關(guān)卡,通過(guò)旋轉(zhuǎn)屏幕的方式幫助球球

相關(guān)視頻攻略

更多

掃二維碼進(jìn)入好特網(wǎng)手機(jī)版本!

掃二維碼進(jìn)入好特網(wǎng)微信公眾號(hào)!

本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請(qǐng)發(fā)郵件[email protected]

湘ICP備2022002427號(hào)-10 湘公網(wǎng)安備:43070202000427號(hào)© 2013~2024 haote.com 好特網(wǎng)