44
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ateam LifestyleAdvent Calendar 2017

Day 2

Elasticsearchを活用したサービス監視ですこしだけ幸せになる

Last updated at Posted at 2017-12-01

エイチームライフスタイルアドベントカレンダー2017、2日目です。
本日は 株式会社エイチームライフスタイル のインフラエンジニア @ihsiek が担当します。

突然ですが皆さん、アクセスログを可視化していますか?
Elasticsearch+Kibanaでやってるよーというところもそこそこありますよね?

そこで今回は、**Elasticsearch上のデータを解析してアラートを投げる ElastAlert**というツールの導入手順と社内での運用方法について紹介していきます。

ちなみにこの仕組みを導入したことで、アラート本文を見るだけでサーバで起きている事象を瞬時に判断し、障害を切り分けられるようになりました。 :tada:
サーバのアクセスログどころか、Kibanaすら見なくてよくなった&経験の浅いメンバーがアラート対応に入れるようになったのが地味に幸せです。 :relaxed:

ElastAlertとは?

Elasticsearch上のIndexに対して、運用者が指定したある条件(クエリや監視ルールタイプ)に応じた通知を可能にするYelp社が開発したOSSツールです。

弊社では、このツールを使い、Elasticsearchに取り込んだアクセスログから、レスポンス遅延HTTPステータス500番台のエラーを検知する仕組みを導入しました。

当初は、指定した期間内にクエリとマッチするイベントがN件あったらアラート送信するFrequencyという監視ルールタイプを使用していました。
これではサービスごとのリクエスト数に応じて閾値を変えたりと運用が大変なので、現在は、指定した期間内にクエリとマッチするイベントがN%あったらアラートを送信するPercentage Matchを採用しています。

導入

ElastAlert

インストール

早速、ElastAlertをインストールします。
Elasticsearchは、運用しているバージョンにあわせてインストールしてください。
弊社ではElasticsearch 5系を運用しているため、以下のコマンドでインストールします。

$ sudo pip install "elasticsearch>=5.0.0" elastalert
$ elastalert -h
usage: elastalert [-h] [--config CONFIG] [--debug] [--rule RULE]
...

インストールはこれで完了です。

共通設定

次にグローバルコンフィグファイルを作成します。
--configオプションに定義するだけなので、どこに作成してもいいのですが、ほかの運用メンバーが迷わないように/etc/elastalert/config.ymlに作成します。

設定ファイル
/etc/elastalert/config.yml
# The Elasticsearch hostname for metadata writeback
# Note that every rule can have its own Elasticsearch host
es_host: elasticsearch.example.com

# The Elasticsearch port
es_port: 443

# Connect with TLS to Elasticsearch
use_ssl: True

# This is the folder that contains the rule yaml files
# Any .yaml file will be loaded as a rule
rules_folder: /var/lib/elastalert/rules

# How often ElastAlert will query Elasticsearch
# The unit can be anything from weeks to seconds
run_every:
  minutes: 2

# ElastAlert will buffer results from the most recent
# period of time, in case some log sources are not in real time
buffer_time:
  minutes: 5

# The index on es_host which is used for metadata storage
# This can be a unmapped index, but it is recommended that you run
# elastalert-create-index to set a mapping
writeback_index: elastalert_status

# If an alert fails for some reason, ElastAlert will retry
# sending the alert until this time period has elapsed
alert_time_limit:
  days: 1
設定ファイル(解説)
キー 内容
es_host 接続するElasticsearchのエンドポイントを指定します。
es_port 接続するElasticsearchのポート番号を指定します。
use_ssl SSL接続を選択する場合はTrueを指定します。
rules_folder 監視ルールを格納するパスを指定します。
ElastAlert実行時、このパスに格納されたルールが再帰的に評価されます。
run_every クエリをElasticsearchに投げる間隔(監視の間隔)を指定します。
buffer_time ログをバッファリングする期間を指定します。
1分間隔の監視で過去5分間に異常値が10回出現したらアラート送信するというケースでの利用が想定されます。
writeback_index ElastAlertのシステム用Index名を指定します。
alert_time_limit アラート送信に失敗した場合に再送をリトライする期間を指定します。

ElastAlertのシステム用Indexの作成

このままではElasticsearch上にElastAlertの監視ログなどを書き出せないため、以下のコマンドを実行してElasticsearchにIndexを作成します。

$ elastalert-create-index --config /etc/elastalert/config.yml

監視ルールファイル

先ほどグローバルコンフィグファイルで指定したパスに監視ルールファイルを格納していきます。
今回は監視対象Indexの更新状況・レスポンス遅延・HTTPステータスコードのエラー(以降、HTTP5XXエラー)を検知する3つのルールを設置します。

監視ルールのファイル自体は同一階層にまとめてもいいのですが、弊社では監視ルールごとに階層を分けてその下にサービス名ごとのファイルを置くことで管理しています。

$ sudo mkdir -p /var/lib/elastalert/rules/{logforward,response,status-5XX}

