go-monitor: 服務(wù)質(zhì)量統(tǒng)計(jì)分析告警工具
本文介紹了一款開源 Go 語言監(jiān)控項(xiàng)目。
go-monitor基于golang開發(fā),是一個(gè)輕量的,用于服務(wù)質(zhì)量監(jiān)控并實(shí)現(xiàn)分析告警的工具。go-monitor目前并不是一個(gè)獨(dú)立的服務(wù),而是希望被大多數(shù)基于golang開發(fā)的項(xiàng)目如同引入一個(gè)日志組件一樣使用。
go-monitor能做什么
通過上報(bào)接口、函數(shù)、或者是任意調(diào)用服務(wù)的耗時(shí)以及其成功狀態(tài),go-monitor將按照設(shè)定的周期自動進(jìn)行服務(wù)質(zhì)量分析,統(tǒng)計(jì),并輸出詳細(xì)的報(bào)告數(shù)據(jù)。
在服務(wù)質(zhì)量達(dá)不到理想狀態(tài)時(shí),go-monitor將觸發(fā)告警,并在服務(wù)質(zhì)量回升時(shí),觸發(fā)恢復(fù)通知。
go-monitor提供非常多靈活的配置,以使其在大多數(shù)場景下都可以通過參數(shù)調(diào)整來勝任服務(wù)監(jiān)控的職責(zé)。
go-monitor采用無鎖隊(duì)列的方式避免并發(fā)鎖帶來的性能問題,MBP2012版本實(shí)測500萬次上報(bào)數(shù)據(jù)(go test bench)僅花費(fèi)1.6s即完成所有分析統(tǒng)計(jì)(此前并發(fā)鎖方案為1.9s),強(qiáng)大的性能允許你像記錄日志一樣來使用它,并且不需要擔(dān)心IO壓力(大部分日志組件使用緩存寫盤的方式提升性能,大并發(fā)下IO壓力明顯)。
什么場景建議使用go-monitor
例如我們開發(fā)了一個(gè)web應(yīng)用以對外提供服務(wù),我們可以嵌入go-monitor,上報(bào)每一個(gè)訪問的耗時(shí)、狀態(tài),以達(dá)到對我們整個(gè)web應(yīng)用服務(wù)質(zhì)量的監(jiān)控,也可以在服務(wù)質(zhì)量下滑甚至不可用時(shí)及時(shí)作出告警,更詳盡的,我們可以上報(bào)任何一個(gè)調(diào)用服務(wù)的狀態(tài),例如我們所訪問的數(shù)據(jù)庫,所依賴的外部接口等,除了監(jiān)控服務(wù)質(zhì)量,事實(shí)上也可以通過go-monitor提供的統(tǒng)計(jì)數(shù)據(jù)了解任何一個(gè)服務(wù)的平均時(shí)延,大到一個(gè)完整的接口,小到一個(gè)數(shù)據(jù)庫查詢語句。而使用go-monitor的成本非常小,僅僅是在golang項(xiàng)目中引入go-monitor,像使用日志組件一樣,毫無負(fù)擔(dān)。
使用方法
安裝
go get github.com/blurooo/go-monitor
引入使用
go-monitor的使用非常簡單,只需調(diào)用其提供的Register函數(shù)即可注冊得到一個(gè)上報(bào)客戶端,上報(bào)客戶端暴露了Report方法用于上報(bào)服務(wù)的耗時(shí)指標(biāo):
import (
"github.com/blurooo/go-monitor"
"time"
)
// 注冊得到一個(gè)上報(bào)客戶端用于http服務(wù)質(zhì)量監(jiān)控
var httpReportClient = monitor.Register(monitor.ReportClientConfig {
Name: "http服務(wù)監(jiān)控",
StatisticalCycle: 100, // 每100ms統(tǒng)計(jì)一次服務(wù)質(zhì)量
})
func main() {
t := time.NewTicker(10 * time.Millisecond)
for curTime := range t.C {
// 每10ms向http監(jiān)控客戶端上報(bào)一條http服務(wù)數(shù)據(jù),耗時(shí)0-100ms,狀態(tài)為200
httpReportClient.Report("GET - /app/api/users", uint32(curTime.Nanosecond() % 100), 200)
}
}
go-monitor將每個(gè)統(tǒng)計(jì)周期(100ms,默認(rèn)1min)輸出一條服務(wù)質(zhì)量分析報(bào)告,例如:
{"timestamp":"2018-01-24T09:10:55.190503145Z","clientName":"http服務(wù)監(jiān)控","interfaceName":"GET - /app/api/users","count":10,"successCount":10,"successRate":1,"successMsAver":48,"maxMs":98,"minMs":9,"fastCount":10,"fastRate":1,"failCount":0,"failDistribution":{},"timeConsumingDistribution":{"100~150":0,"150~200":0,"200~250":0,"250~300":0,"300~350":0,"350~400":0,"400~450":0,"450~500":0,"<100":10,">500":0}}
默認(rèn)的報(bào)告數(shù)據(jù)將輸出在控制臺,但允許我們定制,例如打印到日志文件或?qū)懭霐?shù)據(jù)庫等,只需傳入我們自己的OutputCaller即可:
import (
"github.com/Blurooo/go-monitor"
"time"
)
// 注冊得到一個(gè)上報(bào)客戶端用于http服務(wù)質(zhì)量監(jiān)控
var httpReportClient = monitor.Register(monitor.ReportClientConfig {
Name: "http服務(wù)監(jiān)控",
StatisticalCycle: 100, // 每100ms統(tǒng)計(jì)一次服務(wù)質(zhì)量
OutputCaller: func(o *monitor.OutPutData) {
// 寫入數(shù)據(jù)庫等邏輯
...
},
})
func main() {
t := time.NewTicker(10 * time.Millisecond)
for curTime := range t.C {
// 每10ms向http監(jiān)控客戶端上報(bào)一條http服務(wù)數(shù)據(jù),耗時(shí)0-100ms,狀態(tài)為200
httpReportClient.Report("GET - /app/api/users", uint32(curTime.Nanosecond() % 100), 200)
}
}
go-monitor支持多實(shí)例,并鼓勵使用多實(shí)例。實(shí)例之間互不影響,例如在同個(gè)應(yīng)用下,我們除了可以注冊一個(gè)http服務(wù)監(jiān)控之外,還可以注冊一個(gè)函數(shù)耗時(shí)監(jiān)控:
// 注冊得到一個(gè)上報(bào)客戶端用于http服務(wù)質(zhì)量監(jiān)控
var httpReportClient = monitor.Register(monitor.ReportClientConfig {
Name: "http服務(wù)監(jiān)控",
})
// 注冊得到一個(gè)上報(bào)客戶端用于函數(shù)耗時(shí)監(jiān)控
var funcReportClient = monitor.Register(monitor.ReportClientConfig {
Name: "函數(shù)耗時(shí)監(jiān)控",
})
go-monitor除了分析統(tǒng)計(jì)之外,還幫助實(shí)現(xiàn)告警策略,這依賴于服務(wù)異常的判定規(guī)則。默認(rèn)當(dāng)上報(bào)code為200時(shí),認(rèn)為成功。當(dāng)然,在大多數(shù)應(yīng)用中,如此簡單的判定規(guī)則通常難以勝任各類復(fù)雜的場景。所以go-monitor允許我們使用白名單的方式定制自己的一套規(guī)則:
// 注冊得到一個(gè)上報(bào)客戶端用于http服務(wù)質(zhì)量監(jiān)控
var httpReportClient = monitor.Register(monitor.ReportClientConfig {
Name: "http服務(wù)監(jiān)控",
CodeFeatureMap: map[int]monitor.CodeFeature {
0: {
Success: true,
Name: "成功",
},
10000: {
Success: false,
Name: "服務(wù)不可用",
},
}
})
CodeFeatureMap中允許聲明該狀態(tài)碼是否成功,并指定其名稱(使用在統(tǒng)計(jì)報(bào)告中),除此之外的code都將認(rèn)為失敗。
除了使用白名單機(jī)制來決斷code之外,go-monitor也提供了一個(gè)適應(yīng)性更強(qiáng)的方式去判定(優(yōu)先于CodeFeatureMap):
// 注冊得到一個(gè)上報(bào)客戶端用于http服務(wù)質(zhì)量監(jiān)控
var httpReportClient = monitor.Register(monitor.ReportClientConfig {
Name: "http服務(wù)監(jiān)控",
GetCodeFeature: func(code int) (success bool, name string) {
if code == 0 {
return true, "成功"
} else {
return false, "失敗"
}
},
})
在每個(gè)統(tǒng)計(jì)周期內(nèi),成功率達(dá)不到期望的值時(shí),該條目將被標(biāo)記,在連續(xù)標(biāo)記若干個(gè)統(tǒng)計(jì)周期之后,go-monitor便會觸發(fā)成功率不達(dá)標(biāo)告警,告警數(shù)據(jù)明確指明了具體的監(jiān)控服務(wù)和告警條目,并附帶連續(xù)被標(biāo)記為成功率不達(dá)標(biāo)的幾次統(tǒng)計(jì)數(shù)據(jù),默認(rèn)打印到控制臺,但同樣允許我們定制,我們可以按照自己的意愿處理,例如發(fā)送郵件通知相關(guān)人等:
// 注冊得到一個(gè)上報(bào)客戶端用于http服務(wù)質(zhì)量監(jiān)控
var httpReportClient = monitor.Register(monitor.ReportClientConfig {
Name: "http服務(wù)監(jiān)控",
AlertCaller: func(clientName string, interfaceName string, alertType monitor.AlertType, recentOutputData []monitor.OutPutData) {
// 處理相關(guān)告警
}
})
除了成功率不達(dá)標(biāo)告警,go-monitor也提供了耗時(shí)不達(dá)標(biāo)告警,精確到每個(gè)監(jiān)控條目都允許定制耗時(shí)達(dá)標(biāo)參數(shù)。
// 一個(gè)上報(bào)客戶端全局的耗時(shí)達(dá)標(biāo)值
var httpReportClient = monitor.Register(monitor.ReportClientConfig {
Name: "http服務(wù)監(jiān)控",
DefaultFastTime: 1000, // 設(shè)定http上報(bào)客戶端的默認(rèn)耗時(shí)達(dá)標(biāo)為1000ms內(nèi)
})
// 具體到一個(gè)條目的耗時(shí)標(biāo)準(zhǔn)
httpReportClient.AddEntryConfig("GET - /app/api/users", monitor.EntryConfig {
FastLessThan: 100, // 設(shè)定接口"GET - /app/api/users"的耗時(shí)達(dá)標(biāo)值為100ms以內(nèi)
})
go-monitor同時(shí)也支持服務(wù)質(zhì)量恢復(fù)通知,與告警的策略類似,當(dāng)出現(xiàn)告警狀態(tài)時(shí),后續(xù)若干次連續(xù)標(biāo)記為服務(wù)達(dá)標(biāo)的統(tǒng)計(jì)數(shù)據(jù)將觸發(fā)恢復(fù)通知,我們只需要定制RecoverCaller即可:
var httpReportClient = monitor.Register(monitor.ReportClientConfig {
Name: "http服務(wù)監(jiān)控",
RecoverCaller: func(clientName string, interfaceName string, alertType monitor.AlertType, recentOutputData []monitor.OutPutData) {
// 處理恢復(fù)通知
},
})
還有更多靈活的配置在go-monitor中得到支持,歡迎大家在使用中發(fā)現(xiàn)它們,更歡迎有意向的開發(fā)人參與到這份工作來,在設(shè)想中,希望go-monitor可以脫胎為一個(gè)完善的獨(dú)立服務(wù),以支持任何系統(tǒng)接入(包括前后端上報(bào)),并提供盡可能多的現(xiàn)成方案,例如統(tǒng)計(jì)數(shù)據(jù)輸出到數(shù)據(jù)庫,郵箱告警,接口通知等。在此拋磚引玉了:??https://github.com/blurooo/go-monitor??