度量是大多數軟件的一個基本部分. 度量可以窺探, 監控一個軟件系統的在運行時的行爲. 並在系統異常的時候進行報警.git
Elixir常常被稱讚爲一個跑的快的語言. 特別是在分佈式, 併發應用程序方面. 可是 "快" 若是沒有測量指標, 重構會變得異常困難, 也難於判斷是否性能獲得改善.github
下面咱們來俺看用什麼方式和工具在Elixir應用程序中搜集度量信息.數據庫
咱們的統計數據蒐集總體架構以下:網絡
下面更加深刻的探索這個架構和其中的組件.架構
如今咱們從架構的核心開始: 用於存儲度量數據的數據量. 咱們使用 InfluxDB 一個開源的時序數據庫, 它特別適合存儲度量數據. 而且提供一堆很是有用的功能.併發
InfluxDB 數據庫由一組被稱爲 measurements
的東西組成. 每一個 measurements
是一個數據點的集合. 每一個數據點由一個時間戳, 一組標記(tags), 和一組值(values)組成.負載均衡
標籤(Tags)用元數據標記measurements
. 例如一個measurement經常使用的標記爲host
, 它保存了報告該measurement
的主機, 在一個measurement
中標記是被全部點共享的. 相反 值是和measurement
相關的, 例如標識完成一個HTTP請求的時間被稱爲request_time
. 一個數據點能夠有多個值, 當一個點只有一個值的時候, 咱們一般叫這個值只是一個value
, 由於measurement
名稱足夠判斷他標識的是哪一個值. 框架
在本文的剩餘部分, 咱們把measurements
稱做measurements
和points
使閱讀體驗更流暢.分佈式
InfluxDB 還提供了豐富的SQL語法來查詢數據. 以及重採用數據已優化存儲. 工具
InfluxDB 支持一些存儲數據的方法: measurements
能夠經過HTTP接口或UDP便可上報, 能夠編碼爲JSON或InfluxDB本身的協議. UDP接口自然的有更快的速度, 由於它沒有想HTTP協議和TCP協議那樣的開銷, 可是, 它不能保證數據成功投遞到目標. 選擇HTTP仍是UDP
咱們使用 influxdb-relay, 它設置了一個相似負載均衡的架構添加一些複製到統計存儲
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產生的網絡流量.
若是咱們須要在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虛擬機的統計, 咱們使用 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應用程序中收集程序的運行數據, 以及咱們如何使用它來監視應用程序的監控狀態和性能, 當出現應用程序出現異常的時候咱們可以得到警告, 以讓咱們在早期對應用程序異常狀況進行處理, 避免系統發送大的故障致使的經濟損失.