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

最近由於要在 Apache/dubbo-go(如下簡稱 dubbo-go )裏面實現相似的這個 metrics 功能,因而花了不少時間去了解如今 Dubbo 裏面的 metrics 是怎麼實現的。該部分,其實是被放在一個獨立的項目裏面,即 metrics 。git

整體上來講,Dubbo 的 metrics 是一個從設計到實現都很是優秀的模塊,理論上來講,大部分的 Java 項目是能夠直接使用 metrics 的。但也由於兼顧性能、擴展性等各類非功能特性,因此初看代碼會有種無從下手的感受。github

今天這篇文章將會從比較大的概念和抽象上討論一下 dubbo-go 中的 metrics 模塊的設計——實際上也就是 Dubbo 中的 metrics 的設計。由於我僅僅是將 Dubbo 裏面的相關內容在 dubbo-go 中複製一份。apache

目前 dubbo-go 的 metrics 剛剛開始起步,第一個 PR ,點擊這裏框架

整體設計

Metric

要想理解 metrics 的設計,首先要理解,咱們須要收集一些什麼數據。咱們能夠輕易列舉出來在 RPC 領域裏面咱們所關心的各類指標,諸如每一個服務的調用次數,響應時間;若是更加細緻一點,還有各類響應時間的分佈,平均響應時間,999線……ide

可是上面列舉的是從數據的內容上劃分的。 metrics 在抽象上,則是摒棄了這種劃分方式,而是結合了數據的特性和表現形式綜合劃分的。性能

從源碼裏面很容易找到這種劃分的抽象。阿里雲

metrics 設計了 Metric 接口做爲全部數據的頂級抽象:url

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

爲了你們理解,這裏我抄一下這些接口的用途:線程

  • Gauge: 一種實時數據的度量,反映的是瞬態的數據,不具備累加性,例如當前 JVM 的線程數;
  • Counter: 計數器型指標,適用於記錄調用總量等類型的數據;
  • Histogram : 直方分佈指標,例如,能夠用於統計某個接口的響應時間,能夠展現 50%, 70%, 90% 的請求響應時間落在哪一個區間內;
  • Meter: 一種用於度量一段時間內吞吐率的計量器。例如,一分鐘內,五分鐘內,十五分鐘內的qps指標;
  • Timer: Timer至關於Meter+Histogram的組合,同時統計一段代碼,一個方法的qps,以及執行時間的分佈狀況;

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

這個接口功能很簡單,就是用於收集一段時間以內的 subCategory 執行的次數和響應時間。 subCategory 是一個比較寬泛的概念,不管是在 Dubbo 仍是在 dubbo-go 裏面,一個典型的 subCategory 就會是某個服務。

這裏的設計要點在於,它是從什麼角度上去作這些數據的抽象的。

不少人在開發這種採集數據的相關係統或者功能的時候,最容易陷入的就是從數據內容上作抽象,例如抽象一個接口,裏面的方法就是得到服務的調用次數或者平均響應時間等。

這種抽象並不是不能夠,尤爲是在簡單系統裏面,還很是好用。惟獨在通用性和擴展性上要差不少。

MetricManager

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

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

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

所以不管是上報採集的數據,仍是某些功能要用這些採集的數據,最重要的就是得到一個 MetricManager 的實例。例如咱們最近正在開發的接入 Prometheus 就是拿到這個 MetriManger 實例,然後從裏面拿到 FastCompass 的實例,然後採集這些數據:

MetricRegistry

MetricRegistry 是一個對 Metric 集合的抽象。 MetricManager 的默認實現裏面,就是使用 MetricRegistry 來管理 Metric 的:

因此,本質上它就是提供了一些註冊 Metric 而後再從裏面撈出來的方法。

因而,這就有一個問題了:爲何我在有了 MetricManager 以後,還有有一個MetricRegistry?彷佛這兩個功能有些重疊?

答案大概是兩個方面:

