Why StatsD
在很多系統(tǒng)中,大家都能看到metric的蹤影,我們通過監(jiān)控metric的變化,就可能知道當前系統(tǒng)運行的狀況。
Metric的方案有很多,譬如著名的prometheus,statsd等,也可以自己造輪子,畢竟通用的metric types也就那么幾種,用好了足夠用來監(jiān)控系統(tǒng)了。
Etcd使用的是prometheus,看名字就知道很是cool的一個系統(tǒng),筆者之前使用Etcd的時候碰到了一個超時問題,通過Etcd的metric發(fā)現是當前磁盤IO負載太高,使得Etcd的fsync太慢,從而導致請求超時的。
因為metric很重要,所以我們也決定在項目中引入metric。最開始,我們想的是直接使用memory的metric解決方案,但Etcd的團隊推薦我們使用prometheus,可是這玩意并沒有rust的client,于是我們就選擇了另一個流行的解決方案StatsD。主要幾個原因:
- 協(xié)議簡單外面可以非常方便的對接使用,rust也有相關的library。
- 使用UDP,速度快,client這邊即使頻繁發(fā)送,也不會降低系統(tǒng)性能。
- StatsD還支持多種backend,我們可以將StatsD收集到的信息轉發(fā)到其他的系統(tǒng)譬如graphite,influxdb,prometheus上面。
Usage StatsD
StatsD的使用非常簡單,因為是node.js的,所以我們需要先安裝好node環(huán)境,然后寫好一個配置文件,直接啟動就可以了,一個簡單的配置文件:
{
port: 8125
, backends: [ "./backends/console" ]
, console: { prettyprint: true }
}
這里,我們使用默認的8125 UDP端口,backend使用的是console,也就是StatsD會將收集到的metrics匯總輸出到console上面,既然是console,那就prettyprint一下,好看一點 :-)
啟動好StatsD之后,我們就可以通過nc簡單使用了:
echo "foo:1|c" | nc -w 1 -u 127.0.0.1 8125
上面的例子中,我們發(fā)送了一個counter,metric的名字是foo,StatsD收到這條metric之后,會查看當前是不是已經有該foo的metric,并將對應的值加1,如果沒有,則默認從0開始。
可以看到,metric的協(xié)議格式是非常簡單的,如下:
<metricname>:<value>|<type>
也就是對于一個metric來說,我們只要想好他的名字以及對應的類型,然后發(fā)實際的數據給StatsD就可以了。
Metric Types
Counting
最簡單的metric應該就是counter,也就是通常的計數功能,StatsD會將收到的counter value累加,然后在flush的時候輸出,并且重新清零。所以我們用counter就能非常方便的查看一段時間某個操作的頻率,譬如對于一個HTTP服務來說,我們可以使用counter來統(tǒng)計request的次數,finish這個request的次數以及fail的次數。
Gauges
不同于Counter,Gauge在下次flush的時候是不會清零的,另外,gauge通常是在client進行統(tǒng)計好在發(fā)給StatsD的,譬如, capacity:100|g 這樣的gauge,即使我們發(fā)送多次,在StatsD里面,也只會保存100,不會學counter那樣進行累加。
但我們可以通過顯示的加入符號來讓StatsD幫我們進行累加,譬如:
capacity:+100|g
capacity:-100|g
假設我們原來的capacity gauge的值為100,經過上面的操作之后,gauge仍然是100。
如果我們需要記錄當前的總用戶數,或者CPU,Memory的usage,使用gauge就是一個不錯的選擇。
Sets
Set用來計算某個metric unique事件的個數,譬如對于一個接口,可能我們想知道有多少個user訪問了,我們可以這樣:
request:1|s
request:2|s
request:1|s
StatsD就會展示這個request metric只有1,2兩個用戶訪問了。
Timing
最后再來說timing,timing顧名思義,就是記錄某個操作的耗時,譬如:
foo:100|ms
上面的例子中,完成foo這個操作花費了100ms,但僅僅是記錄這個操作的耗時,并不能讓我們很好的知道當前系統(tǒng)的情況,所以通常,timing都是跟histogram一起來使用的。
在StatsD里面,配置histogram很簡單,例如:
histogram: [ { metric: '', bins: [10, 100, 1000, 'inf']} ]
在上面的例子中,我們開啟了histogram,這個histogram的bin的間隔是[-inf, 10ms),[10ms - 100ms), [100ms - 1000ms), 以及[1000ms, +inf),如果一個timing落在了某個bin里面,相應的bin的計數就加1,譬如:
foo:1|ms
foo:100|ms
foo:1|ms
foo:1000|ms
那么StatsD在console就會顯示:
histogram: { bin_10: 2, bin_100: 0, bin_1000: 1, bin_inf: 1 } } },
Summary
通過上面的例子可以看到,StatsD還是非常容易使用的,所以剩下的就是我們在代碼里面根據實際情況加上metric了,但這里還有幾點需要注意:
- UDP雖然很快,但仍然可能會因為發(fā)送buffer滿block當前進程,建議設置成noblock,對于metric來說,其實我們并不在意丟了幾個包。
- 埋點是一個辛苦活,太多或者太少的metric其實都沒啥用。
- metric也并不是萬能的,它只是一個系統(tǒng)的匯總統(tǒng)計,有時候我們還需要借助log,flamegraph等其他方式來進行系統(tǒng)問題排查。