當前位置:編程學習大全網 - 源碼下載 - 如何深入理解 StatsD 與 Graphite

如何深入理解 StatsD 與 Graphite

StatsD

為了全面了解 StatsD 的工作原理,我閱讀了它的源碼。之前我就耳聞 StatsD 是壹種簡單的應用,但讀過源碼後才發現它竟如此簡單!在主腳本文件只有300多行代碼,而 Graphite 的後端代碼只有150行左右。

StatsD 中的概念

在這個文檔中,列出了壹些需要理解的 StatsD 概念。

Buckets

當壹個 Whisper 文件被創建,它會有壹個不會改變的固定大小。在這個文件中可能有多個 "buckets" 對應於不同分別率的數據點,每個 bucket 也有壹個保留屬性指明數據點應該在 bucket 中應該被保留的時間長度,Whisper 執行壹些簡單的數學計算來計算出多少數據點會被實際保存在每個 bucket 中。

Values

每個 stat 都有壹個 value,該值的解釋方式依賴於 modifier。通常,values 應該是整數。

Flush Interval

在 flush interval (沖洗間隔,通常為10秒)超時之後,stats 會聚集起來,傳送到上遊的後端服務。

測量值類別

計數器

計數器很簡單。它會給 bucket 加 value,並存儲在內存中,直到 flush interval 超時。

讓我們看壹下生成計數器 stats 的源碼,該 stats 會被推送到後端。

for (key in counters) {

var value = counters[key];

var valuePerSecond = value / (flushInterval / 1000); // calculate "per second" rate

statString += 'stats.'+ key + ' ' + valuePerSecond + ' ' + ts + "\n";

statString += 'stats_counts.' + key + ' ' + value + ' ' + ts + "\n";

numStats += 1;

}

首先,StatsD 會叠代它收到的所有計數器,對每個計數器它都會分配兩個變量。壹個變量用於存儲計數器的 value,另壹個存儲 per-second value。之後,它會將 values 加至 statString,同時增加 numStats 變量的值。

如果妳使用默認的 flush interval(10秒),並在每個間隔通過某個計數器給 StatsD 傳送7個增量。則計時器的 value 為 7,而 per-second value 為 0.7。

計時器

計時器用於收集數字。他們不必要包含時間值。妳可以收集某個存儲器中的字節數、對象數或任意數字。計時器的壹大好處在於,妳可以得到平均值、總值、計數值和上下限值。給 StatsD 設置壹個計時器,就能在數據傳送給 Graphite 之前自動計算這些量。

計時器的源碼比計數器的源碼要稍微復雜壹些。

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 + "\n";

message += 'stats.timers.' + key + '.upper_' + clean_pct + ' ' + maxAtThreshold + ' ' + ts + "\n";

message += 'stats.timers.' + key + '.sum_' + clean_pct + ' ' + sum + ' ' + ts + "\n";

}

sum = cumulativeValues[count-1];

mean = sum / count;

message += 'stats.timers.' + key + '.upper ' + max + ' ' + ts + "\n";

message += 'stats.timers.' + key + '.lower ' + min + ' ' + ts + "\n";

message += 'stats.timers.' + key + '.count ' + count + ' ' + ts + "\n";

message += 'stats.timers.' + key + '.sum ' + sum + ' ' + ts + "\n";

message += 'stats.timers.' + key + '.mean ' + mean + ' ' + ts + "\n";

statString += message;

numStats += 1;

}

}

如果在默認的 flush interval 內,妳將下列計數器 values 傳給 StatsD:

450

120

553

994

334

844

675

496

StatsD 將會計數下面的 values:

mean_90 496

upper_90 844

sum_90 3472

upper 994

lower 120

count 8

sum 4466

mean 558.25

Gauges

壹個 guage 代表著時間段內某點的任意 vaule,是 StatsD 中最簡單的類型。妳可以給它傳任意值,它會傳給後端。 Gauge stats 的源碼只有短短四行。 for (key in gauges) { statString += 'stats.gauges.' + key + ' ' + gauges[key] + ' ' + ts + "\n"; numStats += 1; } 給 StatsD 傳壹個數字,它會不經處理地將該數字傳到後端。值得註意的是,在壹個 flush interval 內,只有 gauge 最後的值會傳送到後端。因此,如果妳在壹個 flush interval 內,將下面的 gauge 值傳給 StatsD:

643

754

583

會傳到後端的值只有583而已。該 gauge 的值會壹直存儲在內存中,直到 flush interval 結束才傳值。

Graphite

現在,我們已經了解數據是怎樣從 StatsD 傳出來的,讓我們看看它在 Graphite 裏是如何存儲並處理的。

總覽

在 Graphite 文檔裏,我們可以找到 Graphite 概覽,此概覽總結了 Graphite 的兩個要點:

Graphite 存儲數值型帶有時間序列的數據。

Graphite 按需繪制圖表。

Graphite 由三部分組成:

carbon :監聽時間序列的數據的後臺程序。

whisper:壹個簡單的數據庫庫,用來存儲時間序列數據。

webapp: Django webapp,使用 Cairo 來根據需要呈現圖形。

Graphite 當做時間序列數據的格式如下: <key> <numeric value> <timestamp>

存儲方案

Graphite 采用可配置的存儲方案用以定義所存數據的留存率。它會給數據路徑匹配特定的模式,從而決定所存數據的頻率和來歷。

以下配置示例截取自 StatsD 文檔。

[stats]

pattern = ^stats\..*

retentions = 10:2160,60:10080,600:262974

該示例表明,匹配上述樣式的數據都會套用這些留存。留存的格式為 frequency: history。所以,該配置允許我們將10秒鐘的數據存儲6個小時,1分鐘的數據存儲1周,10分鐘的數據存儲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

讓我們看看該數據生成的 Graphite 圖。該數據來自 2 分鐘前,而 elapsed_time 則來自前面的腳本。

圖像生成

Render URL

下面圖片的 Render URL

/render/?width=586&height=308&from=-2minutes&target=stats.timers.http_request.elapsed_time.sum

  • 上一篇:股市仙人指路第二天什麽走勢
  • 下一篇:為什麽用PHP制作網頁普遍認為比用ASP好?
  • copyright 2024編程學習大全網