Metric模組原始碼解析

語言: CN / TW / HK

分散式系統的監控告警及運維服務離不開指標監控,開務作為浪潮自主研發的一款分散式資料庫自然也不例外。在兼顧強一致性、高可用分散式架構、線上水平擴充套件、企業級安全等特性下,開務的 metric 模組可提供監控指標,實現預先定義指標的週期性採集。同時,可以提供相容 Prometheus 標準格式的 API 介面,方便與外部的 Prometheus 服務進行整合。

開務資料庫 metric 模組收集各模組相關統計的 metric 資訊,並將其作為 Prometheus 格式的指標儲存起來用於進一步查閱,對判斷開務資料庫的執行情況有著重要作用,同時也是開務資料庫 adminUI 指標的資料來源。本期內容將圍繞下圖展示的 metric 模組基本框架,帶領大家深入瞭解開務資料庫 metric 模組的原始碼,圖中各模組的詳細介紹將持續為大家更新。

1、定義介面介紹

1.IterableIterable:提供了一個同步訪問內部物件的方法。方法如下:

GetName() string 返回指標名
GetHelp() string 返回指標幫助文字
GetMeasurement() string 返回指標的lable
GetUnit() Unit 返回指標使用的單位
GetMetadata() Metdata 返回指標的Metadata
Inspect(func(interface{})) Inspect對每個包含的項呼叫給定的閉包

2.PrometheusExportable:是標準獨立指標介面,可供指標匯入 Prometheus。方法如下:

GetName() string 返回指標名
GetHelp() string 返回指標幫助文字
GetType() *prometheusgo.MetricType 返回指標的Prometheus型別
GetLables() []*prometheusgo.LabelPair Metadata中的一個方法,返回指標的標籤
ToPrometheusMetric() *prometheusgo.Metric 返回一個完成值填充的Prometheus指標

3.PrometheusIterable:是 PrometheusExportable 的擴充套件,用於指示該指標由增加父標籤值的子指標組成。包含成員:PrometheusExportable。方法如下:

Each([]*prometheusgo.LabelPair, func(metric *prometheusgo.Metric))
“Each”獲取與父指標相關聯的標籤對切片,並使用每個子指標呼叫所傳遞的函式

2、Metric Metadata介紹

Metadata 包含關於指標的元資料,它必須嵌入到每個 metric object 中。它用於將有關指標的資訊匯出到 Promethues 和 adminUI 圖表。

type Metadata struct {  
Name        string           
Help        string           
Measurement string            
Unit        Unit             
MetricType  _go.MetricType    
Labels      []*LabelPair     
}  

// 方法
GetName() string  
GetHelp() string  
GetMeasurement() string  
GetUnit() Unit  
GetLabels() []*prometheusgo.LabelPair  
Addlabel(name value string)//給一個指標新增標籤/值對映

3、指標型別介紹

1.Histogram:在一段時間範圍內對資料進行取樣(通常是請求持續時間、響應大小等),並將其計入可配置的儲存桶(bucket)中,後續可通過指定區間篩選樣本,也可以統計樣本總數,最後一般將資料展示為直方圖。

Prometheus 的 Histogram 是一種累積直方圖,與上面的區間劃分方式是有差別的。它的劃分方式如下:假設每個 bucket 的寬度是 0.2s,那麼第一個 bucket 表示響應時間小於等於 0.2s 的請求數量,第二個 bucket 表示響應時間小於等於 0.4s 的請求數量,以此類推。也就是說,每一個 bucket 的樣本包含了之前所有 bucket 的樣本,所以叫累積直方圖。

