Logstash にデータロストを防ぐ キュー永続化機能(Beta)がリリースされました
こんにちは、藤本です。
先月に Elastic Stack の 5.1.1 がリリースされました。その中で Logstash にキュー永続化機能のベータがリリースされていたので試してみました。
Logstash とキュー永続化
Logstash はインプット → フィルター → アウトプットと大きく 3つの処理でデータ転送を行います。例えばインプットはファイルからデータを取り込だり、AWS の S3 からオブジェクトを取り込んだり、JDBCを利用してデータベースへクエリを投げてデータを取り込んだりすることができます。フィルターはアクセスログといった決まった形式のログメッセージをフィールド分割したり、任意の日時フォーマットを異なる日時フォーマットに変換したり、フィールドを追加/複製/削除したりすることができます。アウトプットは Elasticsearch にインデキシングしたり、JDBCを利用してデータベースにインサートしたり、datadog にメトリクスとして送信したりすることができます。様々なファイルをデータソースにElasticsearchへデータ投入する、データベースをデータソースにElasticsearchへデータ投入するのエントリでいくつかの例をご紹介しているので、ご参照ください。
Logstash は一つ一つの処理をパイプラインとして繋いでおり、メモリでデータを受け渡すことで高速な処理を実現しています。しかし、その一方でメモリ内に保持することによりパイプラインの途中で障害などにより Logstash プロセスが落ちた場合、処理途中でメモリにキューイングされたデータは転送されなくなる可能性があるという問題を抱えていました。それがついに Logstash でもディスクにキューイングする機能が追加されました。ディスクにキューイングすることで処理途中で Logstash プロセスが落ちても、ディスクにデータがストアされているため、データが消失しません。嬉しいですね!
約1年前の Elastic{ON} で発表されたロードマップの機能がリリースされました。
ちなみに似た役割のツールである Fluentd はファイルバッファ機能を備えています。
試してみた
それでは具体的にメモリキュー、ディスクキューでどのような差異があるのか見てみましょう。下記 2つの観点で見てみました。
- 障害時の挙動の差異
- パフォーマンスの差異
環境
- Logstash
- OS : CentOS 7
- Logstash : 5.1.2
- Elasticsearch
- OS : CentOS 7
- Elasticsearch : 5.1.2
利用するパイプライン設定
今回はサンプルとして以下のようなパイプラインで検証しています。
- ELBのアクセスログ 10万件をファイルインプットで取り込む
- grok、date、geoip、useragent のフィルターでデータ変換する
- アウトプット先として別サーバの Elasticsearch にインデキシングする
/etc/logstash/conf.d/elb.conf
input { file { path => [ "/tmp/elb.log" ] start_position => "beginning" } } filter { grok { match => { "message" => "%{ELB_ACCESS_LOG}" } } date { match => [ "timestamp", "ISO8601" ] locale => en } geoip { source => "clientip" } useragent { source => "agent" target => "useragent" } } output { elasticsearch { hosts => ["10.255.0.100"] } }
キュー設定
logstash.yml
にQueueの設定が追加されました。queue.type
がキュータイプの設定になります。キュータイプの値を変えることでメモリにキューするのか、ファイルにキューするのか選択することができます。
タイプ | 設定値 |
---|---|
メモリキュー | queue.type: memory |
ファイルキュー | queue.type: persisted |
障害時の挙動の差異
まずはキュー設定をメモリ/ファイルによって、Logstash プロセスがダウンするような障害時にどのような挙動の違いがあるか確認してみます。
メモリキューの場合
まずはメモリキューの挙動です。メモリキューはデフォルト設定なので設定ファイルはそのままで変更不要です。Logstash のプロセスを起動します。
# systemctl start logstash
しばし、待ちます。データが入ってきたタイミングで Logstash を停止(kill)します。
# kill -9 $(pgrep java) # curl 10.255.0.100:9200/_cat/indices yellow open logstash-2016.12.22 tQ_Z_sxMQYKvfAdCfOvTKQ 5 1 16092 0 105.3mb 105.3mb yellow open .kibana TuK3j9xhQfSFLXPeOM-QUQ 1 1 1 0 3.1kb 3.1kb
Elasticsearch には 16,092件取り込まれています。それでは再度、Logstash のプロセスを起動します。
# systemctl start logstash
しばし、待ちます。
# curl 10.255.0.100:9200/_cat/indices yellow open logstash-2016.12.22 tQ_Z_sxMQYKvfAdCfOvTKQ 5 1 16092 0 105.3mb 105.3mb yellow open .kibana TuK3j9xhQfSFLXPeOM-QUQ 1 1 1 0 3.1kb 3.1kb
データ件数は増えませんでした。プロセスがダウンしたことにより、ファイルから取り込んでメモリにキューイングしたデータが消失したからです。
次の検証を実施する前にsincedb
とインデックスが残っているので削除します。
# rm /usr/share/logstash/data/plugins/inputs/file/.sincedb* rm: remove regular file ‘/usr/share/logstash/data/plugins/inputs/file/.sincedb_61bfae04417018879917486181e01d8b’? y # curl -XDELETE "10.255.0.100:9200/logstash*" {"acknowledged":true}
ディスクキューの場合
続いて、ディスクキューです。キュー設定をファイルに変更し、同じことを試してみます。
/etc/logstash/logstash.yml
path.data: /usr/share/logstash/data path.config: /etc/logstash/conf.d queue.type: persisted path.queue: /usr/share/logstash/data/queue path.logs: /var/log/logstash
メモリキューを同じように確認します。まずは Logstash プロセスを起動します。
# systemctl start logstash
しばし、待ちます。データが入ってきたタイミングで Logstash を停止します。kill で落としても別プロセスで上がってくるのでサーバを停止しました。
# curl 10.255.0.100:9200/_cat/indices yellow open logstash-2016.12.22 bXb3E6TOS3qCC8fGXOl9kw 5 1 25750 0 26.8mb 26.8mb yellow open .kibana TuK3j9xhQfSFLXPeOM-QUQ 1 1 1 0 3.1kb 3.1kb
Elasticsearch には 25,750件取り込まれています。それでは再度、サーバを起動し、Logstash プロセスを起動します。
# systemctl start logstash
しばし、待ちます。
# curl 10.255.0.100:9200/_cat/indices yellow open logstash-2016.12.22 bXb3E6TOS3qCC8fGXOl9kw 5 1 101250 0 89.2mb 89.2mb yellow open .kibana TuK3j9xhQfSFLXPeOM-QUQ 1 1 1 0 3.1kb 3.1kb
データのインデキシングが継続されました!が、タイミングによっては重複されるようです。バルク単位でキュー管理していて、そのタイミングによるのかな。
キュー永続化有無によるパフォーマンスの差異
次にキュー設定をメモリ/ファイルによって、パフォーマンスにどの程度の違いがあるのか確認してみます。先ほど同じ 10万件のメッセージが入った ELB のアクセスログを Elasticsearch に取り込むのにどの程度の差があるのか確認してみます。
メモリキューの場合
まずはメモリキューのパフォーマンスです。
キュー設定を変更します。
/etc/logstash/logstash.yml
path.data: /usr/share/logstash/data path.config: /etc/logstash/conf.d queue.type: memory path.queue: /usr/share/logstash/data/queue log.level: debug path.logs: /var/log/logstash
データを取り込みを実施します。
# systemctl start logstash
Elasticsearch に 10万件のデータが取り込まれるまで待ちます。
# curl 10.255.0.100:9200/_cat/indices yellow open .kibana TuK3j9xhQfSFLXPeOM-QUQ 1 1 1 0 3.1kb 3.1kb yellow open logstash-2016.12.22 Mh4CGNxBTBeX90kOR5a9WQ 5 1 100000 0 84.6mb 84.6mb
開始時間と完了時間をログから確認します。
[2017-01-22T14:20:12,712][INFO ][logstash.pipeline ] Pipeline main started : [2017-01-22T14:22:13,695][DEBUG][org.apache.http.impl.conn.PoolingHttpClientConnectionManager] Connection released: [id: 0][route: {}->http://10.255.0.100:9200][total kept alive: 1; route allocated: 1 of 100; total allocated: 1 of 1000]
たぶん、この辺のログかなー。メモリキューの場合は、2分1秒ぐらいです。
ディスクキューの場合
続いて、ディスクキューのパフォーマンスです。
キュー設定を変更します。
/etc/logstash/logstash.yml
path.data: /usr/share/logstash/data path.config: /etc/logstash/conf.d queue.type: persisted path.queue: /usr/share/logstash/data/queue log.level: debug path.logs: /var/log/logstash
データを取り込みを実施します。
# systemctl start logstash
Elasticsearch に 10万件のデータが取り込まれるまで待ちます。
# curl 10.255.0.100:9200/_cat/indices yellow open .kibana TuK3j9xhQfSFLXPeOM-QUQ 1 1 1 0 3.1kb 3.1kb yellow open logstash-2016.12.22 CU6wcL_yRJOt4cGXpy5D6Q 5 1 100000 0 86.7mb 86.7mb
開始時間と完了時間をログから確認します。
[2017-01-22T11:46:02,559][INFO ][logstash.pipeline ] Pipeline main started : [2017-01-22T11:48:20,369][DEBUG][org.apache.http.impl.conn.PoolingHttpClientConnectionManager] Connection released: [id: 0][route: {}->http://10.255.0.100:9200][total kept alive: 1; route allocated: 1 of 100; total allocated: 1 of 1000]
2分18秒ぐらいです。10万件で17秒差なのでそこまで大きな差ではないかな、システムによっては許容できないかもしれませんね。
まとめ
いかがでしたでしょうか?
Logstash に待望のキュー永続化機能が追加されました。キューをメモリにするか、ディスクにするかはパフォーマンスか、データ保全かのトレードオフです。ただ、環境に合わせた選択肢が追加されたことは嬉しいですね。まだベータ機能ですので正式リリースが待ち遠しいです。