`

如何深入理解 StatsD 与 Graphite ?

阅读更多

众所周知,StatsD 负责收集并聚合测量值。之后,它会将数据传给 Graphite,后者以时间序列为依据存储数据,并绘制图表。但是,我们不知道,基于 http 访问的图表在展示时,是基于每秒钟的请求数,每次留存的平均请求数还是其它。让我们就以此为目标,来一探究竟吧!本文系 OneAPM 工程师编译整理。

理解 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

Graphite 生成的图片

该图片简单地描绘了 http 请求在一段时间内的 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

在下面的结果中,我们可以查看来自 Graphite 的源数据。这些数据来自12个不同的数据点,也即 StatsD 10 秒 flush internal 的两分钟。Graphite 绘制数据就是如此简单。

此外,借助 JSONLint,JSON-data 的数据显示更加美观。

[
    {
        "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  

图像显示——用户注册数量

Render URL

下面图片的 Render URL

/render/?width=586&height=308&from=-20minutes&target=stats.gauges.user_registrations

来自 Graphite 的图片

另一个简单的图片,展示总的注册数。

图片显示——每分钟的用户注册数

使用 Graphite 的衍生函数,可以获得每分钟的用户注册数量。

Render URL

下面图片的 Render URL

/render/?width=586&height=308&from=-20minutes&target=derivative(stats.gauges.user_registrations)

来自 Graphite 的图片

该图片所用的数据跟之前的图片一致,但是使用了衍生函数从而显示每分钟的注册率。

结论

深入了解 StatsD 与 Graphite 的工作原理,能让我们更加明白 StatsD 所传送的数据种类,如何传送,以及怎样更有效地根据 Graphite 读取数据。

原文地址:https://blog.pkhamre.com/understanding-statsd-and-graphite/

分享到:
评论

相关推荐

    前端开源库-node-statsd

    与其他监控工具(如 Prometheus、Grafana 或 ELK Stack)配合使用,`node-statsd` 可以帮助构建一个全面的性能监控体系,从而更好地理解应用程序的运行状况,及时发现和解决问题。 总结,`node-statsd` 是前端...

    delphi-使用delphi实现的statsd客户端库-允许java应用与statsd通信.zip

    本篇文章将深入探讨如何使用Delphi编程语言创建一个StatsD客户端库,使得Java应用程序能够有效地与StatsD进行通信。 首先,我们需要理解Delphi与Java之间的通信机制。Delphi是一款强大的面向对象的编程环境,基于...

    开源项目-alexcesaro-statsd.zip

    这些资源对于想要深入理解其工作原理或者想要对其进行二次开发的开发者来说非常宝贵。通过阅读源代码,我们可以学习到如何在Go中实现高效的数据处理和网络通信,这对于提升个人编程技能和解决实际问题都有很大的帮助...

    metrics-poc:一个测试指标和监控工具(如logstash statsd Graphite Grafana)的游乐场

    4. **Grafana**: 是一个流行的开源度量分析和可视化套件,它可以与多种数据源(包括Graphite)集成,用于创建、共享和操作动态仪表板。Grafana提供了丰富的图形化选项,使用户能直观地理解系统性能和健康状况。 这...

    统计数据收集器StatsD.zip

    《深入理解StatsD:Node.js平台的统计信息收集器》 在现代软件开发中,数据分析和监控成为衡量应用性能、优化用户体验的关键环节。StatsD,作为一个轻量级的统计信息收集器,因其简单易用和强大的聚合功能,受到了...

    statsd_exporter-0.22.4.linux-amd64.tar.gz

    《statsd_exporter在Linux运维中的应用与详解》 在IT运维领域,监控系统性能、收集和分析数据是至关重要的工作。statsd_exporter作为Prometheus生态中的一个重要组件,为统计和导出statsd指标提供了方便。本文将...

    C implementation of statsd.zip

    本文将深入探讨如何使用C语言来实现statsd。 首先,理解statsd的基本工作原理至关重要。statsd是一个轻量级守护进程,运行在服务器上,接收来自应用程序的统计信息,并以批处理的方式将这些信息转发到一个或多个...

    Laravel开发-laravel-statsd

    本篇文章将深入探讨如何在Laravel项目中集成`laravel-statsd`,以便将应用程序的性能数据发送到Statsd服务器进行监控和分析。 首先,让我们了解什么是Statsd。Statsd是由 Etsy 开发的一款轻量级代理服务,它运行在...

    Python库 | guillotina_statsd-1.0.4-py3-none-any.whl

    首先,让我们深入了解`StatsD`。StatsD是一个轻量级的代理服务,由 Etsy 开源,它的主要任务是收集来自应用程序的性能数据,如计数器、计时器、直方图和分布,然后将这些数据转发到诸如Graphite、InfluxDB或Elastic...

    开源项目-amalfra-gin-statsd.zip

    在这个开源项目中,"gin-statsd"中间件的主要功能是集成Gin应用与statsd服务,以便实时追踪和度量应用程序的关键性能指标。这包括但不限于请求计数、响应时间、错误率等。通过这种集成,开发者可以更好地了解其应用...

    PyPI 官网下载 | sanic-statsd-0.1.0.tar.gz

    首先,让我们深入了解 Sanic。Sanic 是一个 Python 的异步 Web 框架,它以其快速和反向思维的设计而闻名。与传统的 Web 框架不同,如 Flask 和 Django,Sanic 不是等待每个请求完成后再处理下一个,而是允许同时处理...

    statsd-redis-backend:跷跷板

    《statsd-redis-backend:构建高效数据收集与分析系统》 在现代的互联网应用开发中,数据监控和分析是至关重要的。"statsd-redis-backend"是一个针对此需求的解决方案,它结合了StatsD和Redis的强大功能,为开发者...

    scala-statsd-example

    **正文** `scala-statsd-example` 是一个基于 Scala 语言实现的示例项目,它主要用于演示如何使用 StatsD 库来收集和报告...通过深入理解这个示例,开发者可以更好地实现对复杂系统的监控,确保服务的稳定性和高效性。

    spring-statsd

    《深入理解Spring-Statsd:基于Java的统计与监控利器》 在当今的软件开发领域,性能监控和数据统计已经成为衡量应用健康状况的关键指标。Spring-Statsd作为一个强大的工具,它利用了statsD库,为Java开发者提供了一...

    Graphite网站实时信息采集和统计-其他

    本文将深入探讨Graphite的功能、工作原理以及如何利用它来实现网站信息的采集和统计。 1. Graphite概述: Graphite由三个主要组件组成:Carbon、Whisper和Graphite Web。Carbon负责接收和缓存时间序列数据,...

    tornado-statsd-example

    本篇将深入探讨如何在Tornado应用中集成StatsD。 首先,我们需要确保已经安装了`statsd`这个Python库,它提供了与StatsD服务器通信的客户端接口。可以使用pip来安装: ```bash pip install statsd ``` 接下来,...

    weld-jsf-translator-war-2.0.0.Alpha2.zip

    开源项目statsd-over-slf4j.zip提供了一个巧妙的解决方案,它将Java StatsD客户端与SLF4J(Simple Logging Facade for Java)相结合,使得日志数据能够方便地传输到StatsD服务器,进一步进行统计和分析。本文将深入...

    statsd-mysql-watcher:从 mysql 获取状态数据并将其通过管道传输到 StatsD

    `statsd-mysql-watcher`是一个工具,它允许开发者从MySQL数据库中收集状态数据,并通过StatsD发送到诸如Graphite或Elasticsearch这样的后端系统进行进一步的处理和可视化。这个项目基于JavaScript编写,旨在简化...

    statsdtest:一个简单的脚本来测试statsd向我们的内部服务器发送消息

    本文将深入探讨一个名为“statsdtest”的简单Java脚本,它用于测试StatsD服务器与内部服务器之间的通信。 首先,让我们理解statsdtest的用途。这个工具的主要功能是验证statsd服务器是否能够正确接收并处理由Java...

    Mambo-collector:statsd的数据收集器

    《Mambo Collector:statsd数据收集器的深入解析》 Mambo Collector,作为一个专门针对statsd的MySQL数据收集器,是统计监控领域中一个关键的组件。它旨在为statsd提供一种有效的方式来整合MySQL数据库中的数据,...

Global site tag (gtag.js) - Google Analytics