type Histogram {  
Metadata  
maxVal int64  
mu     struct {  
syncutil.Mutex  
cumulative *hdrhistogram.Histogram  
sliding    *slidingHistogram     
}  
//hdrhistogram.Histogram
type Histogram struct {  
lowestTrackableValue        int64  
highestTrackableValue       int64  
unitMagnitude               int64  
significantFigures          int64  
subBucketHalfCountMagnitude int32  
subBucketHalfCount          int32  
subBucketMask               int64  
subBucketCount              int32  
bucketCount                 int32  
countsLen                   int32  
totalCount                  int64  
counts                      []int64  
} 
//slidingHistogram
type slidingHistogram struct {  
windowed *hdrhistogram.WindowedHistogram  
nextT    time.Time  
duration time.Duration  
} 
type WindowedHistogram struct {
idx int
h  []Histogram
m  *Histogram
Current *Histogram
}

//相關方法介紹
func (h *Histogram) Windowed() (*hdrhistogram.Histogram, time.Duration)
返回一份當前的視窗化直方圖的資料和其中的時間間隔

func (h *Histogram) Snapshot() *hdrhistogram.Histogram
返回累積(即所有樣本)直方圖資料的副本

func (h *Histogram) RecordValue(v int64)
RecordValue將給定的值新增到直方圖。記錄超過該直方圖配置最大值使用方法

func (h *Histogram) TotalCount() int64
TotalCount返回樣本的(累計)數量

func (h *Histogram) Min() int64
返回最小值

func (h *Histogram) Inspect(f func(interface{}))
呼叫帶有空字串和接收方的閉包

func (h *Histogram) GetType() *prometheusgo.MetricType
返回此指標的Prometheus型別enum

func (h *Histogram) ToPrometheusMetric() *prometheusgo.Metric
返回正確型別的已填充的Prometheus度量值

func (h *Histogram) GetMetadata() Metadata
返回指標的元資料,包括Prometheus MetricType

func NewHistogram(metadata Metadata, duration time.Duration, maxVal int64, sigFigs int) (*Histogram)
例項化一個新histogram

func NewLatency(metadata Metadata, histogramWindow time.Duration) *Histogram
NewLatency
返回一個帶有適當預設值的直方圖來跟蹤延遲。數值以ns表示,截斷為間隔[0,MaxLatency],並以1位精度記錄(即誤差在100ms時<10ms,在60s時<6s)

2.Counter:代表一種樣本資料單調遞增的指標,即只增不減,除非監控系統發生了重置。例如,你可以使用 Counter 型別的指標來表示服務的請求數、已完成的任務數、錯誤發生的次數等。

type Counter struct {  
Metadata  
metrics.Counter  
}  
type Counter interface {  
Clear()  
Count() int64  
Dec(int64)  
Inc(int64)  
Snapshot() Counter  
}

//相關方法介紹
func (c *Counter) Dec(int64)
Dec過載了metric.Counter的方法。不能使用這種方法,它只用於防止誤用metric型別

func (c *Counter) GetType() *prometheusgo.MetricType
返回此指標的Prometheus型別enum

func (c *Counter) Inspect(f func(interface{}))
呼叫帶有空字串和接收方的閉包,即返回自己c

func (c *Counter) MarshalJSON() ([]byte, error)
MarshalJSON將資料封裝到JSON

func (c *Counter) GetMetadata() Metadata
返回指標的元資料,包括Prometheus MetricType

3.Gauge:代表一種樣本資料可以任意變化的指標,即可增可減。Guage 通常用於像溫度或者記憶體使用率這種指標資料,也可以表示能隨時增加或減少的“總數”,例如:當前併發請求的數量。

type Gauge struct {  
Metadata  
value *int64  
fn    func() int64  
}

//相關方法介紹
func (g *Gauge) Snapshot() metrics.Gauge
Snapshot返回Gauge的只讀副本

func (g *Gauge) Update(v int64)
更新Gauge的值

func (g *Gauge) Inc(i int64)
增加Gauge的當前值

func (g *Gauge) Dec(i int64)
減少Gauge的當前值

func (g *Gauge) Value() int64
Value返回Gauge的當前值

func (g *Gauge) GetType() *prometheusgo.MetricType
返回此指標的Prometheus型別enum

func (g *Gauge) ToPrometheusMetric() *prometheusgo.Metric
返回此指標的Prometheus型別enum

func (g *Gauge) GetMetadata() Metadata
返回指標的元資料,包括Prometheus MetricType

4.Rate:用來計算某個指標在最近一個區間時間內的變化率。

type Rate struct {  
Metadata  
mu       syncutil.Mutex // protects fields below  
curSum   float64  
wrapped  ewma.MovingAverage  
interval time.Duration  
nextT    time.Time  
}  

//相關方法介紹
func (e *Rate) GetType() *prometheusgo.MetricType
GetType返回該指標的Prometheus型別enum

func (e *Rate) Inspect(f func(interface{}))
Inspect用自身呼叫給定的閉包

func (e *Rate) ToPrometheusMetric() *prometheusgo.Metric
返回此指標的Prometheus型別enum

func (c *Counter) MarshalJSON() ([]byte, error)
MarshalJSON將資料封裝到JSON

func (e *Rate) GetMetadata() Metadata
GetMetadata返回指標的元資料,包括Prometheus MetricType

func (e *Rate) Value() float64
Value返回Rate的當前值

func (e *Rate) tick()
Rate時間前進

func (e *Rate) nextTick() time.Time
返回Rate的當前時間。

func (e *Rate) Add(v float64)
新增將給定的測量值新增到Rate

4、註冊器Registry介紹

Registry 是 metric 的列表,它提供了一種處理指標的方法,可以將 metric 編組成 JSON,並生成 Prometheus 格式的 metric。同時可以給註冊的指標打上標籤,當匯出到 Prometheus 時,這些標籤將應用於它的所有指標。

type Registry struct {  
syncutil.Mutex  
labels  []*prometheusgo.LabelPair  
tracked []Iterable  
}  

//相關方法介紹
func (r *Registry) AddLabel(name, value string)
AddLabel為這個登錄檔新增一個標籤/值對

func (r *Registry) AddMetric(metric Iterable)
AddMetric將傳入的metric新增到登錄檔

func (r *Registry) WriteMetricsMetadata(dest map[string]Metadata)
WriteMetricsMetadata將所有跟蹤metric的元資料寫入引數對映

func (r *Registry) Each(f func(name string, val interface{}))
每個函式對所有metric呼叫給定的閉包

func (r *Registry) MarshalJSON() ([]byte, error)
格式化到JSON格式

5、註冊新Registry步驟

// 以txnMetric說明  
//txn_metric.go  
//宣告定義的指標結構體型別  
type TxnMetrics struct {  
Commits         *metric.Counter  
...  
}  
//定義指標的metadata  
var(  
metaCommitsRates = metric.Metadata{  
Name:        "txn.commits",  
Help:        "Number of committed KV transactions (including 1PC)",  
Measurement: "KV Transactions",  
Unit:        metric.Unit_COUNT,  
}  
...  
)  
//將定義的指標型別和metadata相關聯  
func MakeTxnMetrics(histogramWindow time.Duration) TxnMetrics {  
return TxnMetrics{  
Commits:                       metric.NewCounter(metaCommitsRates),  
}  
//server.go:  
//註冊進Registry  
txnMetrics := kvcoord.MakeTxnMetrics(cfg.HistogramWindowInterval())  
registry.AddMetricStruct(txnMetrics) 

開務資料庫是一款浪潮集團核心研發的先進、安全的雲原生分散式資料庫;具備雲原生、多中心、高可用、事務強一致等特性,滿足 HTAP 場景需求。業務範圍覆蓋能源、工業網際網路、政務、教育、金融等多行業。我們是一支平均年齡 30 歲的年輕團隊,在短短不到三年的時間裡,我們已取得近 300 項發明專利受理,10 項自有產品軟著授權。熱烈歡迎廣大夥伴加入我們的團隊,熱門崗位火熱招聘中,簡歷投遞郵箱: [email protected] / [email protected]

資料庫儲存核心研發工程師

工作職責:

1、負責儲存子系統的研發路線規劃、架構設計和關鍵技術問題攻關;

2、負責編寫功能測試用例,測試工具進行系統驗證;

3、負責資料庫的系統性能診斷與調優;

4、負責資料庫相關關鍵技術的預研和在團隊中的引導;

5、深入理解業務場景的資料庫儲存需求,針對性的為不同業務場景提供最合適的儲存方案。

任職要求:

1、學歷:本科或者本科以上學歷;

2、專業:計算機或相關專業;

3、專業知識:

— 3 年及以上 GO/C++ 開發經驗;

— 精通 C/C++/GO 語言,Linux 系統程式設計。熟悉無鎖資料結構,熟悉現代硬體體系結構 (CPU/Cache/Memory/Storage), 熟悉併發程式設計;

— 熟練使用 MySQL、PostgeSQL 等主流資料庫;

— 熟悉資料庫儲存系統的基本理論,熟悉事務處理,日誌與恢復策略,多版本併發控制技術的實現,對資料庫的基本理論和內部實現機制有深刻的理解;

— 技術視野開闊,有一定的系統性能優化經驗,掌握各種效能診斷工具和各種優化方法;

— 熟悉時序資料庫,有實際的時序資料庫開發經驗優先;

— 熟悉 RocksDB、Arrow、Parquet 等開源儲存專案原始碼者優先。

Base 地: 上海 / 天津 / 濟南 / 北京

資料庫方案工程師

工作職責:

1、負責分散式資料庫,或其相關工具、平臺等產品的梳理、規劃、設計和推進工作;

2、進行解決方案的調研、設計和驗證;

3、設計、撰寫和維護產品紅皮書;

4、跨部門溝通,協調各類資源以確保產品順利上線,推進產品迭代。

任職要求:

1、5 年以上的資料庫運維及方案設計經驗(ORACLE/Mysql/PostgreSQL 任意一種),對部署,優化,災備,恢復,高可用有實際經驗;

2、1 年左右的分散式資料庫經驗,瞭解國內任意一款分散式資料庫,有部署,POC,問題處理經驗;

3、對 OLTP 和 OLAP 系統或其中一種有實際運維設計經驗;

4、對資料庫災備,同步方案有實際專案經驗;

5、會一種資料庫 benchmark 工具,設計相應場景進行測試並結合已有經驗給與相應調整優化;

6、有基本的程式設計能力,如 go,shell,python 其中一項,可以寫簡單程式對資料庫進行併發測試,功能驗證;

7、有專案管理能力,很好的溝通能力,可以與開發人員順暢溝通,並於合作高校學生完成實驗及文件編寫;

8、紮實的技術,linux 和資料庫方面有一定積累,能對開發人員及學生進行一定指導,促使相關工作順利推進;

9、較強的文件編寫組織能力,根據實驗文件及相關手冊,編寫使用者解決方案手冊;

10、有一定語言表達能力,能做資料庫相關功能培訓。

Base 地: 上海 / 天津 / 濟南 / 北京