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應用程序中收集程序的運行數據, 以及咱們如何使用它來監視應用程序的監控狀態和性能, 當出現應用程序出現異常的時候咱們可以得到警告, 以讓咱們在早期對應用程序異常狀況進行處理, 避免系統發送大的故障致使的經濟損失.

相關文章
相關標籤/搜索