以下に監視ルールのサンプルを掲載しますが、詳細は公式のドキュメントを参考にしてください。

監視ルール - 監視対象Indexの更新状況

ElasticsearchのIndexが更新されなくなると根本が揺らぐため、Indexが更新されているかをチェックします。

設定ファイル
/var/lib/elastalert/rules/logforward/sample.yml
es_host: elasticsearch1.example.com
es_port: 443
use_ssl: True

index: access-log-*

name: No access log on hogehoge

type: flatline
threshold: 1
timeframe:
  hours: 1

timestamp_field: "time"

use_count_query: True
doc_type: access-log

alert:
- "email"
email:
- "hoge@example.com"
設定ファイル(解説)
キー 必須 説明
es_host グローバルコンフィグを上書きする場合に指定します。
es_port
use_ssl
index 監視対象のElasticsearchのIndexを指定します。
name 全監視ルールに対して一意な名前を指定します。
type 監視ルールタイプを指定します。
flatlineはイベント数thresholdを下回った場合にアラートを送信します。
threshold アラートのトリガとなる閾値(イベント数の下限)を指定します。
※flatlineを指定した場合、必須。
timeframe 閾値監視の期間を指定します。
1時間を指定した場合、1時間以内にイベント数がthresholdを下回った場合にアラートを送信します。
timestamp_field timestampを保持するフィールドを指定します。
use_count_query Count APIを使用するかどうかを指定します。
Trueを指定するとElasticsearchのCount APIを使用します。
doc_type Indexのdoc_typeを指定します。
※use_count_queryを指定した場合、必須。
alert アラートの通知方法を指定します。
email アラートの通知先メールアドレスを指定します。
※alertにemailを指定した場合、必須。

監視ルール - レスポンス遅延

設定ファイル
/var/lib/elastalert/rules/response/sample.yml
es_host: elasticsearch1.example.com
es_port: 443
use_ssl: True

index: access-log-*
doc_type: access-log

name: Response was delayed on hogehoge

type: percentage_match

match_bucket_filter:
- query_string:
    query: "response: >3000000 AND -path:(csv AND sitemap)"

max_percentage: 10

top_count_keys:
  - "host"
  - "agent"
  - "path"

timeframe:
  minutes: 5

timestamp_field: "time"

use_kibana4_dashboard: "https://kibana.example.com/#/discover/alert-response-hoge"

alert:
- "email"
email:
- "hoge@example.com"
設定ファイル(解説)
キー 必須 説明
match_bucket_filter アラートとして引っ掛けたい条件を定義します。
query_stringにはKibanaのクエリと同じものが使えるため、そちらであらかじめ想定通り動作するか確認することをお勧めします。
※percentage_matchの場合、必須。
max_percentage match_bucket_filterにマッチするイベントの出現比率の上限を指定します。
総イベント数に対する比率がこの閾値を上回った場合にアラートを送信します。
※percentage_matchの場合、min_percentage, max_percentagのいずれかが必須。
top_count_keys Indexの任意のキーを指定します。
match_bucket_filterにマッチするイベントのうち、top_count_keysに指定したキーをそれぞれ出現率の多い順に表示します。
use_kibana4_dashboard アラートの本文にKibanaへのリンクを挿入します。

flatlineと重複する説明は省略しています。

アラート本文

以下のようなアラートが送られるようになります。

Response was delayed on hoge.

Percentage violation, value: 10.5504587156 (min: None max : 10)

host.keyword:
xxx.yyy.zzz.aaa: 31
xxx.yyy.zzz.bbb: 13
xxx.yyy.zzz.ccc: 1
xxx.yyy.zzz.ddd: 1

agent.keyword:
Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/14A346 Safari/602.1: 31
Mozilla/5.0 (iPhone; CPU iPhone OS 11_1_2 like Mac OS X) AppleWebKit/604.3.5 (KHTML, like Gecko) Mobile/15B202 YJApp-IOS jp.co.yahoo.ipn.appli/4.8.9: 13
Googlebot-Image/1.0: 1
Mozilla/5.0 (iPhone; CPU iPhone OS 11_1_2 like Mac OS X) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0 Mobile/15B202 Safari/604.1: 1

path.keyword:
/sample1.jpg: 2
/sample2.jpg: 2
/sample3.jpg: 2
/sample4.jpg: 2
/sample5.jpg: 2

kibana_link: https://kibana.example.com/#/discover/alert-response-hoge?_g=%28refreshInterval%3A%28display%3AOff%2Csection%3A0%2Cvalue%3A0%29%2Ctime%3A%28from%3A%272017-11-24T16%3A27%3A28.717549Z%27%2Cmode%3Aabsolute%2Cto%3A%272017-11-24T16%3A37%3A28.717549Z%27%29%29
num_hits: 436
num_matches: 1
percentage: 10.5504587156
time: 2017-11-24T16:32:28.717549Z

監視ルール - HTTP5XXエラー

