天天看點

eBay鄧明:dubbo-go 中 metrics 的設計

最近因為要在 Apache/dubbo-go(以下簡稱 dubbo-go )裡面實作類似的這個 metrics 功能,于是花了很多時間去了解現在 Dubbo 裡面的 metrics 是怎麼實作的。該部分,實際上是被放在一個獨立的項目裡面,即 metrics

總體上來說,Dubbo 的 metrics 是一個從設計到實作都非常優秀的子產品,理論上來說,大部分的 Java 項目是可以直接使用 metrics 的。但也因為兼顧性能、擴充性等各種非功能特性,是以初看代碼會有種無從下手的感覺。

今天這篇文章将會從比較大的概念和抽象上讨論一下 dubbo-go 中的 metrics 子產品的設計——實際上也就是 Dubbo 中的 metrics 的設計。因為我僅僅是将 Dubbo 裡面的相關内容在 dubbo-go 中複制一份。

目前 dubbo-go 的 metrics 剛剛開始起步,第一個 PR ,點選

這裡

總體設計

Metric

要想了解 metrics 的設計,首先要了解,我們需要收集一些什麼資料。我們可以輕易列舉出來在 RPC 領域裡面我們所關心的各種名額,諸如每個服務的調用次數,響應時間;如果更加細緻一點,還有各種響應時間的分布,平均響應時間,999線……

但是上面列舉的是從資料的内容上劃分的。 metrics 在抽象上,則是摒棄了這種劃分方式,而是結合了資料的特性和表現形式綜合劃分的。

從源碼裡面很容易找到這種劃分的抽象。

eBay鄧明:dubbo-go 中 metrics 的設計

metrics 設計了 Metric 接口作為所有資料的頂級抽象:

在 Dubbo 裡面,其比較關鍵的子接口是:

eBay鄧明:dubbo-go 中 metrics 的設計

為了大家了解,這裡我抄一下這些接口的用途:

  • Gauge: 一種實時資料的度量,反映的是瞬态的資料,不具有累加性,例如目前 JVM 的線程數;
  • Counter: 計數器型名額,适用于記錄調用總量等類型的資料;
  • Histogram : 直方分布名額,例如,可以用于統計某個接口的響應時間,可以展示 50%, 70%, 90% 的請求響應時間落在哪個區間内;
  • Meter: 一種用于度量一段時間内吞吐率的計量器。例如,一分鐘内,五分鐘内,十五分鐘内的qps名額;
  • Timer: Timer相當于Meter+Histogram的組合,同時統計一段代碼,一個方法的qps,以及執行時間的分布情況;

目前 dubbo-go 隻實作了 FastCompass ,它也是 Metric 的子類:

eBay鄧明:dubbo-go 中 metrics 的設計

這個接口功能很簡單,就是用于收集一段時間之内的 subCategory 執行的次數和響應時間。 subCategory 是一個比較寬泛的概念,無論是在 Dubbo 還是在 dubbo-go 裡面,一個典型的 subCategory 就會是某個服務。

這裡的設計要點在于,它是從什麼角度上去做這些資料的抽象的。

很多人在開發這種采集資料的相關系統或者功能的時候,最容易陷入的就是從資料内容上做抽象,例如抽象一個接口,裡面的方法就是獲得服務的調用次數或者平均響應時間等。

這種抽象并非不可以,尤其是在簡單系統裡面,還非常好用。唯獨在通用性和擴充性上要差很多。

MetricManager

在我們定義了 Metric 之後,很容易就想到,我要有一個東西來管理這些 Metric 。這就是 MetricManager ——對應到 Dubbo 裡面的 IMetricManager 接口。

MetricManager 接口目前在 dubbo-go 裡面還很簡單:

eBay鄧明:dubbo-go 中 metrics 的設計

本質上來說,我在前面提到的那些 Metric 的子類,都可以從這個 MetricManager 裡面拿到。它是對外的唯一入口。

是以無論是上報采集的資料,還是某些功能要用這些采集的資料,最重要的就是獲得一個 MetricManager 的執行個體。例如我們最近正在開發的接入 Prometheus 就是拿到這個 MetriManger 執行個體,而後從裡面拿到 FastCompass 的執行個體,而後采集這些資料:

eBay鄧明:dubbo-go 中 metrics 的設計

MetricRegistry

MetricRegistry 是一個對 Metric 集合的抽象。 MetricManager 的預設實作裡面,就是使用 MetricRegistry 來管理 Metric 的:

eBay鄧明:dubbo-go 中 metrics 的設計

是以,本質上它就是提供了一些注冊 Metric 然後再從裡面撈出來的方法。

