eBay邓明:dubbo-go 中 metrics 的设计
最近因為要在 Apache/dubbo-go(以下簡稱 dubbo-go )里面實現(xiàn)類似的這個 metrics 功能,于是花了很多時間去了解現(xiàn)在 Dubbo 里面的 metrics 是怎么實現(xiàn)的。該部分,實際上是被放在一個獨立的項目里面,即?metrics?。
總體上來說,Dubbo 的 metrics 是一個從設(shè)計到實現(xiàn)都非常優(yōu)秀的模塊,理論上來說,大部分的 Java 項目是可以直接使用 metrics 的。但也因為兼顧性能、擴展性等各種非功能特性,所以初看代碼會有種無從下手的感覺。
今天這篇文章將會從比較大的概念和抽象上討論一下 dubbo-go 中的 metrics 模塊的設(shè)計——實際上也就是 Dubbo 中的 metrics 的設(shè)計。因為我僅僅是將 Dubbo 里面的相關(guān)內(nèi)容在 dubbo-go 中復(fù)制一份。
目前 dubbo-go 的 metrics 剛剛開始起步,第一個 PR ,點擊這里。
總體設(shè)計
Metric
要想理解 metrics 的設(shè)計,首先要理解,我們需要收集一些什么數(shù)據(jù)。我們可以輕易列舉出來在 RPC 領(lǐng)域里面我們所關(guān)心的各種指標(biāo),諸如每個服務(wù)的調(diào)用次數(shù),響應(yīng)時間;如果更加細致一點,還有各種響應(yīng)時間的分布,平均響應(yīng)時間,999線……
但是上面列舉的是從數(shù)據(jù)的內(nèi)容上劃分的。 metrics 在抽象上,則是摒棄了這種劃分方式,而是結(jié)合了數(shù)據(jù)的特性和表現(xiàn)形式綜合劃分的。
從源碼里面很容易找到這種劃分的抽象。
metrics 設(shè)計了 Metric 接口作為所有數(shù)據(jù)的頂級抽象:
在 Dubbo 里面,其比較關(guān)鍵的子接口是:
為了大家理解,這里我抄一下這些接口的用途:
- Gauge: 一種實時數(shù)據(jù)的度量,反映的是瞬態(tài)的數(shù)據(jù),不具有累加性,例如當(dāng)前 JVM 的線程數(shù);
- Counter: 計數(shù)器型指標(biāo),適用于記錄調(diào)用總量等類型的數(shù)據(jù);
- Histogram : 直方分布指標(biāo),例如,可以用于統(tǒng)計某個接口的響應(yīng)時間,可以展示 50%, 70%, 90% 的請求響應(yīng)時間落在哪個區(qū)間內(nèi);
- Meter: 一種用于度量一段時間內(nèi)吞吐率的計量器。例如,一分鐘內(nèi),五分鐘內(nèi),十五分鐘內(nèi)的qps指標(biāo);
- Timer: Timer相當(dāng)于Meter+Histogram的組合,同時統(tǒng)計一段代碼,一個方法的qps,以及執(zhí)行時間的分布情況;
目前 dubbo-go 只實現(xiàn)了 FastCompass ,它也是 Metric 的子類:
這個接口功能很簡單,就是用于收集一段時間之內(nèi)的 subCategory 執(zhí)行的次數(shù)和響應(yīng)時間。 subCategory 是一個比較寬泛的概念,無論是在 Dubbo 還是在 dubbo-go 里面,一個典型的 subCategory 就會是某個服務(wù)。
這里的設(shè)計要點在于,它是從什么角度上去做這些數(shù)據(jù)的抽象的。
很多人在開發(fā)這種采集數(shù)據(jù)的相關(guān)系統(tǒng)或者功能的時候,最容易陷入的就是從數(shù)據(jù)內(nèi)容上做抽象,例如抽象一個接口,里面的方法就是獲得服務(wù)的調(diào)用次數(shù)或者平均響應(yīng)時間等。
這種抽象并非不可以,尤其是在簡單系統(tǒng)里面,還非常好用。唯獨在通用性和擴展性上要差很多。
MetricManager
在我們定義了 Metric 之后,很容易就想到,我要有一個東西來管理這些 Metric 。這就是 MetricManager ——對應(yīng)到 Dubbo 里面的 IMetricManager 接口。
MetricManager 接口目前在 dubbo-go 里面還很簡單:
本質(zhì)上來說,我在前面提到的那些 Metric 的子類,都可以從這個 MetricManager 里面拿到。它是對外的唯一入口。
因此無論是上報采集的數(shù)據(jù),還是某些功能要用這些采集的數(shù)據(jù),最重要的就是獲得一個 MetricManager 的實例。例如我們最近正在開發(fā)的接入 Prometheus 就是拿到這個 MetriManger 實例,而后從里面拿到 FastCompass 的實例,而后采集這些數(shù)據(jù):
MetricRegistry
MetricRegistry 是一個對 Metric 集合的抽象。 MetricManager 的默認實現(xiàn)里面,就是使用 MetricRegistry 來管理 Metric 的:
所以,本質(zhì)上它就是提供了一些注冊 Metric 然后再從里面撈出來的方法。
于是,這就有一個問題了:為什么我在有了 MetricManager 之后,還有有一個MetricRegistry?似乎這兩個功能有些重疊?
答案大概是兩個方面:
1、除了管理所有的 Metric 之外,還承擔(dān)著額外的功能,這些功能典型的就是 IsEnabled 。而實際上,在未來我們會賦予它管理生命周期的責(zé)任,比如說在 Dubbo 里面,該接口就還有一個 clear 方法;
2、 metrics 里面還有一個 group 的概念,而這只能由 MetricManager 來進行管理,至少交給 MetricRegistry 是不合適的。
metrics 的 group 說起來也很簡單。比如在 Dubbo 框架里面采集的數(shù)據(jù),都會歸屬于 Dubbo 這個 group 。也就是說,如果我想將非框架層面采集的數(shù)據(jù)——比如純粹的業(yè)務(wù)數(shù)據(jù)——分隔出來,就可以借用一個 business group 。又或者我采集到的機器自身的數(shù)據(jù),可以將其歸類到 system 這個 group 下。
所以 MetricManger 和 MetricRegistry 的關(guān)系是:
Clock
Clock 抽象是一個初看沒什么用,再看會覺得其抽象的很好。Clock 里面就兩個方法:
一個是獲得時間戳,另外一個則是獲得時間周期(Tick)。比如通常采集數(shù)據(jù)可能是每一分鐘采集一次,所以你得知道現(xiàn)在處在哪個時間周期里面。Clock 就提供了這種抽象。
很多人在實現(xiàn)自己的這種 metrics 的框架的時候,大多數(shù)都是直接使用系統(tǒng)的時鐘,也就是系統(tǒng)的時間戳。于是所有的 Metic 在采集數(shù)據(jù)或者上報數(shù)據(jù)的時候,不得不自己去處理這種時鐘方面的問題。
這樣不同的 Metric 之間就很難做到時鐘的同步。比如說可能在某個 Metric1 里面,采集周期是當(dāng)前這一分鐘,而 Metric2 是當(dāng)前這一分鐘的第三十秒到下一分鐘的第三十秒。雖然它們都是一分鐘采集一次,但是這個周期就對不上了。
另外一個有意思的地方在于,Clock 提供的這種抽象,允許我們不必真的按照現(xiàn)實時間的時間戳來處理。比如說,可以考慮按照 CPU 的運行時間來設(shè)計 Clock 的實現(xiàn)。
例子
就用這一次 PR 的內(nèi)容來展示一下這個設(shè)計。
在 dubbo-go 里面這次實現(xiàn)了 metricsFilter ,它主要就是收集調(diào)用次數(shù)和響應(yīng)時間,其核心是:
report 其實就是把 metrics reports 給 MetricManager :
所以,這里面可以看出來,如果我們要收集什么數(shù)據(jù),也是要先獲得 MetricManager 的實例。
FastCompass 的實現(xiàn)里面會將這一次調(diào)用的服務(wù)及其響應(yīng)時間保存下來。而后在需要的時候再取出來。
所謂的需要的時候,通常就是上報給監(jiān)控系統(tǒng)的時候。比如前面的提到的上報給 Prometheus。
所以這個流程可以抽象表達為:
這是一個更加寬泛的抽象。也就是意味著,我們除了可以從這個 metricFilter 里面收集數(shù)據(jù),也可以從自身的業(yè)務(wù)里面去收集數(shù)據(jù)。比如說統(tǒng)計某段代碼的執(zhí)行時間,一樣可以使用 FastCompass 。
而除了 Prometheus ,如果用戶自己的公司里面有監(jiān)控框架,那么他們可以自己實現(xiàn)自己的上報邏輯。而上報的數(shù)據(jù)則只需要拿到 MetricManager 實例就能拿到。
總結(jié)
本質(zhì)上來說,整個 metrics 可以看做是一個巨大無比的 provider-conumer 模型。
不同的數(shù)據(jù)會在不同的地方和不同時間點上被采集。有些人在讀這些源碼的時候會有點困惑,就是這些數(shù)據(jù)什么時間點會被采集呢?
它們只會在兩類時間點采集:
1、實時采集。如我上面舉例的 metricsFilter ,一次調(diào)用過來,它的數(shù)據(jù)就被采集了;
2、另外一個則是如同 Prometheus 。每次 Prometheus 觸發(fā)了 collect 方法,那么它就會把每種(如 Meter, Gauge )里面的數(shù)據(jù)收集過來,然后上報,可以稱為是定時采集;
Dubbo 里面采集了非常多的數(shù)據(jù):
這些具體的實現(xiàn),我就不一一討論了,大家有興趣可以去看看源碼。這些數(shù)據(jù),也是我們 dubbo-go 后面要陸續(xù)實現(xiàn)的東西,歡迎大家持續(xù)關(guān)注,或者來貢獻代碼。
原文鏈接
本文為阿里云原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的eBay邓明:dubbo-go 中 metrics 的设计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 立根融资租赁:内部系统平台上云
- 下一篇: 瓜子二手车在 Dubbo 版本升级、多机