/var/lib/elastalert/rules/status-5XX/sample.yml
es_host: elasticsearch1.example.com
es_port: 443
use_ssl: True

index: access-hoge-*
doc_type: access-log

name: HTTP status 5XX on hoge

type: percentage_match

match_bucket_filter:
- query_string:
    query: "code: [500 TO 599]"

max_percentage: 1

top_count_keys:
  - "host"
  - "agent"
  - "path"

timeframe:
  minutes: 5

timestamp_field: "time"

use_kibana4_dashboard: "https://kibana.example.com/#/discover/alert-5xx-hoge"
alert:
- "email"
email:
- "hoge@example.com"

クエリ以外は、レスポンスの監視とほぼ同じなので説明は割愛します。

検証

監視ルールの準備が完了したので検証してみます。
検証にはelastalert-test-ruleを使用します。

$ elastalert-test-rule --config /etc/elastalert/config.yml

実際にアラートを飛ばしてみたいときは、--alertをつけて先ほどのコマンドを実行してください。
検証でエラーが出なければ、下準備は完了です。

運用

ここからは実際に本番環境で運用する際に行ったことと、本番運用を開始してトラブったことを少しだけ紹介していきます。

デーモン化

ElastAlert自体にデーモン化する機能がないため、Supervisorを使ってDaemon化してしまいます。

Supervisor

インストール

まずはSupervisorをインストールします。

$ sudo pip install supervisor

設定ファイルの作成

次に設定ファイルを用意します。
設定ファイルは、ElastAlertプロジェクトに用意されているサンプルも参考にしてみてください。

/etc/supervisord.conf
[unix_http_server]
file=/var/run/supervisor.sock

[supervisord]
logfile=/var/log/supervisord.log
logfile_maxbytes=1MB
logfile_backups=2
loglevel=warn
nodaemon=false
directory=%(here)s

[inet_http_server]
port = 127.0.0.1:9001

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/run/supervisor.sock

[program:elastalert]
command=elastalert --config /etc/elastalert/config.yml --verbose
process_name=elastalert
autorestart=true
startsecs=15
stopsignal=TERM
stopasgroup=true
killasgroup=true
redirect_stderr=false
stderr_logfile=/var/log/supervisord/elastalert_stderr.log
stderr_logfile_maxbytes=1MB
stderr_logfile_backups=5

Supervisorの起動

Supervisorの本体を起動します。
$ supervisord -c /etc/supervisord.conf
SupervisorからElastAlertをデーモンとして起動します。
$ supervisorctl start elastalert

supervisorのinitスクリプト設置

サーバーが再起動されても大丈夫なように、こちらの記事を参考にinitスクリプトを設置します。

$ sudo curl -o /etc/rc.d/init.d/supervisord https://raw.githubusercontent.com/Supervisor/initscripts/master/redhat-init-equeffelec
$ sudo chmod 755 /etc/rc.d/init.d/supervisord
$ sudo chkconfig --add supervisord

これでElastAlertのデーモン化が完了しました。
とりあえずの運用はここまででも大丈夫かと思います。

ElastAlert導入の注意点

ElasticsearchのCPUリソースに気を付けましょう

当初のElasticsearchの運用では、障害分析などのタイミングでログを見るために使うくらいしか想定していなかったため、Amazon Elasticsearch Service(ES)のt2.microを使っていました。
ElasticAlertを導入し毎分クエリが投げられるようになったことで、CPUリソースを食い潰す事象が発生したため、ESのスケールアップとクエリの実行間隔(run_every)の見直しをしています。
どの程度リソースを消費するのか見えにくいと思うので、導入初期はCPUリソースの監視をしっかり行ったほうがいいと思います。

top_count_keysのサマリが実は・・・。

監視期間の全数からサマリが作られてしまうため、「監視期間中、HTTPステータスコード5XXになった」イベントの上位5件を見ているつもりが、監視期間の全数に対する上位5件が表示されてしまい、まったく見当はずれな情報になっています。
なので、「監視期間中、HTTPステータスコード5XXになった」イベントのURIを確認したいという場合、監視ルールをカスタマイズする必要があります。
この監視ルールをカスタマイズしたスクリプトも用意していますが、今回の記事が相当なボリュームになってしまったので、次の機会に紹介します。
==2017/12/23 追記==
ElastAlertの監視ルールをカスタマイズする方法を別記事にまとめました。
サンプルコードも記載しているので、参考にしてみてください。
ElastAlertの監視ルールを拡張してすこしだけ幸せになる

参考

最後に

エイチームライフスタイルアドベントカレンダー2017の2日目、いかがでしたでしょうか。
明日は株式会社エイチームライフスタイルでフロントエンドからインフラまで幅広く担当している @maa0984 さんが ReactNative に関する記事を書いてくれるらしいので、お楽しみに。


株式会社エイチームライフスタイルでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。興味を持たれた方はぜひエイチームグループ採用サイトを御覧ください。
http://www.a-tm.co.jp/recruit/

44
30
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
44
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?