SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

イベントレポート

サイバーエージェントのエンジニアがハマった・失敗したポイントを語る「オレシカナイト Vol.1」イベントレポート


  • X ポスト
  • このエントリーをはてなブックマークに追加

3. Elastic Stackにstuckした話(小坂 和弘)

 次は小坂の発表です。企業ユーザのオペレーションエビデンスを永続化・可視化するにあたって、Elastic Stackを活用した経験談です。

Elastic Stackの用途・導入経緯

 私たちは現在、主に各メディアへの広告配信設定を運用・管理するためのWebアプリケーション上のユーザ操作履歴を収集・検索するためにElastic Stackを利用しています。ユーザ操作履歴を集約し、一元的に検索できる必要があったのですが、一番早く、かつ簡単に実現できる方法としてAmazon Elasticsearch Serviceが選択されました。サイバーエージェントでは、Fluentdが使われることが圧倒的に多かったので、Elastic Stack(当時はまだELK Stackと呼ばれていました)について、知見を溜めておきたいという理由も背景にはありました。現在MDH内では、システムのパフォーマンス計測、ジョブの実行結果の集計にも一部使われています。

動作している環境

 環境ですが、私たちはAmazon Elasticsearch ServiceでElasticsearchのバージョンは1.5を使っています(構築当初は2.3も選べなかったのですが、現在では5.1も選べるようになりましたね!)。その他にログ収集サーバでフィルタパイプラインであるLogstashが、各Webアプリケーションサーバでログ転送エージェントであるFilebeatが立ち上がっています。これらはElastic Beanstalkで構築されています。

 ちなみに、Elasticsearchにストアされるドキュメント数は1日40万件ほどになりますが、このうち約95%は自動化処理からのリクエストによるものです。検索クエリの条件指定で除外が可能ですが、検索パフォーマンスやメンテナンスの面から、純粋なユーザ操作履歴のみを別インデクスに分離する予定となっています。

 ログ収集サーバとして使用しているLogstashでは、Beats InputでFilebeatから受け取ったログデータを一旦、ほぼ生の状態でローカルファイルに書き込むようにしました。それらをスクリプトとcronを使い、定期的にS3にコピーを行うことで、各Webアプリケーションサーバの生ログを集約された状態で残しています。さらに、そのローカルファイルを再度LogstashのFile Inputで読み込み、不要な情報の削除や加工といったフィルタリングを行い、最終的にElasticsearchに転送されているわけです。特にメッセージキューを入れたりはせず、シンプルな構成になっています。

データロスとの戦い

 キューは入れていないのですが、最初にLogstashを検討した際に悩んだのが、どうやってデータロスを防ぐかということでした。Filebeatはバックプレッシャーに対応しているのと、どこまで転送が完了したかとインデクスで管理しているため、ログを転送し損ねることはなさそうでしたし、データソースがファイルですから、オリジナルのログデータが失われる心配はほぼ必要ありませんでした。しかし、Logstashはバージョン5.1でキューをディスクにバッファする機能がベータリリースされたものの、私たちが導入した当時の最新バージョン2.3では、その機能はまだありませんでした。

 LogstashのInput-Filter-Outputというパイプラインにおいて、Input-Filter、Filter-Outputのそれぞれの間はメモリ上にデータがキューされています。データがこのキュー上にある状態でLogstashのプロセスがクラッシュした場合、データが失われる可能性があるわけですね。前述の通り、今回のケースでは、オリジナルのログデータはファイル上に残っていますので、再転送させることでデータロスを回避できますが、そうではない場合では、何かしらのキューをBeatsとLogstashの間に入れることを検討する必要があったでしょう。その際、Kafkaであれば、オフセット情報を元にデータの再送信が可能なようです。その他のキューでは、少し工夫が必要かもしれません(この辺りはまだ検証しきれていません!)。

 いずれにせよ、データの再転送(再送信)ができればデータロスは防ぐことができるわけですが、すでにElasticsearchにストアされているデータを再転送することで、今度はドキュメントの重複が問題になります。これには、Logstashのフィルタでデータのハッシュ値を取り、それをドキュメントIDとして使うことで、既にElasticsearch上に存在するデータに上書きしてくれるので、ドキュメントの重複を簡単に防ぐことができます。

 今回のケースでは、リアルタイムでの検索性は要求されていないこともあり、万が一Logstashがクラッシュした場合は、Filebeatのレジストラファイル(どこまで転送が完了したかが記録されているインデクスファイル)を削除して、ログを再転送させる方法でデータロスを防ぐこととしましたが、運用中にLogstashがクラッシュした経験はまだありません。非常に安定して動いてくれています。

