使用Prometheus

動機

最近需要將流程的耗時接入可觀測系統(tǒng)邮府,方便后續(xù)優(yōu)化性能溉奕。為了統(tǒng)一技術(shù)棧加勤,決定使用prometheus來接入。特別的是鳄梅,我需要使用自定義的時間戳,由于PushGateway不支持自定義的時間戳粟焊,只能使用 pull 的方式了孙蒙。

整體流程

1、構(gòu)建 Collector马篮。
2浑测、注冊到 Register(也實現(xiàn)了 Gatherer 接口)歪玲,其中會調(diào)用 CollectorDescribe方法掷匠。
3、通過http請求到 /metrics,使用 promhttp.Handler 來處理請求讹语。
4、調(diào)用 RegisterGather方法短条,其中會調(diào)用 注冊的CollectorCollect方法才菠。
5、將 Metric 按名稱分組為 dto.MetricFamily可都,編碼后寫入 ResponseWriter蚓耽,返回給請求端。

實現(xiàn)細(xì)節(jié)

實現(xiàn) Collector

type timestampedCollector struct {
    bufferChan chan prometheus.Metric
    desc       *prometheus.Desc
}

func newTimestampedCollector(bufferSize int, desc *prometheus.Desc) *timestampedCollector {
    metrics := make(chan prometheus.Metric, bufferSize)
    return &timestampedCollector{
        bufferChan: metrics,
        desc:       desc,
    }
}

func (t *timestampedCollector) add(m prometheus.Metric) {
    logger.Infof("add metric:%s", util.ToJson(m.Desc()))
    t.bufferChan <- m
}

func (t *timestampedCollector) Describe(c chan<- *prometheus.Desc) {
    c <- t.desc
}

func (t *timestampedCollector) Collect(c chan<- prometheus.Metric) {
    for {
        select {
        case m := <-t.bufferChan:
            c <- m
        case <-time.After(time.Second * 1):
            return
        }
    }
}

prometheus中有2種Collector签杈,一種是uncheckedCollectors贤徒,還有一種是checkedCollectors,就是看你實現(xiàn)的CollectorDescribe方法中有沒有添加prometheus.Desc

注冊到Registry

構(gòu)建prometheus.Desc

var totalDesc = prometheus.NewDesc("emr_exclude_bootstrap_duration_seconds",
    "流程去掉執(zhí)行引導(dǎo)操作的時間",
    []string{"service", "region", "nodeCnt", "flowId"},
    nil)

NewDesc生成 prometheus.Desc的id踢涌,總的來說就是(fqName + constLabels的值列表) 合并起來的string的hash值

func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, constLabels Labels) *Desc {
        // 構(gòu)建 Desc
        ......
        labelValues := make([]string, 1, len(constLabels)+1)
    labelValues[0] = fqName
        for _, labelName := range labelNames {
        labelValues = append(labelValues, constLabels[labelName])
    }
        xxh := xxhash.New()
    for _, val := range labelValues {
        xxh.WriteString(val)
        xxh.Write(separatorByteSlice)
    }
    d.id = xxh.Sum64() // 生成 Desc 的 id
}

NewDesc生成 prometheus.Desc的dimHash睁壁,總的來說就是(fqName + constLabels的值列表) 合并起來的string的hash值

func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, constLabels Labels) *Desc {
        // 構(gòu)建 Desc
        ......
        labelNames := make([]string, 0, len(constLabels)+len(d.variableLabels.names))
        for labelName := range constLabels {
        labelNames = append(labelNames, labelName)
    }
      for _, label := range variableLabels {
        labelNames = append(labelNames, "$"+label)
    }
        xxh := xxhash.New()
    xxh.WriteString(help)
    xxh.Write(separatorByteSlice)
    for _, labelName := range labelNames {
        xxh.WriteString(labelName)
        xxh.Write(separatorByteSlice)
    }
    d.dimHash = xxh.Sum64()
}

注冊到prometheus

totalCollector = newTimestampedCollector(1000, totalDesc)
if err := handleErr(prometheus.Register(totalCollector)); err != nil {
    panic(err)
}

偽代碼如下

func (r *Registry) Register(c Collector) error {
        c.Describe(descChan)
        close(descChan)
        for desc := range descChan {
            1互捌、desc.id不能重復(fù)
            2、desc.dimHash + desc.fqName 不能重復(fù)
        }
}

使用 promhttp.Handler 來處理請求

func main() {
    http.Handle("/metrics", promhttp.Handler())
        // 暴露自己的指標(biāo)
    http.ListenAndServe(":13000", nil)
}

使用curl -XGET 'http://localhost:13000/metrics'來驗證metric是否暴露成功钳降。其中 http handler的鏈表結(jié)構(gòu)為:

InstrumentHandlerCounter -- HandlerForTransactional內(nèi)部方法

暴露指標(biāo)

promhttp.Handler最核心的就是調(diào)用 RegistryGather方法腌巾,其中會調(diào)用注冊的CollectorCollect方法來將指標(biāo)拉取出來铲觉,接著主要是2步
1撵幽、聚合

MetricFamily 按照Metric fqName分組礁击,相同Metric fqNameMetric會放入到 MetricFamily 的集合中

2、校驗

1哆窿、指標(biāo)名稱 + lable的名字 + label的值 + 時間戳 不能重復(fù)
2、label不能重復(fù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末测垛,一起剝皮案震驚了整個濱河市秧均,隨后出現(xiàn)的幾起案子号涯,更是在濱河造成了極大的恐慌,老刑警劉巖誉己,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件域蜗,死亡現(xiàn)場離奇詭異,居然都是意外死亡筑累,警方通過查閱死者的電腦和手機丝蹭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镜沽,“玉大人贱田,你說我怎么就攤上這事∈叨眨” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵扶平,是天一觀的道長蔬蕊。 經(jīng)常有香客問我,道長岸夯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任勉吻,我火速辦了婚禮旅赢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘短纵。我一直安慰自己僵控,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布悠就。 她就那樣靜靜地躺著充易,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盹靴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天宇立,我揣著相機與錄音自赔,去河邊找鬼。 笑死润脸,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的倒堕。 我是一名探鬼主播爆价,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼铭段!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起憔披,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤爸吮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蔗候,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體埂软,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡纫事,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年丽惶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钾唬。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡抡秆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出儒士,到底是詐尸還是另有隱情,我是刑警寧澤着撩,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布诅福,位于F島的核電站匾委,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏氓润。R本人自食惡果不足惜赂乐,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望咖气。 院中可真熱鬧挨措,春花似錦、人聲如沸采章。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悯舟。三九已至,卻和暖如春抵怎,著一層夾襖步出監(jiān)牢的瞬間奋救,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工反惕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留尝艘,地道東北人。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓姿染,卻偏偏與公主長得像背亥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子悬赏,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內(nèi)容