这篇文章上次修改于 2409 天前,可能其部分内容已经发生变化,如有疑问可询问作者。 ##基础介绍 eBay 云谈及 OpenStack 的监控和报警时,提及了 statsd 和 graphite,如下图所示: ![statsd.png](/usr/uploads/2018/04/2250615346.png) ###statsd Statsd 最早是 2008 年 Flickr 公司用 Perl 写的针对 Graphite、datadog 等监控数据后端存储开发的前端网络应用,2011 年 Etsy 公司用 node.js 重构。statsd狭义来讲,其实就是一个监听UDP(默认)或者TCP的守护程序,根据简单的协议收集statsd客户端发送来的数据,聚合之后,定时推送给后端,如graphite和zabbix statsd系统包括三部分: > - 客户端(client) - 服务器(server) - 后端(backend) 客户端以sdk方式植入于应用代码中,将相应的metrics上报给statsd server。statsd server聚合这些metrics之后,定时发送给backends。backends则负责存储这些时间序列数据,并通过适当的图表工具展示。 ###Graphite Graphite 是一个企业级的监控工具,用 Python 编写,采用 django 框架,sqlite 数据库存储,自有简单文本协议通讯,绘图功能强大。最初由 Chris Davis 在 Orbitz 工作时,作为一个辅助项目开发的,最终成了一个监控基础工具,如他所言,Graphite provides real-time visualization and storage of numeric time-series data,重点解决: > - 实时可视化 - 时间序列数据的存储 Graphite 分为三个组件: > - carbon - a Twisted daemon that listens for time-series data - whisper - a simple database library for storing time-series data (similar in design to RRD) - graphite webapp - A Django webapp that renders graphs on-demand using Cairo ![graphite_arch.png](/usr/uploads/2018/04/1318154929.png) 严格地说,Graphite 只是一个根据数据绘图的工具,数据收集通常由第三方工具或插件完成,它自带了 carbon 和 whisper,还可根据其协议选用别的数据源供其绘图。官方描述,预计用 Ceres 替代 Whisper。 ![graphite.jpg](/usr/uploads/2018/04/2769381873.jpg) ##基本原理与概念 statsd采用简单的行协议: ``` :|[|@sample_rate] ``` **bucket** bucket是一个metric的标识,可以看成一个metric的变量。 **value** metric的值,通常是数字。 **type** metric的类型,通常有timer、counter、gauge和set四种。 **sample_rate** 采样频率。适当的降低采样,减少server负载。 这个频率容易误解,需要解释一下。客户端减少数据上报的频率,然后在发送的数据中加入采样频率,如0.1。statsd server收到上报的数据之后,如cnt=10,得知此数据是采样的数据,然后flush的时候,按采样频率恢复数据来发送给backend,即flush的时候,数据为cnt=10/0.1=100,而不是容易误解的10*0.1=1。 UDP 和 TCP statsd可配置相应的server为UDP和TCP。默认为UDP。 > 建议使用UDP以节省资源。 采集到的数据会走 UDP 协议发给 StatsD,由 StatsD 解析、提取、计算处理后,周期性地发送给 Graphite。 数据推送到 Graphite 时,时间周期为1分钟,采集1分钟内的业务数据按照 metric_path value timestamp\n 的格式发送。需要注意的是每次发送的数据必须以 \n 结尾,不能省略。 ##graphite主要配置 Graphite 里有一个 retention(保留)的概念,即明确数据精度以及丢弃多久之前的数据,在 /opt/graphite/conf/storage-schemas.conf 配置文件里定义。retention 定义的表达式为 frequency:history,每一个 retention 之间用英文逗号分隔。 默认是按10秒一个数据的方式,存一天的数据,一天前的数据就没了,如下面的配置所言: ``` [default_1min_for_1day] pattern = .* retentions = 10s:1d ``` 可以自定义 retentions,注意表达式里每一个时间间隔必须是第一个的倍数,也就是说,第一个是10s,那么第二个只能是10s的整数倍,以此类推: ``` [stats] pattern = ^stats.* retentions = 10s:1d,30s:7d,1m:28d,15m:1y ``` 依次解释一下: 10s:1d——1天以内的数据是10秒为一个值 30s:7d——大于1天小于7天内的数据是以30秒为一个值 1m:28d——大于7天小于28天内的是以1分钟为一个值 15m:1y——大于28天小于1年的,是以15分钟为一个值 大于1年的数据丢弃。 ##statsd主要配置 statsd提供默认的配置文件exampleConfig.js。可以参考相应的注释按需配置 **backends后端** 后端默认有console、greaphite等。console的后端通常加上prettyprint。可以同时配置多个backends。backends都要放在代码目录的backends目录下。 ``` backends: ["./backends/console", "./backends/graphite"], console: { prettyprint: true } ``` **flush interval** statsd 默认是10s执行一次flush。可通过flushInterval设置,单位ms。 ``` flushInterval: 2000 // 设为2s ``` **delete系列配置** metric上报时,每次flush之后,就会重置为0(gauge是保持原有值)。如果不上报这些空闲值,可以通过delete*来设置。 ``` deleteGauges: true, deleteTimers: true, deleteSets: true, deleteCounters: true ``` **percentThreshold** 对于timer数据,会计算一个百分比的数据(过滤掉峰值数据),默认是90%。可以通过percentThreshold修改这个值或配置多个值。 ``` //分别计算50%和80%的相关值 percentThreshold: [50, 80] ``` **指标 metric** statsd 有四种指标类型:counter、timer、gauge和set。 **计数器 counter** counter类型的指标,用来计数。在一个flush区间,把上报的值累加。值可以是正数或者负数。 ``` user.logins:10|c // user.logins + 10 user.logins:-1|c // user.logins - 1 user.logins:10|c|@0.1 // user.logins + 100 ``` **计时器 timer** timers用来记录一个操作的耗时,单位ms。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 ``` 对于百分数相关的数据需要解释一下。以90%指标监控为例。statsd会把一个flush期间上报的数据,去掉10%(1-90%)的峰值,即按大小取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 ``` **标量 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,替代前一个值 ``` **sets** 单个flush周期内不重复的值。 ``` request:1|s // user 1 request:2|s // user1 user2 request:1|s // user1 user2 ``` **statsd 客户端** statsd的客户端已经支持多种语言的实现,[参看列表](https://github.com/etsy/statsd/wiki "参看列表") statsd结合Graphite 之后,graphite还支持根据metric路径自动聚合,你可以在它自带的管理站点上看到所有指标的历史数据,可以选时间范围,如下图所示:![graphite_demo.png](/usr/uploads/2018/04/2364195842.png)
没有评论