Collectd & InfluxDb & Grafana 之四: 在Elixir应用程序中收集度量信息

度量是大多数软件的一个基本部分. 度量可以窥探, 监控一个软件系统的在运行时的行为. 并在系统异常的时候进行报警.git

Elixir常常被称赞为一个跑的快的语言. 特别是在分布式, 并发应用程序方面. 可是 "快" 若是没有测量指标, 重构会变得异常困难, 也难于判断是否性能获得改善.github

下面咱们来俺看用什么方式和工具在Elixir应用程序中搜集度量信息.数据库

工具栈概述

咱们的统计数据搜集总体架构以下:网络

图片描述

下面更加深刻的探索这个架构和其中的组件.架构

存储度量数据

如今咱们从架构的核心开始: 用于存储度量数据的数据量. 咱们使用 InfluxDB 一个开源的时序数据库, 它特别适合存储度量数据. 而且提供一堆很是有用的功能.并发

InfluxDB 数据库由一组被称为 measurements 的东西组成. 每一个 measurements 是一个数据点的集合. 每一个数据点由一个时间戳, 一组标记(tags), 和一组值(values)组成.负载均衡

标签(Tags)用元数据标记measurements. 例如一个measurement经常使用的标记为host, 它保存了报告该measurement的主机, 在一个measurement中标记是被全部点共享的. 相反 值是和measurement相关的, 例如标识完成一个HTTP请求的时间被称为request_time. 一个数据点能够有多个值, 当一个点只有一个值的时候, 咱们一般叫这个值只是一个value, 由于measurement名称足够判断他标识的是哪一个值. 框架

在本文的剩余部分, 咱们把measurements称做measurementspoints使阅读体验更流畅.分布式

InfluxDB 还提供了丰富的SQL语法来查询数据. 以及重采用数据已优化存储. 工具

InfluxDB 支持一些存储数据的方法: measurements 能够经过HTTP接口或UDP便可上报, 能够编码为JSON或InfluxDB本身的协议. UDP接口自然的有更快的速度, 由于它没有想HTTP协议和TCP协议那样的开销, 可是, 它不能保证数据成功投递到目标. 选择HTTP仍是UDP

咱们使用 influxdb-relay, 它设置了一个相似负载均衡的架构添加一些复制到统计存储

统计报告

Telegraf

InfluxDB 的开发者为咱们提供了另一个开源的工具叫作 Telegraf. Telegraf 基本上就是一个守护进程, 它没隔N秒从各类数据源收集数据并投递到不一样的输出目标. 输入和输出是经过"输入插件""输出插件"进行管理. 这里咱们使用两个主要输入员, 以及一个输出目标.

输入

第一个Telegraf要收集的输入源是"系通通计", 包含CPU使用率, 内存使用率, 磁盘使用率, 网络使用率等系统级别的运行信息.Telegraf负责读取这些系统的状态值. 另一个咱们使用的输入是内置在Telegraf中的UDP监听器: 它提供了一个到InfluxDB的UDP接口的一个镜像, 并经过本地Telegraf进行把UDP端口暴露出来(做用是做为一个管道联通本机的UDP接口和InfluxDB的UDP接口)

输出

咱们只用一个输出插件: InfluxDB 插件. 该插件很简单: 它把经过输入插件收集到的measurements上报给InfluxDB. 它还提供了一些从没隔输入插件中能够应用于全部measurements的全局标记.(咱们使用其来设置host标记给应用程序和系通通计), 以及measurement过滤. 可是最有用的功能是该插件能够经过InfluxDB的HTTP接口通讯, 而不是UDP接口: 这保证了统计包可以到达InfluxDB而不会丢失.

聚合

Telegraf 做为一个在咱们的应用程序和InfluxDB之间的中间件, 这种架构有几个有点:

  • 咱们能够从应用程序中经过UDP接口发送统计数据给Telegraf, 在上报统计数据的时候有极大的速度提高, 另外 Telegraf 是在本地运行的, 而且经过HTTP协议把统计信息发送给InfluxDB, UDP丢包的风险获得极大的下降. measurements 丢失的风险很是低.

  • 能够设置报告给InfluxDB的measurements数量阀值: Telegraf 会每隔N秒(5,或10秒是一个合理的值, 取决于应用程序)把这些值聚合后发送给InfluxDB, 这意味着, 每隔N秒, Telegraf 发送一个统计报告给InfluxDB, 减小了网络流量.

聚合的做用是能够下降报告的平率, 同时保持较高的采样频率. 同时减小由于上报统计数据给InfluxDB产生的网络流量.

Telegraf/InfluxDB 驱动

若是咱们须要在Elixir应用程序中使用InfluxDB和Telegraf, 如今没有现成的Elixir的UDP接口可用(只有HTTP接口).