デフォルト設定の罠

 このように、Logstashは安定しているのですが、Elasticsearchではいくつか障害が発生しました。そのうちひとつを紹介したいと思います。

 これは、Elasticsearch 1.5でのみ発生すると思われるので、最新の環境を利用している場合は考えなくても良いかと思いますが、ある時、突如としてElasticsearchに書き込みができなくなりました。AWSコンソールのモニタリングで状態を調べてみると、JVMMemoryPressureの値が高い状態で張り付いていましたが、まだ幾分余裕はありそうな状態でした。しかし、FreeStorageSpaceには全く問題がなく、ディスクスペースが原因ではなさそうでした。

 当初、メモリは検索には影響が出ても、書き込みに影響するようなことはないだろうと思い込んでいましたが、AWSのドキュメントを読んでいると「t2インスタンスを利用している場合、JVMMemoryPressure値が92%の達すると書き込みをブロックする」ということが書かれていました。その時はt2インスタンスは使っていなかったので、これをヒントにメモリが原因ではないかという線で調査を開始しました。そしてメモリを増やしたら書き込みが再開されるかどうか確かめるために、メモリをより多く持つインスタンスに替えてみたところ、書き込みが再開されました。やはりメモリが原因のようでした。

 Amazon Elasticsearch Serviceではコンソールから設定できる項目は数少ないのですが(簡単に使い始められるとも言えますし、ユーザ毎に違う様々な利用方法に対して安定したサービスを提供するためには仕方ないのだと思います)、なんと、indices.fielddata.cache.sizeが未設定のままになっていました。この設定値が未設定の場合、Elasticsearchは際限なくメモリを確保しようとするようです。その際にfielddataとは、ドキュメントの各フィールドの値をインデクス化したようなものだと理解しました。現在は設定値を50%にして様子を見ていますが、Elastic社のドキュメントを読むと、十分な未使用メモリが残っていない場合、Lucene(Elasticsearchの検索エンジン)ファイルシステムへのアクセスパフォーマンスが出ないとのことです。

 さらに、Elasticsearch 1.x系では、Doc Values設定がデフォルトでオフになっていることがわかりました。これはLucene側の仕組みですが、これにより、メモリ上に保持された情報をディスクに逃がすことでメモリ使用量を抑えることが可能です。インデクステンプレートのマッピング設定で明示的にオンと設定することで、さらにメモリ使用量を抑えることができています。Doc Values設定はバージョン2.x系以降ではONとなっています。

その他、Amazon Elasticsearch Service特有の制限たち

 最後に、前述した設定できる項目の少なさと同様に、Amazon Elasticsearch Serviceは制限がいくつかあることがわかりました。クエリでスクリプトが使えないので、複雑な検索や操作、例えば、ある条件式を満たすドキュメントを一括削除したいといった場合に、スクリプトクエリ以外の方法を模索することになるでしょう。また、Amazon Elasticsearch ServiceがVPC外にある関係上、アクセスコントロールはIPベース、またはIAMベースとなっています。このIAM認証をLogstashから簡単に行えるようにと、AWSからLogstashのoutputプラグインが公開されていますが、同じ環境、同じ設定で運用中に、ある日を境に接続ができなくなったということがあり、現在はIPベースでのアクセス許可を行っていますが、オートスケールした際は接続ができなくなってしまう、といった課題が残ってしまっています。

今後の動き

 これらを踏まえて、私たちはAmazon Elasticsearch ServiceからElastic社のクラウドサービスである、Elastic Cloudへの移行を進行中です。より少ない制限と常に最新バージョンがリリース直後から使えるのは魅力的ですね。完全に制限のない環境が必要なケースでは、Elastic Cloud Enterprise版という選択肢も出てきました。もちろん自前でクラスタを構築するという選択肢もありますが、インフラを含め、メンテナンスやチューニングのコストをどう捉えるか次第ではないでしょうか。

 Elastic社がPrelert社を買収したことにより、教師なしの機械学習での不正検知が可能になるなど、今後もElastic Stack界隈の進化に期待したいと思います。

次のページ
4. フロントエンドでGraphQLを使った所感(李 超)

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
イベントレポート連載記事一覧

もっと読む

この記事の著者

平松 紘典(株式会社サイバーエージェント)(ヒラマツ コウスケ)

 サイバーエージェント メディア広告部門(MDH) チーフアーキテクト 2011年サイバーエージェントに中途入社。スマートフォンPigg、Amebaスマートフォンプラットフォーム、ブログ等を担当。 現在は広告配信システムの開発チームにて、プログラマ/アーキテクト/クラウドインフラなどを担当している。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

海老澤 直樹(株式会社サイバーエージェント)(エビサワ ナオキ)

 株式会社AbemaTV/サイバーエージェント メディア広告部門(MDH) 兼務 2011年サイバーエージェントに中途入社。オフィシャルブログ、アメスタ、GAMYで主にJavaを使ってサーバーサイドを担当。現在はAbemaで広告入稿の支援ツールをScalaやGoで作ったり、AWSのインフラを担当して...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

小坂 和弘(株式会社サイバーエージェント)(コサカ カズヒロ)

 2009年サイバーエージェントへ入社。Pigg、ゲーム部門でのバックエンド、フロントサイド開発を担当。2015年よりメディア広告部門(MDH)にて広告運用管理画面の機能実装と関連サーバアプリケーションの開発を主に担当している。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

李 超(株式会社サイバーエージェント)(リ チョウ)

 サイバーエージェント メディア広告部門(MDH) 2015年サイバーエージェントへ中途入社。メディア広告部門(MDH)にて、フルスタックを目指しながらフロントエンジニアとして従事。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/10218 2017/06/20 18:21

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング