摘要:眾所周知,負(fù)責(zé)收集并聚合測量值。每個都有一個,該值的解釋方式依賴于。計時器的一大好處在于,你可以得到平均值總值計數(shù)值和上下限值。給傳一個數(shù)字,它會不經(jīng)處理地將該數(shù)字傳到后端。由三部分組成監(jiān)聽時間序列的數(shù)據(jù)的后臺程序。
眾所周知,StatsD 負(fù)責(zé)收集并聚合測量值。之后,它會將數(shù)據(jù)傳給 Graphite,后者以時間序列為依據(jù)存儲數(shù)據(jù),并繪制圖表。但是,我們不知道,基于 http 訪問的圖表在展示時,是基于每秒鐘的請求數(shù),每次留存的平均請求數(shù)還是其它。讓我們就以此為目標(biāo),來一探究竟吧!本文系 OneAPM 工程師編譯整理。
StatsD
為了全面了解 StatsD 的工作原理,我閱讀了它的源碼。之前我就耳聞 StatsD 是一種簡單的應(yīng)用,但讀過源碼后才發(fā)現(xiàn)它竟如此簡單!在主腳本文件只有300多行代碼,而 Graphite 的后端代碼只有150行左右。
在這個文檔中,列出了一些需要理解的 StatsD 概念。
Buckets
當(dāng)一個 Whisper 文件被創(chuàng)建,它會有一個不會改變的固定大小。在這個文件中可能有多個 "buckets" 對應(yīng)于不同分別率的數(shù)據(jù)點,每個 bucket 也有一個保留屬性指明數(shù)據(jù)點應(yīng)該在 bucket 中應(yīng)該被保留的時間長度,Whisper 執(zhí)行一些簡單的數(shù)學(xué)計算來計算出多少數(shù)據(jù)點會被實際保存在每個 bucket 中。
Values
每個 stat 都有一個 value,該值的解釋方式依賴于 modifier。通常,values 應(yīng)該是整數(shù)。
Flush Interval
在 flush interval (沖洗間隔,通常為10秒)超時之后,stats 會聚集起來,傳送到上游的后端服務(wù)。
測量值類別計數(shù)器
計數(shù)器很簡單。它會給 bucket 加 value,并存儲在內(nèi)存中,直到 flush interval 超時。
讓我們看一下生成計數(shù)器 stats 的源碼,該 stats 會被推送到后端。
for (key in counters) { var value = counters[key]; var valuePerSecond = value / (flushInterval / 1000); // calculate "per second" rate statString += "stats."+ key + " " + valuePerSecond + " " + ts + " "; statString += "stats_counts." + key + " " + value + " " + ts + " "; numStats += 1; }
首先,StatsD 會迭代它收到的所有計數(shù)器,對每個計數(shù)器它都會分配兩個變量。一個變量用于存儲計數(shù)器的 value,另一個存儲 per-second value。之后,它會將 values 加至 statString,同時增加 numStats 變量的值。
如果你使用默認(rèn)的 flush interval(10秒),并在每個間隔通過某個計數(shù)器給 StatsD 傳送7個增量。則計時器的 value 為 7,而 per-second value 為 0.7。
計時器
計時器用于收集數(shù)字。他們不必要包含時間值。你可以收集某個存儲器中的字節(jié)數(shù)、對象數(shù)或任意數(shù)字。計時器的一大好處在于,你可以得到平均值、總值、計數(shù)值和上下限值。給 StatsD 設(shè)置一個計時器,就能在數(shù)據(jù)傳送給 Graphite 之前自動計算這些量。
計時器的源碼比計數(shù)器的源碼要稍微復(fù)雜一些。
for (key in timers) { if (timers[key].length > 0) { var values = timers[key].sort(function (a,b) { return a-b; }); var count = values.length; var min = values[0]; var max = values[count - 1]; var cumulativeValues = [min]; for (var i = 1; i < count; i++) { cumulativeValues.push(values[i] + cumulativeValues[i-1]); } var sum = min; var mean = min; var maxAtThreshold = max; var message = ""; var key2; for (key2 in pctThreshold) { var pct = pctThreshold[key2]; if (count > 1) { var thresholdIndex = Math.round(((100 - pct) / 100) * count); var numInThreshold = count - thresholdIndex; maxAtThreshold = values[numInThreshold - 1]; sum = cumulativeValues[numInThreshold - 1]; mean = sum / numInThreshold; } var clean_pct = "" + pct; clean_pct.replace(".", "_"); message += "stats.timers." + key + ".mean_" + clean_pct + " " + mean + " " + ts + " "; message += "stats.timers." + key + ".upper_" + clean_pct + " " + maxAtThreshold + " " + ts + " "; message += "stats.timers." + key + ".sum_" + clean_pct + " " + sum + " " + ts + " "; } sum = cumulativeValues[count-1]; mean = sum / count; message += "stats.timers." + key + ".upper " + max + " " + ts + " "; message += "stats.timers." + key + ".lower " + min + " " + ts + " "; message += "stats.timers." + key + ".count " + count + " " + ts + " "; message += "stats.timers." + key + ".sum " + sum + " " + ts + " "; message += "stats.timers." + key + ".mean " + mean + " " + ts + " "; statString += message; numStats += 1; } }
如果在默認(rèn)的 flush interval 內(nèi),你將下列計數(shù)器 values 傳給 StatsD:
450
120
553
994
334
844
675
496
StatsD 將會計數(shù)下面的 values:
mean_90 496
upper_90 844
sum_90 3472
upper 994
lower 120
count 8
sum 4466
mean 558.25
Gauges
一個 guage 代表著時間段內(nèi)某點的任意 vaule,是 StatsD 中最簡單的類型。你可以給它傳任意值,它會傳給后端。
Gauge stats 的源碼只有短短四行。
for (key in gauges) { statString += "stats.gauges." + key + " " + gauges[key] + " " + ts + " "; numStats += 1; }
給 StatsD 傳一個數(shù)字,它會不經(jīng)處理地將該數(shù)字傳到后端。值得注意的是,在一個 flush interval 內(nèi),只有 gauge 最后的值會傳送到后端。因此,如果你在一個 flush interval 內(nèi),將下面的 gauge 值傳給 StatsD:
643
754
583
會傳到后端的值只有583而已。該 gauge 的值會一直存儲在內(nèi)存中,直到 flush interval 結(jié)束才傳值。
Graphite現(xiàn)在,我們已經(jīng)了解數(shù)據(jù)是怎樣從 StatsD 傳出來的,讓我們看看它在 Graphite 里是如何存儲并處理的。
總覽在 Graphite 文檔里,我們可以找到 Graphite 概覽,此概覽總結(jié)了 Graphite 的兩個要點:
Graphite 存儲數(shù)值型帶有時間序列的數(shù)據(jù)。
Graphite 按需繪制圖表。
Graphite 由三部分組成:
carbon :監(jiān)聽時間序列的數(shù)據(jù)的后臺程序。
whisper:一個簡單的數(shù)據(jù)庫庫,用來存儲時間序列數(shù)據(jù)。
webapp: Django webapp,使用 Cairo 來根據(jù)需要呈現(xiàn)圖形。
Graphite 當(dāng)做時間序列數(shù)據(jù)的格式如下:
存儲方案
Graphite 采用可配置的存儲方案用以定義所存數(shù)據(jù)的留存率。它會給數(shù)據(jù)路徑匹配特定的模式,從而決定所存數(shù)據(jù)的頻率和來歷。
以下配置示例截取自 StatsD 文檔。
[stats] pattern = ^stats..* retentions = 10:2160,60:10080,600:262974
該示例表明,匹配上述樣式的數(shù)據(jù)都會套用這些留存。留存的格式為 frequency: history。所以,該配置允許我們將10秒鐘的數(shù)據(jù)存儲6個小時,1分鐘的數(shù)據(jù)存儲1周,10分鐘的數(shù)據(jù)存儲5年。
在 Graphite 顯示計時器了解了這么多,我們來看看一個簡單的 ruby 腳本,該腳本能收集 HTTP 請求的時間。
#!/usr/bin/env ruby require "rubygems" if RUBY_VERSION < "1.9.0" require "./statsdclient.rb" require "typhoeus" Statsd.host = "localhost" Statsd.port = 8125 def to_ms time (1000 * time).to_i end while true start_time = Time.now.to_f resp = Typhoeus::Request.get "http://www.example.org/system/information" end_time = Time.now.to_f elapsed_time = (1000 * end_time) - (to_ms start_time) response_time = to_ms resp.time start_transfer_time = to_ms resp.start_transfer_time app_connect_time = to_ms resp.app_connect_time pretransfer_time = to_ms resp.pretransfer_time connect_time = to_ms resp.connect_time name_lookup_time = to_ms resp.name_lookup_time Statsd.timing("http_request.elapsed_time", elapsed_time) Statsd.timing("http_request.response_time", response_time) Statsd.timing("http_request.start_transfer_time", start_transfer_time) Statsd.timing("http_request.app_connect_time", app_connect_time) Statsd.timing("http_request.pretransfer_time", pretransfer_time) Statsd.timing("http_request.connect_time", connect_time) Statsd.timing("http_request.name_lookup_time", name_lookup_time) sleep 10 end
讓我們看看該數(shù)據(jù)生成的 Graphite 圖。該數(shù)據(jù)來自 2 分鐘前,而 elapsed_time 則來自前面的腳本。
圖像生成
Render URL
下面圖片的 Render URL
/render/?width=586&height=308&from=-2minutes&target=stats.timers.http_request.elapsed_time.sum
Graphite 生成的圖片
該圖片簡單地描繪了 http 請求在一段時間內(nèi)的 elapsed_time 值。
JSON-data
Render URL
下面 JSON-data 的 Render URL
/render/?width=586&height=308&from=-2minutes&target=stats.timers.http_request.elapsed_time.sum&format=json
來自 Graphite 的 JSON-output
在下面的結(jié)果中,我們可以查看來自 Graphite 的源數(shù)據(jù)。這些數(shù)據(jù)來自12個不同的數(shù)據(jù)點,也即 StatsD 10 秒 flush internal 的兩分鐘。Graphite 繪制數(shù)據(jù)就是如此簡單。
此外,借助 JSONLint,JSON-data 的數(shù)據(jù)顯示更加美觀。
[ { "target": "stats.timers.http_request.elapsed_time.sum", "datapoints": [ [ 53.449951171875, 1343038130 ], [ 50.3916015625, 1343038140 ], [ 50.1357421875, 1343038150 ], [ 39.601806640625, 1343038160 ], [ 41.5263671875, 1343038170 ], [ 34.3974609375, 1343038180 ], [ 36.3818359375, 1343038190 ], [ 35.009033203125, 1343038200 ], [ 37.0087890625, 1343038210 ], [ 38.486572265625, 1343038220 ], [ 45.66064453125, 1343038230 ], [ null, 1343038240 ] ] } ]在 Graphite 繪制 gauge 圖像
下面的簡單腳本能將 gauge 傳送給 StatsD,模擬用戶注冊的過程。
#!/usr/bin/env ruby require "./statsdclient.rb" Statsd.host = "localhost" Statsd.port = 8125 user_registrations = 1 while true user_registrations += Random.rand 128 Statsd.gauge("user_registrations", user_registrations) sleep 10 end
圖像顯示——用戶注冊數(shù)量
Render URL
下面圖片的 Render URL
/render/?width=586&height=308&from=-20minutes&target=stats.gauges.user_registrations
來自 Graphite 的圖片
另一個簡單的圖片,展示總的注冊數(shù)。
圖片顯示——每分鐘的用戶注冊數(shù)
使用 Graphite 的衍生函數(shù),可以獲得每分鐘的用戶注冊數(shù)量。
Render URL
下面圖片的 Render URL
/render/?width=586&height=308&from=-20minutes&target=derivative(stats.gauges.user_registrations)
來自 Graphite 的圖片
該圖片所用的數(shù)據(jù)跟之前的圖片一致,但是使用了衍生函數(shù)從而顯示每分鐘的注冊率。
結(jié)論
深入了解 StatsD 與 Graphite 的工作原理,能讓我們更加明白 StatsD 所傳送的數(shù)據(jù)種類,如何傳送,以及怎樣更有效地根據(jù) Graphite 讀取數(shù)據(jù)。
原文地址:https://blog.pkhamre.com/understanding-statsd-and-graphite/
OneAPM 是應(yīng)用性能管理領(lǐng)域的新興領(lǐng)軍企業(yè),Cloud Insight 能幫助企業(yè)用戶和開發(fā)者輕松實現(xiàn):監(jiān)控各項基礎(chǔ)組件以及對數(shù)據(jù)進行聚合、過濾和篩選的功能,致力于打造一個更為強大的數(shù)據(jù)管理平臺。想閱讀更多技術(shù)文章,請訪問 OneAPM 官方博客。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/7924.html
摘要:本文轉(zhuǎn)自劉斌博文如何選擇監(jiān)控方案,文中劉斌從技術(shù)的角度深入解釋了監(jiān)控的數(shù)據(jù)采集原理,介紹了現(xiàn)有開源的監(jiān)控方案,以及能夠?qū)M行監(jiān)控功能的主流服務(wù)工具。下一章,劉斌將為大家介紹監(jiān)控的開原方案,主流服務(wù),及其特點。 過去的一年中,關(guān)于 Docker 的話題從未斷過,而如今,從嘗試 Docker 到最終決定使用 Docker 的轉(zhuǎn)化率依然在逐步升高,關(guān)于 Docker 的討論更是有增無減。另一...
摘要:的展示非常炫酷,絕對是運維提升逼格的一大利器。另外的可視化功能比強得多,而且以上版本將集成報警功能。它由寫成,著力于高性能地查詢與存儲時序型數(shù)據(jù)。被廣泛應(yīng)用于存儲系統(tǒng)的監(jiān)控數(shù)據(jù),行業(yè)的實時數(shù)據(jù)等場景。 原有監(jiān)控系統(tǒng) showImg(https://segmentfault.com/img/remote/1460000011082384); 整個系統(tǒng)以 Graphite (carbon ...
摘要:有如下模塊源碼解析源碼解析源碼解析源碼解析源碼解析源碼解析源碼解析源碼解析源碼解析使用和監(jiān)控和博客從到學(xué)習(xí)介紹從到學(xué)習(xí)上搭建環(huán)境并構(gòu)建運行簡單程序入門從到學(xué)習(xí)配置文件詳解從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自 Flink Metrics 有如下模塊: Flink Metrics 源碼解析 —— Flink-metrics-core Flink Metrics 源碼解析 —— Flink-metr...
摘要:可行工具圖為上監(jiān)控到的應(yīng)用程序響應(yīng)時間和吞吐量平均負(fù)載第二個廣泛使用的衡量指標(biāo)就是服務(wù)器的平均負(fù)載。率和中止時間垃圾回收器行為異常,是導(dǎo)致應(yīng)用吞吐量和響應(yīng)時間突然下降的主要原因之一。 在某個重大發(fā)布之后,都需要記錄相應(yīng)的指標(biāo),本文介紹了最重要的幾個 Java 性能指標(biāo),包括響應(yīng)時間和平均負(fù)載等。為理解應(yīng)用程序在生產(chǎn)環(huán)境中如何運行,就需要遵循一些 Java 性能指標(biāo)。 在以前,當(dāng)軟件被發(fā)...
摘要:前言在資源審計和計費這塊,容器和虛機有很大區(qū)別。支持諸多輸出,稱為。所以本文主要講如何為增加。實際上,基于增加并且更改,也可以做到,只不過需要裝一些包指令,結(jié)果就是鏡像變大。實際運行日志截圖由于的出色的寫入性能,運行非常穩(wěn)定。 前言 在k8s資源審計和計費這塊,容器和虛機有很大區(qū)別。相對虛機來講,容器不容易實現(xiàn)。資源指標(biāo)收集可以采用heapster,也可以用prometheus。之前文...
閱讀 987·2023-04-26 02:56
閱讀 9629·2021-11-23 09:51
閱讀 1891·2021-09-26 10:14
閱讀 2993·2019-08-29 13:09
閱讀 2166·2019-08-26 13:29
閱讀 580·2019-08-26 12:02
閱讀 3573·2019-08-26 10:42
閱讀 3013·2019-08-23 18:18