Elasticsearchアラートで実現!オフィスのコールドブリューコーヒーが「空っぽ」になる前に知らせる監視システム

Elasticsearchアラートで「もうすぐ空になる」を検知する
ObjectRocketのオフィスでは、樽詰めのコールドブリューコーヒーがスタッフのエネルギー源になっています。テキサス州オースティンの8月はとても暑く、カフェインは冷たい状態で摂りたいところです。
しかし、樽は一度に1本しかストックしていないため、在庫を切らさずに発注スケジュールを組むのはなかなか難しいものです。そんなとき、オフィスの誰かが「コールドブリューの使用状況をもっとデータで把握したいね」と口にしたのをきっかけに、私はすぐに飛びつきました。Elastic Stackの可能性を示す新しい題材を常に探していた私は、二度とコールドブリューが切れないようにするための半自動的な監視・アラートシステムの構築に取り掛かったのです。
最終的にできあがったのは、Raspberry Pi、Elasticsearch、Kibana、そしてSentinl/ElastAlertを組み合わせたシステムです。樽に何か重要な変化が起きたときにSlackへアラートを通知します。中でもSentinlとElastAlertが主役級の活躍を見せてくれるので、後ほど詳しく掘り下げていきます。


この2部構成シリーズの第1回では、キーガレーター(樽冷却サーバー)ソリューションから取得したデータを使って、私がどのようにアラートシステムを構築したのかを解説します。この記事を読んで、Elasticsearch向けのオープンソースアラートツールについてのアイデアや知識を持ち帰ってもらえれば幸いです。ハードウェアの物理的な構築方法については、次回の記事で詳しく紹介する予定です。
樽から得られるのはコーヒーだけじゃない――データも
前述のとおり、キーガレーターの組み立て方法や、流量モニタリング方式ではなく重量計測方式(スケール+樽の重さ)を選んだ理由については、次回のブログで扱います。
この記事で知っておくべきことはただひとつ。Raspberry Pi駆動のスケールを設置し、以下のような形式のドキュメントをElasticsearchへ定期的に送信し続けているという点です。
{
"_index": "filebeat-6.2.4-2018.05.15",
"_type": "doc",
"_source": {
"@timestamp": "2018-05-15T16:50:49.000Z",
"beat": {
"hostname": "raspberrypi",
"name": "raspberrypi",
"version": "6.2.4"
},
"weight": 58.4,
"message": "2018-05-15T16:50:49+0000 - -0.4"
}
}
Filebeatがデータを取得し、その中には私たちが注目する2つの主要フィールドが含まれています。
- 各重量測定値の「@timestamp」(タイムスタンプ)
- その時刻における実際の「weight」(重量)の値
アラートツールの選択肢
まず最初に必要なのは、樽に異変が起きた際に担当者へ通知を送る仕組みです。ここで活躍するのがアラートパッケージです。
幸い、Elasticsearchクラスタにアラート機能を追加できるApache 2.0ライセンスの選択肢がいくつか存在します。それが「ElastAlert」と「Sentinl」です。
ElastAlert
ElastAlertはYelpが開発したElasticsearch用の柔軟なアラートフレームワークで、Elasticsearchとは別プロセスとして稼働し、主に基本的な設定ファイルによって構成します。ユーザーはすべてのアラートに共通するグローバルパラメータを記述したメイン設定ファイルを作成し、その後、ルールごとにElastAlert固有のYAMLでルールとアラート内容を定義したルールファイルを作成します。各「ルール」には以下が含まれます。
- 標準のルールタイプ(「flatline」「spike」「metric aggregation」など)に基づくルール設定
- 各ルールが参照するクエリ結果を絞り込むためのElasticsearchフィルター
- 条件に一致した場合に発火するアラート(メール、Jira、Slackなど)
Sentinl
SentinlはElastAlertよりもやや新しいツールです。ObjectRocket Serviceの顧客向けに新しいアラート手段を探していた際、Siren Solutionsが開発したSentinlに出会いました。SentinlはKibanaプラグインで、Elasticsearch向けのアラート機能に加えてレポーティング機能も提供します。各ジョブは「ウォッチャー(watcher)」と呼ばれ(古い同名プラグインとは別物なので注意)、以下の要素で構成されます。
- スケジュール(いつ、どの頻度でチェックするか)
- 入力クエリ(チェックしたいデータを取得するElasticsearchクエリ)
- 条件(データに対してアラートを出すかどうかを判定するロジック)
- トランスフォーム(アラート前にデータを加工するコード)
- アクション(Slack、メール、Webhookなど、アラート時に実行する処理)
どちらのアラートツールを選ぶべきか?
どちらも非常に優れたツールなので、求めるアラートの種類によって使い分けるのがよいでしょう。私が調べた結果は以下のとおりです。
| ElastAlert | Sentinl | |
| メリット |
|
|
| デメリット |
|
|
アラートの設計
次に、どんなアラートを作成すべきかを定義します。最終的に知りたいのは「いつコールドブリューを追加発注すべきか」ということです。そこで、以下のようなアラートを作成しました。
樽が空/まもなく空になる
シンプルなケース:重量が一定のしきい値を下回ったら通知します。
樽が交換された
やあ、新鮮なコーヒーの登場だ:重量が急激に増加したことを検出します。
監視システムの障害
データがなければアラートも出せない:スケールからのデータ送信が停止したタイミングを把握する必要があります。
樽が空/まもなく空になったときのアラート
このシナリオでは、重量が「空」とみなすしきい値を下回った場合にアラートを発火させ、さらに約20%程度残量となった段階で警告を出すように設定します。
ElastAlert
ElastAlertなら「metric aggregation」ルールタイプを使うことで簡単に実現できます。メトリクスから集計値を作成し、それが特定のしきい値より上か下かを判定する仕組みです。
# (Required)
# Rule name, must be unique
name: Empty Alarm
# (Required)
# Type of alert.
type: metric_aggregation
# (Required)
# Index to search, wildcard supported
index: filebeat-*
# How much data should we use
buffer_time:
hours: 1
# How often can we send this alert?
realert:
hours: 24
# Type of elasticsearch document to use
doc_type: doc
metric_agg_key: weight
metric_agg_type: max
min_threshold: 41
# (Required)
# The alert is use when a match is found
alert:
- "slack"
alert_subject: The cold brew keg is empty
alert_text_type: alert_text_only
alert_text: "The cold brew keg is empty. Panic."
slack:
slack_webhook_url: "https://hooks.slack.com/services/foo/bar"
slack_msg_color: danger
slack_emoji_override: ":torch-and-pitchfork:"
この設定では、過去1時間分(buffer_time)の最大重量が41未満(空の樽)であるかを確認し、アラートは24時間に1度だけ送信するようにしています。さらに、Slackへのアラート設定、送信するデータの種類、メッセージの色や絵文字といった細かな指定まで行えます。
警告アラートの方が少し複雑です。警告しきい値の範囲内にあるときだけ知りたいのです。具体的には、41(空)より大きく、65(25%残量ライン=「もうすぐなくなるぞ」と警告を開始する目安)未満の場合です。しかしElastAlertは単一のしきい値しか指定できないため、フィルター機能を使ってこれを実現します。
metric_agg_key: weight
metric_agg_type: avg
min_threshold: 65
filter:
- range:
weight:
gte: 41
41以上の値に絞り込んで評価するのは、すべての重量値が41未満だった場合にはこのアラートを発火させたくないからです(その場合は「空」アラートが発火するため)。逆に、41以上の値がひとつでも存在すれば「空」アラートは発火しないため、平均値が65未満という要件を満たしているかどうかを判断できます。
Sentinl
Sentinlには、ウォッチャーを設定するための使いやすいGUIが用意されています。
最初の画面では、ウォッチャーに名前を付けてスケジュールを設定するだけです。