于是,這就有一個問題了:為什麼我在有了 MetricManager 之後,還有有一個MetricRegistry?似乎這兩個功能有些重疊?

答案大概是兩個方面:

1、除了管理所有的 Metric 之外,還承擔着額外的功能,這些功能典型的就是 IsEnabled 。而實際上,在未來我們會賦予它管理生命周期的責任,比如說在 Dubbo 裡面,該接口就還有一個 clear 方法;

2、 metrics 裡面還有一個 group 的概念,而這隻能由 MetricManager 來進行管理,至少交給 MetricRegistry 是不合适的。

metrics 的 group 說起來也很簡單。比如在 Dubbo 架構裡面采集的資料,都會歸屬于 Dubbo 這個 group 。也就是說,如果我想将非架構層面采集的資料——比如純粹的業務資料——分隔出來,就可以借用一個 business group 。又或者我采集到的機器自身的資料,可以将其歸類到 system 這個 group 下。

是以 MetricManger 和 MetricRegistry 的關系是:

eBay鄧明:dubbo-go 中 metrics 的設計

Clock

Clock 抽象是一個初看沒什麼用,再看會覺得其抽象的很好。Clock 裡面就兩個方法:

eBay鄧明:dubbo-go 中 metrics 的設計

一個是獲得時間戳,另外一個則是獲得時間周期(Tick)。比如通常采集資料可能是每一分鐘采集一次,是以你得知道現在處在哪個時間周期裡面。Clock 就提供了這種抽象。

很多人在實作自己的這種 metrics 的架構的時候,大多數都是直接使用系統的時鐘,也就是系統的時間戳。于是所有的 Metic 在采集資料或者上報資料的時候,不得不自己去處理這種時鐘方面的問題。

這樣不同的 Metric 之間就很難做到時鐘的同步。比如說可能在某個 Metric1 裡面,采集周期是目前這一分鐘,而 Metric2 是目前這一分鐘的第三十秒到下一分鐘的第三十秒。雖然它們都是一分鐘采集一次,但是這個周期就對不上了。

另外一個有意思的地方在于,Clock 提供的這種抽象,允許我們不必真的按照現實時間的時間戳來處理。比如說,可以考慮按照 CPU 的運作時間來設計 Clock 的實作。

例子

就用這一次 PR 的内容來展示一下這個設計。

在 dubbo-go 裡面這次實作了 metricsFilter ,它主要就是收集調用次數和響應時間,其核心是:

eBay鄧明:dubbo-go 中 metrics 的設計

report 其實就是把 metrics reports 給 MetricManager :

eBay鄧明:dubbo-go 中 metrics 的設計

是以,這裡面可以看出來,如果我們要收集什麼資料,也是要先獲得 MetricManager 的執行個體。

FastCompass 的實作裡面會将這一次調用的服務及其響應時間儲存下來。而後在需要的時候再取出來。

所謂的需要的時候,通常就是上報給監控系統的時候。比如前面的提到的上報給 Prometheus。

是以這個流程可以抽象表達為:

eBay鄧明:dubbo-go 中 metrics 的設計

這是一個更加寬泛的抽象。也就是意味着,我們除了可以從這個 metricFilter 裡面收集資料,也可以從自身的業務裡面去收集資料。比如說統計某段代碼的執行時間,一樣可以使用 FastCompass 。

而除了 Prometheus ,如果使用者自己的公司裡面有監控架構,那麼他們可以自己實作自己的上報邏輯。而上報的資料則隻需要拿到 MetricManager 執行個體就能拿到。

總結

本質上來說,整個 metrics 可以看做是一個巨大無比的 provider-conumer 模型。

不同的資料會在不同的地方和不同時間點上被采集。有些人在讀這些源碼的時候會有點困惑,就是這些資料什麼時間點會被采集呢?

它們隻會在兩類時間點采集:

1、實時采集。如我上面舉例的 metricsFilter ,一次調用過來,它的資料就被采集了;

2、另外一個則是如同 Prometheus 。每次 Prometheus 觸發了 collect 方法,那麼它就會把每種(如 Meter, Gauge )裡面的資料收集過來,然後上報,可以稱為是定時采集;

Dubbo 裡面采集了非常多的資料:

eBay鄧明:dubbo-go 中 metrics 的設計

這些具體的實作,我就不一一讨論了,大家有興趣可以去看看源碼。這些資料,也是我們 dubbo-go 後面要陸續實作的東西,歡迎大家持續關注,或者來貢獻代碼。

作者資訊:鄧明,畢業于南京大學,就職于 eBay Payment 部門,負責退款業務開發。