每一个Elixir应用程序有其本身的Fluxter模块:

defmodule MyApp.Fluxter do
  use Fluxter
end

上面的代码把MyApp.Fluxter转换为一个UDP链接的监控进程池. 要达到容错的目的, 咱们要保证在一个应用程序的 supervision 树下启动这个池.

def start(_type, _args) do
  children = [
    Supervisor.Spec.supervisor(MyApp.Fluxter, []),
    # ...
  ]
  Supervisor.start_link(children, strategy: :one_for_one)
end

最后, 咱们经过应用程序配置来配置这个池:

config :fluxter,
  host: "localhost",
  port: 8086

而后, 一旦Fluxter池启动, 咱们能够经过下面的方式来报告统计:

def my_operation() do
  MyApp.Fluxter.write("something_done", [my_tag: "foo"], 1)
end

关于 Fluxter 的详细信息, 能够参考 Fluxter文档

Erlang VM统计

对于Erlang虚拟机的统计, 咱们使用 vmstats, 一个小巧的Erlang应用程序用于从Erlang虚拟机中搜集统计并报告给一个sink: 一个sink是一个实现了:vmstats_sink行为的Erlang/Elixir模块. 咱们使用Fluxter池做为这个sink, 摈而且咱们咱们再每个Elixir应用程序中都有一个等同的设置:

defmodule MyApp.Fluxter do
  use Fluxter

  @behaviour :vmstats_sink

  def collect(_type, name, value) do
    write(name, value: value)
  end
end

查看vmstats的README文件了解用它可以作什么.

批处理

咱们在短期内会产生大量的统计报告, 所以咱们须要对其进行聚合操做以减小发送给InfluxDB的数据.

{:ok, batch} = MyApp.Fluxter.start_batch("my_operation_success", [host: "eu-west"])
Enum.each(1..1_000_000, fn(_) ->
  my_operation()
  MyApp.Fluxter.write_to_batch(batch, 1)
end)
MyApp.Fluxter.flush_batch(batch)

统计可视化

全部咱们搜集到和存储的统计数据若是没有可视化是毫无用处的. 咱们使用Grafana做为咱们的可视化工具, 它原生支持InfluxDB(能够直接查询InfluxDB数据库), 而且提供一打颇有用的功能特性.

咱们的仪表盘可视化效果以下:

图片描述

上面咱们使用的仪表盘用于监控应用程序的健康状态: 它显示了从系统和Erlang虚拟机搜集到的统计数据, 左上角的下拉菜单可让咱们选择要可视化的应用程序, 只须要点击选择不一样的应用程序就能够查看系统和Erlang虚拟机的概述.

Grafana 提供了几个有用的功能: 它能够经过标记进行分组, 在一个图标上显示集群中不一样的主机为不一样的线条. 它还能够在数据上进行聚合排序操做, 并且外观也是很是容易定制的.

Grafana 是整个架构中一个最简单的部分, 但不是一个关键的部分.

报警

咱们主要使用统计来测量咱们的应用程序是如何运行的, 但咱们还能够用它来作另外一件很是有用的事情: 报警.

好比咱们能够统计Erlang的进程数量, 当其值偏离平均值太多的时候, 咱们知道咱们须要查看一下系统到底发生了什么异常的状况.

InfluxDB供应商的另外一个产品 Kapacitor 它是一个守护进程, 能够重复的在InfluxDB运行查询, 而后在查询结果上运行一些分析.

Kapacitor 是一个开源框架, 用来处理, 监控和警告时间序列数据. Kapacitor 使用 TICKscript 脚原本定义任务.

Kapacitor 的任务是经过 Kapacitor scripts 来定义Identifier. 它是用 Kapacitor 领域语言编写的任务脚本. 用这种脚本能够作不少事,

stream
  |from()
    .measurement('pushboy_vm_modules')
  |groupBy('host')
  |deadman(15.0, 1m) //
    .id('Pushboy []')
    .message(' is updown')
    .stateChangesOnly()
    .slack()

该脚本检查 vm_modules 度量值, 若是吞吐量下降到每分钟15个点如下触发一个警告. (健康的应用程序每分钟会报告60个点), 你看到最后一行, 经过Slack发送警告给管理员(在Kapacitor的配置中指定). Kapacitor 支持多种通知方式, 包括限于Slack, PagerDuty或者电子邮件.

总结

本文显示了咱们如何从Elixir应用程序中收集程序的运行数据, 以及咱们如何使用它来监视应用程序的监控状态和性能, 当出现应用程序出现异常的时候咱们可以得到警告, 以让咱们在早期对应用程序异常状况进行处理, 避免系统发送大的故障致使的经济损失.

相关文章
相关标签/搜索