Input(入力)では、必要なデータを取得するためのElasticsearchクエリを記述します。ここではweightフィールドを含むドキュメントを対象に、weightフィールドの平均値集計を行っています。

Condition(条件)画面では、何をトリガーにアラートを発火させるかを決めます。ここでは「ヒットが一定件数以上あること」かつ「平均重量が41未満であること」を条件としています。

以下はコンソールアラートの例です(専用インデックスにもドキュメントが保存されます)。条件が真のときにメッセージが送信されます。

SentinlにはUIが付属していますが、その分、多少クエリを書く必要があります。とはいえ、そのほとんどが通常のElasticsearchクエリなので、おそらく皆さんもすでに慣れているはずです。
樽が補充されたことを検知する
次に、樽が補充されたことをオフィス全体に告知する仕組みが必要です。受け取る樽のサイズが変わることがあるため、単に一定のしきい値を上回ったかどうかを見るのではなく、重量の急激な増加を検出したいと考えました。
ElastAlert
ElastAlertには「spike」という組み込みルールがあり、樽の重量上昇を検出するのに利用できます。
name: Refill Detector
type: spike
index: filebeat-*
field_value: weight
spike_height: 2
spike_type: 'up'
timeframe:
minutes: 10
threshold_ref: 100
threshold_cur: 100
realert:
hours: 6
このルールはweightフィールドの値を10分間のウィンドウごとにグループ化し、あるウィンドウの重量平均が直前の10分ウィンドウの平均より2倍(spike_height)を超えた場合にアラートを発火させます。また、10分ウィンドウが「有効」とみなされるには最低100件のサンプルが必要であり(threshold_refとthreshold_curの設定)、アラートは6時間に1度しか発火できない点にも注意してください。
Sentinl
Sentinl側では少し複雑になりますが、serial difference(系列差分)集計を使って、直前のバケットと比較して大幅な増加を含むバケットがないかを確認します。
{
"input": {
"search": {
"request": {
"index": [
"filebeat-*"
],
"body": {
"query": {
"bool": {
"filter": [
{
"range": {
"@timestamp": {
"gt": "now-5m/m"
}
}
}
]
}
},
"aggs": {
"30s_buckets": {
"date_histogram": {
"field": "@timestamp",
"interval": "30s"
},
"aggs": {
"weight_avg": {
"avg": {
"field": "weight"
}
},
"weight_diff": {
"serial_diff": {
"buckets_path": "weight_avg",
"lag": 3
}
}
}
},
"max_weight_diff": {
"max_bucket": {
"buckets_path": "30s_buckets>weight_diff"
}
}
}
}
}
}
},
"condition": {
"script": {
"script": "payload.hits.total > 20"
},
"compare": {
"payload.aggregations.max_weight_diff.value": {
"gte": 40
}
}
}
}
この「ウォッチャー」は過去5分間を走査し、30秒ごとのバケットに分割した上で、3バケット間の差分が40以上の増加になっていないかをチェックします。ElastAlertの同等機能よりやや複雑ですが、十分うまく機能します。
3つ目のアラート(データフィード断絶の検知)のコードはここでは省略しますが、どちらのツールでも非常にシンプルなアラートです。ElastAlertの「flatline」ルールで綺麗に対応でき、Sentinlでも特定ウィンドウ内の重量データを全件取得してヒット数をカウントするだけで済みます。コードを見たい方がいれば、ぜひお知らせください。
アラートデータの活用
両アラートシステムのもうひとつの利点は、アラート自体のログがElasticsearchに保存されるため、アラート履歴に対してクエリを実行し、可視化を作成できることです。
補充履歴
私は補充アラートを利用して、Kibanaダッシュボード上に樽の補充タイミングをプロットしています。重量データから最終補充時刻の可視化を作る代わりに、最新の補充アラートを参照するだけで済むわけです。例えばSentinlは、日付ベースの「watcher_alerts-*」というローカルインデックスにすべてのアラートを保存します。

