应用程序的监控是微服务中很重要的一环。监控主要包括四个方面的内容:指标(metrics)的采集、存储、展示以及相应的报警机制。目前相关的解决方案以及工具非常多。今天就介绍一款用于采集数据的工具——StatsD。
Statsd 最早是 2008 年 Flickr 公司用 Perl 写的针对 Graphite、datadog 等监控数据后端存储开发的前端网络应用,2011 年 Etsy 公司用 node.js 重构,有时间可以查看这边文章 Measure Anything, Measure Everything 。
github:https://github.com/statsd/statsd
statsD狭义来讲,包含一个监听UDP(默认)或者TCP的守护程序,以及一套简单的协议。任何udp/tcp客户端都可以根据其协议发送数据到守护进程,守护进程聚合之后定时推送给后端,如graphite和influxdb等。
StatsD系统包括三部分:客户端(client)、服务器(server)和后端(backend)。客户端植入于应用代码中,将相应的metrics上报给StatsD server。statsd server聚合这些metrics之后,定时发送给backends。backends则负责存储这些时间序列数据,并通过适当的图表工具展示。
statsd采用简单的行协议,例如:
<bucket>:<value>|<type>[|@sample_rate]
statsd可配置相应的server为UDP和TCP(默认为UDP)。UDP和TCP各有优劣,但UDP确实是不错的方式。
当然,UDP更适合于上报频率比较高的场景,就算丢几个包也无所谓,对于一些一天已上报的场景,任何一个丢包都影响很大。另外,对于网络环境比较差的场景,也更适合用TCP,会有相应的重发,确保数据可靠。
3.1)counter:
用来累加计数,值可以是正数或者负数。在一个flush区间,把上报的值累加,flush后会清零。
user.logins:10|c // user.logins + 10
user.logins:-1|c // user.logins - 1
user.logins:10|c|@0.1 // user.logins + 100
// users.logins = 10-1+100=109
3.2)timer:
timers用来记录一个操作的耗时,单位ms。
1)statsd会记录平均值(mean)、最大值(upper)、最小值(lower)、累加值(sum)、平方和(sum_squares)、个数(count)以及部分百分值。
rpt:100|g
如下是在一个flush期间,发送了一个rpt的timer值100。以下是记录的值。
count_80: 1,
mean_80: 100,
upper_80: 100,
sum_80: 100,
sum_squares_80: 10000,
std: 0,
upper: 100,
lower: 100,
count: 1,
count_ps: 0.1,
sum: 100,
sum_squares: 10000,
mean: 100,
median: 100
2)percentThreshold
对于timer数据,除了正常的统计之外还会计算一个百分比的数据(过滤掉峰值数据),默认是90%。可以通过percentThreshold修改这个值或配置多个值。例如在config.js中配置:
//分别计算50%和80%的相关值
percentThreshold: [50, 80]
对于百分数相关的数据需要解释一下。以90为例,statsd会把一个flush期间上报的数据,去掉10%的峰值,即按大小取cnt*90%(四舍五入)个值来计算百分值。假如10s内上报以下10个值:
1,3,5,7,13,9,11,2,4,8
则只取10*90%=9个值,则去掉13。百分值即按剩下的9个值来计算。
$KEY.mean_90 // (1+3+5+7+9+2+11+4+8)/9
$KEY.upper_90 // 11
$KEY.lower_90 // 1
3)直方图
有时仅记录操作的耗时并不能让我们很好的知道当前系统的情况,通常,timing都是跟histogram一起来使用的。在config.js配置文件中设置:
histogram: [ { metric: '', bins: [10, 100, 1000, 'inf']} ]
这样就开启了histogram,这个histogram的bin的间隔是[0, 10ms),[10ms - 100ms), [100ms - 1000ms), 以及[1000ms, +inf),如果一个timing落在了某个bin里面,相应的bin的计数就加1,譬如:
foo:1|ms
foo:100|ms
foo:1|ms
foo:1000|ms
那么最终statsd最终flush输出时:
histogram: { bin_10: 2, bin_100: 0, bin_1000: 1, bin_inf: 1 } } },
注:没有p99等指标。
3.3)gauge:
gauge是任意的一维标量值(如:内存、身高等值)。gague值不会像其它类型会在flush的时候清零,而是保持原有值。statsd只会将flush区间内最后一个值发到后端。另外,如果数值前加符号,会与前一个值累加。
age:10|g // age 为 10
age:+1|g // age 为 10 + 1 = 11
age:-1|g // age为 11 - 1 = 10
age:5|g // age为5,替代前一个值
注:gauge通常是在client进行统计好在发给StatsD的,如capacity:100|g 这样的gauge,即使我们发送多次,在StatsD里面,也只会保存100 。
3.4)sets:
记录flush期间,不重复的值。可以用来计算某个metric unique事件的个数,譬如对于一个接口,可能我们想知道有多少个user访问了,我们可以这样:
StatsD就会展示这个request metric只有1,2两个用户访问了。
request:1|s // user 1
request:2|s // user1 user2
request:1|s // user1 user2
在centos6上通过源码安装statsd(也可以根据github上的说明,使用docker安装)。
1.1)nodejs环境:
参考:https://blog.csdn.net/liuxiao723846/article/details/48519593
注意:最新的statsd使用了ES6的语法,所以需要至少node6.0以上的版本。(https://nodejs.org/download/release/v6.17.1/)
1.2)下载、配置、启动:
#下载
cd /usr/local
git clone https://github.com/statsd/statsd.git
cd statsd
cp exampleConfig.js config.js
#修改config.js
#...
#启动
node /usr/local/statsd/stats.js /usr/local/statsd/config.js
statsd提供默认的配置文件exampleConfig.js。可以参考相应的注释按需配置,接下来将简单介绍一些配置项。
{
port:8125,//statsd 服务端口
backends:["./backends/console"],
console:{
prettyprint:true
},
flushInterval:30000,//statsd flush时间
percentThreshold: [80,90]
}
{
port: 8125,
graphitePort: 2003,
graphiteHost: "graphite.example.com",
backends: [ "./backends/graphite" ]
}
注:在statsd目录下,backends中包含了默认的后端:graphite和console。
配置statsd的backends问console进行调试,启动statsd。然后使用netcat发送数据进行测试:
echo "test:9|ms" | nc -w 1 -u 127.0.0.1 8125
注意:netcat -w参数表示超时时间,单位是秒。
根据配置的flushinterval,statsd服务端会定时的将聚合好的数据发送到backends,如果配置的后端是console,则会输出:
Flushing stats at Mon Oct 12 2020 22:53:11 GMT+0800 (CST)
{ counters:
{ 'statsd.bad_lines_seen': 0,
'statsd.packets_received': 0,
'statsd.metrics_received': 0 },
timers: { 'statsd_test.test.cost': [] },
gauges: { 'statsd.timestamp_lag': 0 },
timer_data: { 'statsd_test.test.cost': { count_ps: 0, count: 0 } },
counter_rates:
{ 'statsd.bad_lines_seen': 0,
'statsd.packets_received': 0,
'statsd.metrics_received': 0 },
sets: {},
pctThreshold: [ 80, 90 ] }
StatsD支持可插拔backends,安装包中默认带有graphite后端。可以将其他后端作为简单的npm软件包进行分发和安装:
StatsD最初由Etsy的Erik Kastner编写,它基于Flickr的想法以及Cal Henderson的这篇文章:Counting and Timing。2011年该服务器用Nodejs编写重写,但是从那时起已经有其他语言的实现:
客户端主要是根据statsd协议,通过UDP/TCP向守护进程通信。常见的实现有:
Node
Java
Python
Ruby
Perl
PHP
Clojure
Io
C
CPP
.NET
Go
Apache
Varnish
PowerShell
Browser
Objective-C
ActionScript
WordPress
Drupal
Haskell
R
Lua
Nim
https://github.com/statsd/statsd/wiki