一、除了管理全部的 Metric 以外,還承擔着額外的功能,這些功能典型的就是 IsEnabled 。而實際上,在將來咱們會賦予它管理生命週期的責任,好比說在 Dubbo 裏面,該接口就還有一個 clear 方法;
二、 metrics 裏面還有一個 group 的概念,而這隻能由 MetricManager 來進行管理,至少交給 MetricRegistry 是不合適的。

metrics 的 group 提及來也很簡單。好比在 Dubbo 框架裏面採集的數據,都會歸屬於 Dubbo 這個 group 。也就是說,若是我想將非框架層面採集的數據——好比純粹的業務數據——分隔出來,就能夠借用一個 business group 。又或者我採集到的機器自身的數據,能夠將其歸類到 system 這個 group 下。

因此 MetricManger 和 MetricRegistry 的關係是:

Clock

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

一個是得到時間戳,另一個則是得到時間週期(Tick)。好比一般採集數據多是每一分鐘採集一次,因此你得知道如今處在哪一個時間週期裏面。Clock 就提供了這種抽象。

不少人在實現本身的這種 metrics 的框架的時候,大多數都是直接使用系統的時鐘,也就是系統的時間戳。因而全部的 Metic 在採集數據或者上報數據的時候,不得不本身去處理這種時鐘方面的問題。

這樣不一樣的 Metric 之間就很難作到時鐘的同步。好比說可能在某個 Metric1 裏面,採集週期是當前這一分鐘,而 Metric2 是當前這一分鐘的第三十秒到下一分鐘的第三十秒。雖然它們都是一分鐘採集一次,可是這個週期就對不上了。

另一個有意思的地方在於,Clock 提供的這種抽象,容許咱們沒必要真的按照現實時間的時間戳來處理。好比說,能夠考慮按照 CPU 的運行時間來設計 Clock 的實現。

例子

就用這一次 PR 的內容來展現一下這個設計。

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

report 其實就是把 metrics reports 給 MetricManager :

因此,這裏面能夠看出來,若是咱們要收集什麼數據,也是要先得到 MetricManager 的實例。

FastCompass 的實現裏面會將這一次調用的服務及其響應時間保存下來。然後在須要的時候再取出來。

所謂的須要的時候,一般就是上報給監控系統的時候。好比前面的提到的上報給 Prometheus。

因此這個流程能夠抽象表達爲:

這是一個更加寬泛的抽象。也就是意味着,咱們除了能夠從這個 metricFilter 裏面收集數據,也能夠從自身的業務裏面去收集數據。好比說統計某段代碼的執行時間,同樣可使用 FastCompass 。

而除了 Prometheus ,若是用戶本身的公司裏面有監控框架,那麼他們能夠本身實現本身的上報邏輯。而上報的數據則只須要拿到 MetricManager 實例就能拿到。

總結

本質上來講,整個 metrics 能夠看作是一個巨大無比的 provider-conumer 模型。

不一樣的數據會在不一樣的地方和不一樣時間點上被採集。有些人在讀這些源碼的時候會有點困惑,就是這些數據什麼時間點會被採集呢?

它們只會在兩類時間點採集:

一、實時採集。如我上面舉例的 metricsFilter ,一次調用過來,它的數據就被採集了;
二、另一個則是如同 Prometheus 。每次 Prometheus 觸發了 collect 方法,那麼它就會把每種(如 Meter, Gauge )裏面的數據收集過來,而後上報,能夠稱爲是定時採集;

Dubbo 裏面採集了很是多的數據:

這些具體的實現,我就不一一討論了,你們有興趣能夠去看看源碼。這些數據,也是咱們 dubbo-go 後面要陸續實現的東西,歡迎你們持續關注,或者來貢獻代碼。

做者信息:鄧明,畢業於南京大學,就任於 eBay Payment 部門,負責退款業務開發。


本文做者:鄧明

閱讀原文

本文爲阿里雲內容,未經容許不得轉載。

相關文章
相關標籤/搜索