最終補充日の可視化を作成するには、「watcher」フィールドでイベントをフィルタリングして補充イベントのみを抽出し、最大日付を選択します。

日次レポーティング
もうひとつ便利な使い方として、通常のアラートを応用して、いわゆる「ロールアップ(集約)」のような振る舞いを実現し、後からレポートできるようにすることもできます。
例えば、日々の消費量を把握したい場合、日ごとの重量減少量を確認し、大きな急変(補充などのイベントによるもの)を除外した上で、重量をオンス単位に変換します。
これは単一のKibanaビジュアライゼーションでは少し扱いにくい部分があります(ただしVegaには期待が持てます)。
そこで代わりに、毎晩深夜0時前に実行され、その日の消費量の合計を作成する日次アラートを用意しました。そして、「watcher_alerts」インデックスからそれらの日次合計を読み取るシンプルな可視化を作成したのです。


最終的な成果
セットアップを完了すると、今ではSlackが「コールドブリューの樽を追加発注すべきタイミング」を教えてくれるようになりました。しかも、IT部門や管理者など一部の人だけでなく、オフィス全员が新しい樽の到着を把握できるようになりました。

もう冷や汗をかいてコールドブリューを探す必要はありません。スタッフの満足度と生産性は過去最高に達しています。
Elasticsearch + Sentinl/ElastAlertアラート、まさに最強です!
-
Dockerとは?コンテナ技術で開発・運用のワークロードを簡素化する完全ガイド
2013年に登場したDockerは、以来IT業界全体に大きな話題を巻き起こしてきました。Dockerが提供するコンテナ技術ベースのソリューションは、IT運用の在り方を根本から変えつつあります。 本記事では、現在のDevOpsパイプラインにおいて最も注目されている技術のひとつであるDockerについて、その仕組みやメリットをわかりやすく解説します。 Dockerが注目される理由 想像してみてください。自分の開発マシンでは完璧に動作していたアプリケーションが、QA環境や本番環境にデプロイした途端、動かなくなったら――。多くの開発者が経験したことのあるこの問題の背景には、「環境の違い」による依存関係
-
WhatsAppデータ復元ツールおすすめ4選|削除したチャット・写真・動画を簡単に復旧!
世界で16億人以上の月間アクティブユーザーを抱えるWhatsAppは、AndroidやiPhone、さらにはデスクトップでも利用できる、最も人気のあるメッセージングアプリの一つです。毎日のコミュニケーションに欠かせない存在だからこそ、チャット履歴や大切なデータを失ってしまうのは本当に怖いもの。どのスマートフォンを使っていても、誤操作による削除は誰にでも起こり得ます。この記事では、削除されたテキスト、写真、動画などの添付ファイルを復元できる、Android・iPhone対応の優秀なWhatsApp復元ツールをご紹介します。なお、WhatsAppをもっと便利に使いたい方は、「WhatsAppの裏ワ