大きくなってきたIoTプロダクトのログ活用について 〜Amazon Elasticsearch Service篇〜
ども、id:kazuph1986 です。この記事は、Akerun Advent Calendar 2018の1日目の記事です。
今回は弊社のログの活用をするためにサクッとElasticsearchを導入して業務改善を行った話をします。
背景
弊社では利用関連のデータはすべてDBに保持しており、データをRails consoleやRedashを用いて確認・分析を行っております。
ですが、IoT機器自体のログをすべてDBに含めるのは(負荷・量・金銭コスト的に)無理があったため、そのままサーバーのログとして吐き出しているだけのものもあります。
弊社ではログの収集については、
- リアルタイムにCloudWatchLogsに送信
- 日次でS3に送信
しており、それぞれ
- 短期間の生ログの確認用
- 長期間の保存用
という分け方をしていました。
サポートのために弊社のカスタマーサポート(以下、CS)のメンバーと一緒にエンジニアが調査を行うことも多いのですが、このCloudWatchLogsの方のデータについては、クエリや集計の弱さ、AWS Conosleの権限の中にエンジニア以外が含まれてくる煩雑さ(IAM)等の理由により、そのままではCSメンバーには提供してませんでした。そのためエンジニアが調査作業のたびにCSから依頼を受け、AWSのconsoleを開きログの確認をせざるを得ない状況になっていました。
解決方法
そ・こ・で!どうしようと思っていた時にAWSのCloudwatchLogsがElasticsearchへの吐き出しに標準で対応していると知り、
「もしかして一瞬でできる??」
と思いやってみたのでした。
結果的に1日くらいの工数で構築できたので、もし似たようなケースであれば、かなりおすすめです。 しかも僕はハマってしまったので1日でしたが、わかっていれば1, 2時間くらいで終わると思います。
はまりポイントは以下でした。最も時間がかかったのが地味に一番上のやつです。AWS力を上げないとなと思いました。
- デフォで生成されるvpc*********.comのURLがPrivate IPのを返却していると気づいてなかった(EC2のような感覚でネットワークパスを通そうとしてしまった)
- 弊社のログがLTSV形式だったのでLambda側のパースの処理でちょっと試行錯誤が必要だった
- Elasticsearch自体のindexの概念の学習コスト
それでは実際にやってみましょう!
1. Elasticsearchのインスタンスを立ち上げる
AWSは「Amazon Elasticsearch Service(以下、ES)」というフルマネージドなサービスを提供しています。 ESの画面に行ったら「新しいドメインの作成」からサクッと作成できます。
次の画面で、ドメイン名とESのバージョンの指定ができます。
次へを押すと、インスタンスタイプ等の設定画面に行きます。最初はt2系で立てたのですが、インスタンスのタイプ毎にストレージ上限が決まっているため、容量が必要になるたびに増やす必要があります。ただ一旦低いので立てておいて、あとからスケールアップするのは簡単だったので、お試しではt2でも問題ないかもしれません。ちなみにt2系はすべて35Gが上限です。
次にネットワーク構成を選択します。ほとんどの場合社内利用だと思いますので、VPCアクセスで問題ないと思います。
次に認証ですが、AWSのCognitoを挟むこともできますし、単にVPCでのアクセス制限もできます。今回は「IAM認証情報を使用した署名リクエストを要求しない」にしました。
これで必須のものを全部選択して、確認画面に行き、「確認」を押すことでインスタンスの生成がはじまります。
2. CloudWatchLogsとの連携
連携は非常に簡単です。ESへのストリーミングを開始を押し、
先程作成したESのクラスタとログの形式を指定します。 右下の「ストリーミングを開始」ボタンを押すと即刻連携がはじまります。
簡単ですね^^
3. (必要なら)Lambdaを編集する
上記まで完了するとLambdaの関数も自動で作成されます。 そうです、実は、連携と言って起きながら、AWSさんはそれを実現するためのLambdaを作成しているだけなのでした。
Lambdaですので、普通のソースを編集できます(JS)。
弊社ではログをLTSVで出力しているため、これをES様に変換するスクリプトに修正します。
100行目くらいにある buildSource
を少し修正します。
function buildSource(message, extractedFields) { var log={}; // LTSVとしてパースする message .split(/\t/) .map(function(s) { var res = s.match(/(.+?):(.*?)$/); return [res[1], res[2]]; }).map(function(ary){ log[ary[0]] = ary[1] }); // 必要に応じて方を合わせる // 特にnumber型にしたいが、空となってしまう場合は代替の数字を用意する // ES側でindexの修正でも対応できるが、日次でindexを作り直す場合に戻ってしまうので、 // 出力側で注意する log['time'] = moment.parseZone(log['time'], 'DD:hh:mm:ss').toISOString(); log['size'] === '-' ? -1 : parseInt(log['size']) log['reqtime'] === '-' ? -1.0 : parseFloat(log['reqtime']) return log; ... }
型が合わないとES側で適切に検索・集計ができないので、おそらくここで試行錯誤することになります。 基本的に今回はストリームを想定しているので、過去分を間違って登録してしまった場合は、ES側のデータを全部吹っ飛ばすなどしてやり直しましょう。
逆に過去分を全部集計するような場合は、またS3+Athenaが向いていると思うので、それは別途書きます。
4. ESのkibanaを見れるようにする
上記までがうまくいっていると、実際にESの方で可視化ができるようになります。 AWSで構築するESには最初からkibanaというビジュアライゼーションツールが入っているので、こちらを利用しましょう(AWSだからというかESについている)。
kibanaのURLもESの管理画面から確認できます。
ですが、冒頭言ったように、普通にこのvpc〜のURLをクリックしても、VPC内のPrivateなIPを返すため、会社などのPCからはそのままでは閲覧できません。 VPCに対してVPNを張るか、プロキシサーバーやLBを追加する必要があります。
弊社では、社内閲覧のために以下の2種類の方法を使っています。
- Route53 + ALBで見えるようにする
- プロキシサーバーを構築して見えるようにする
ALBを利用する方法については、クラスメソッドさんの記事が詳しいです。
本当の意味でPublicにするかは設定次第で、弊社では社内IPからのみ許可するようにALBのセキュリティグループを設定しています。
Route53にてわかりやすいドメインをつけることで、社内での利用がしやすくなっています。
またプロキシサーバーについてはsquidを用いてサクッと構築してます。 こちらについても、プロキシサーバー自体の記事を別日程で書く予定なので、そちらを待ちください。
というわけでこんな感じでKibanaが見れるようになるので、あとはKibanaのビジュアライゼーションツールによって様々なグラフが生成できます。 またAPIも充実しているので、IN/OUTで色々な用途に利用できそうです。
まとめ
DBにないログの情報を活用するためにESを構築する方法を紹介しました。 構築もAWSのUIに則って作業することで、半自動で構築が可能です。 すごい便利ですね。
実は、これをやるにあたり、目黒のAWS Loftにいるソリューションアーキテクトの方に相談に乗ってもらいました。 最初はAthenaでやるつもりで相談したら、ESの方法を紹介してもらい、そこまで便利そうならということで、ESを選択しましたが大正解でした。
こんな感じで、単に質問に答える以上に提案ももらえるのはありがたいことです。 東京にいるならサクッと相談できるLoftの利用は最高に便利です。AWSを利用しているのであれば誰でも入れますので、気軽に行ってみてくださいね!
それでは。
弊社ではデータ分析に興味があるWebエンジニアの方も募集しております。 詳しくを以下を御覧ください。