「Microservices Meetup vol.6」に行ってきた

2017/1/19のデイリーストックランキングにランクインしました。

【毎日自動更新】Qiitaのデイリーストックランキング!ウィークリーもあるよ_-_Qiita.png


いままでの。
「Microservices Meetup vol.2」行ってきたメモ。
「Microservices Meetup vol.4」に行ってきた

図らずして1回おきに参加してますね。

Connpassのイベントページ

少し間が空いてしまったがまた定期的に開催していきたいです。
登壇したいよーって人は直接リプ投げてください
by @qsona さん

Microservices on AWS by @Keisuke69 さん

Keisuke Nishitani @ AWS

Specialist Solutions Architect

サーバーレスアプリケーション開発ガイド 2月発売

マイクロサービスのポイント

  • 管理運用まで含めて分散型
  • 各コンポーネントが独立している
    • 単独で実行できないのは適切に設計されていない

独立して分散していると負荷の高い機能の単位でスケールさせられる=コスト効率が良い

  • 一つのことをうまくやる

    • 複雑化したら分割する
  • 多言語

    • チーム(機能)にはそれぞれの問題に対して適切なツールを選択する自由がある
    • OS、言語、各種ツールに至るまで最適なアプローチを目指せる
  • 検索:Elasticsearch / Solr

  • ソーシャル:グラフDB

  • ログデータ:Cassandra

  • セッション:Redis

†AWSでは:AWSには100ちょいのサービスがあって、その中で更にチームが分かれている。
各チームに社内標準の開発プロセスは存在しない。

  • ブラックボックス

    • 詳細は外部のコンポーネントに公開されない
  • DevOps
    • マイクロサービスにおける組織原理

†AWSでは:運用のみのチームはない。オンコールも開発チームが請け負う

  • 俊敏性

    • 狭い範囲のコンテキストで活動=サイクルタイムが短い
    • システムもシンプル
    • パラレルな開発とデプロイが可能
  • イノベーション

    • 選択に対する権限と責任を持つのでイノベーションを起こしやすい
    • DevとOpsの対立がないため、効率化やイノベーションが起こしやすい
  • 拡張性

    • 適切に非干渉化されてていることで水平方向に単独にスケールできる
  • 可用性

    • ヘルスチェック、キャッシング、隔壁、サーキットブレーカーと言った仕組みは全体の可用性を向上させる

課題

  • 分散型であることは難しい

    • システム数が増える
    • 協調動作の難しさ
    • コンポーネント間のコミュニケーションメッセージ増によるレイテンシ低下
    • ネットワークの信頼性は無限ではない、帯域も無限ではない
  • 移行が大変
    • モノリシックなシステムの分割は難しい
  • 組織
    • 組織体制の変更が必要になるが、それは大変なこと
  • アーキテクチャの難易度
    • 非同期通信
    • データ整合性
    • やっぱりココが一番の課題
    • サービスディスカバリ
    • 認証
  • 運用の複雑さ

アーキテクチャ

一番シンプルなパターン

CloudFront – ALB – ECS – datastore(ElastiCache, Dynamo, )
|
S3

  • バックエンドをRESTfulなAPIにしたSPA
  • 静的なコンテンツはS3とCloudFront
    • CDN通すことでレイテンシが上がることもある
    • キャッシュとの併用を検討
  • ECSとAutoScalingをALBとともに使うことが多い
    • ALB(L7LB)でアプリレベルの情報をルーティング
    • コンテナインスタンスにリクエストを分散
    • ECSのコンテナを負荷に応じてスケールアウト/インする

コンテナのメリット

  • Portable
  • Flexible
  • Fast
    • 軽量で早い
    • ポータビリティと関連して開発サイクルも早く
  • Efficient

  • 一貫性のある環境

  • バージョン管理出来る

Dockerの特徴

  • Package
  • Ship
  • Run

ECS

  • 複数のコンテナをEC2のクラスタ上で一元管理

    • まだTokyoにきてないけど、FargateでEC2の管理もいらなくなるよ
    • EKS(Kubernetes)も発表されています

データストア

  • インメモリ

    • Memcached, Redis
    • ElastiCache
    • DB負荷の軽減
  • RDBMS
    • 無限のスケーリングには向いていない
    • Amazon RDS
  • NoSQL
    • 水平スケーリングをサポートするものが多い
    • テーブル結合ができないのでロジックの実装が必要になる場合も
    • Amazon DynamoDb, KynamoDB Accelarator(DAX)

APIの実装

  • APIの設計、改善、デプロイ、モニタリング、保守派手間がかかる
  • 異なるバージョンが混在すると大変

Amazon API Gateway

  • 複数バージョンとステージ
  • Cognite User Poolsと連携して認証を追加
  • スロットリング、モニタリング
  • バックエンドとしてLamdbaが使える

サーバーレス

  • サーバーはないに越したことはない
  • スケーリングと高可用性の担保が大変
CloudFront - API Gateway - Lamdba - datastore
   |                            (ElastiCache, Dynamo)
   |
  S3

課題をAWSでどうするか

サービスディスカバリ

  • お互いの死活確認や発見
  • ハードコードするとスケールできない

    • メタデータをどこに置くか
  • ALBを利用したサービスディスカバリ

  • DNS(Route53)のサービスディスカバリ

    • VPC単位の振り分け
  • ECSイベントストリームを使用したサービスディスカバリ

    • CloudWatchイベントで拾ってキック
    • LamdbaでRoute53に登録
    • これが一番多いかも
  • DynamoDBを使用したサービスディスカバリ

    • DNSキャッシュの問題がない
    • 自由度が高い
    • 実装が大変
    • DynamoDBストリームを活用して他のサービスへステータス変更を反映
  • イベントベースのアーキテクチャ

    • イベントで処理する
    • いわゆる結果整合性とも関連
    • Dual Write Problem
    • Event Sourcing
      • 状態の記録ではなく状態の変更「イベント」を記録
      • Amazon Kinesis
      • kinesisにpublishして他サービスはsubscribe
      • S3にログを残す
      • トランザクションログの仕組み

モニタリング

  • CloudWatch

    • ログファイルの一元化
    • CloudWatch LogsかS3に保存可能
    • ECSはCloudWatch Logsに一元化できる

分散トレース

  • AWS X-Ray
  • 複数サービスに分散したリクエスト処理を透過的に追える

LogWatchの先に Kinesis FireHorse – ほにゃほにゃ

スロットリング

  • 大事だよ

リトライ

  • 多くのエラーはリトライでカバーできるものが多い
  • リトライ多発で過負荷になることがある
    • Exponential back offもしくはフィボナッチ数列を利用したリトライ感覚の調整
    • 更に乱数でゆらぎを付けて重ならないように

LT:クラウド型医療系業務システムと Microservices への歩み by @hashedhyphen さん

https://speakerdeck.com/hashedhyphen/kuraudoxing-dian-zi-karutesisutemuto-microservices-hefalsebu-mi

クラウド型電子カルテシステムの話

  • メインロジックをRails
  • 常時接続をNode.js
  • バックエンドをScala
  • 基盤はAWS

ここに至る道のり

ファーストリリース前

  • レコメンドは大量のデータが必要

  • メインロジックで実現させようとすると厳しかった

    • Threadとか試したけど……
    • 別アプリケーションとして分離
    • JVM上でScala + Skinnyでスレッドアプリケーションンを実装
    • Microservicesちっくな構成へ
  • 障害検知時

    • メインロジック内のプロトタイプ版が動く!

会計機能リリース前

  • お金を扱う機能は安定性が欲しい
  • Scala + Cats による実装を別エンドポイントとして実装
  • マイクロサービスっぽい作りになっていたから自由度のある技術選択が出来た

まとめ

  • ちょっとマイクロサービス化したことで自由度が上がった
  • 原理主義的にならなくても恩恵がある
  • エンジニアの伸びしろ!

FrontEndからみるmicroserviceとBackendからみるmicroservice by @taka_ft さん

Takahiro Fujii @ Rakuten Travel

楽天内でも採用アーキテクチャはサービスによって異なる。

サービスとしては

  • コンシューマ向け
  • Extranet
  • In-house
  • other
    • ここまではWEBとモバイルがあって、100以上のAPIを利用する
  • API(内部APIを直接利用)

Phase 1

  • 大きなモノリシックなアプリだった
  • 機能がどんどん増えていく
    • 機能別で複数のモノリシックなアプリに分割
    • その後フロントエンドとバックエンドに分割

Phase 2

  • ドメインモデルを整理
  • なるべくRESTfulで作るようになっていった
  • 大きなAPIから小さなAPIに分離
  • I/Fの決定に時間がかかるようになった
  • API呼び出しが大変になった
  • Microservicesっぽくなってきた 2014年くらい

  • 国内予約、海外予約で多言語化だけではない商習慣に根ざしたドメインの差異による重複ロジックの増殖が起きた

  • Microservicesっぽくなってきたが、どんどん品質が下がっていった

Phase 3

(ちょうど前日にプレスリリース)サイト前面刷新に向けての取り組み

  • FrontendsはJavaScriptに刷新
  • API GatewayにKong

組織

  • フロントエンドチームが2人から始まって半年でReactエンジニアを集めて20人以上に

    • 日本人は2, 3人

UI Component

  • SpringからJavaScriptでSPAに変更
  • zeplinのデザインモックからUI Componentを実装するようになった
  • Storyboardを使ってUI Coponentを管理
  • ドメインを含むUI Componentはドメインと結び付きが強いことが多い=専用のオーケストレーションAPIを用意してUI Componentないで処理を閉じることが出来る
  • レスポンシビリティを明示的に定義

    • どこまでフロントエンドでやるか、どこからAPIからもらうか
  • フロントエンドの「使いやすいレスポンス」の要求

  • バックエンドの「汎用的でシンプルなレスポンス」の希望

    • これらのバランスを取る
  • API Gatewayはフロントエンド(UI)チームの管轄

    • ただし状況によってはバックエンド側に持っていくことも検討するつもり

LT: “マイクロサービスはもう十分”か? by @qsona さん

https://speakerdeck.com/qsona/enough-with-the-microservices

POSTDに投稿していた翻訳記事。

スタートアップ企業のほとんどはマイクロサービスをさいようすべきではない

銀の弾丸はない。

「チーム間の依存性」の解決にマイクロサービスというアプローチは違う。疎結合と分散は別。

組織が大きくなると、複数チームが1つのコードベースを触るようになる。そしてマイクロサービス化したくなる。

しかし、モノリスの分割で十分。

チームとは何か

  • 自律的に動けるべき

    • チームが増えるとコミュニケーションコストや、しがらみ
  • チームの分割は目的にそった分割を行う

  • 悪い分割の例: Dev / Ops

  • 依存度が低いほど自律的に動ける

  • High Output という本

  • 使命型組織/技術型組織

    • Micorservicesは使命型組織
    • 組織間が密ならサービス間も密になる

話戻して

  • スタートアップは組織をキレイに分割することが難しい
  • 分割しても密になってしまう

  • 大きなモノリスになるとやはり分割は難しい

    • ドメインの意識は必要
  • マイクロサービス設計しなくても「マイクロサービス精神」で開発すると効果的なのではないか

FiNCが初期からマイクロサービスでやってた理由

  • 単独の事業にできるような一つ一つのサービスを組み合わせて提供してきたから

あとで読み返して修正します。
資料パスの追加とかも。

続きを読む

Dynamic Inventoryを用いたプロジェクトでansible-consoleを使う

概要

ansibleでDynamic Inventoryを用いてec2を管理している際に
ansible-consoleをどのように使うのかメモ。
複数台のサーバに対して、簡単に調査したいときなど使えそう。

起動

  • -iの引数に、ec2.pyを渡せばOK。
$ cd /path/to/your/ansible
$ ansible-console -i ./inventories/ec2.py

console操作

グルーピング

user@all (19)[f:100]$ list groups

all
ec2
tag_Group_api
tag_Group_web
tag_Group_elasticsearch
・・・・・
  • リストした時に出力されるのは、./ec2.pyのtag_xxxが全てのようだ。
./ec2.py  --list

  "tag_Group_api": [
    "api01_dev"
  ],
・・・・・

(試し)elasticseachクラスタに対して設定ファイルgrepする

(グループ移動)
user@all (19)[f:100]$ cd tag_Group_elasticsearch

(対象ホスト確認)
user@tag_Group_elasticsearch (2)[f:100]$ list
es01_dev
es02_dev

(grepする)
user@tag_Group_elasticsearch (2)[f:100]$ grep "discovery.type" /etc/elasticsearch/elasticsearch.yml
es01_dev | SUCCESS | rc=0 >>
discovery.type: ec2

es02_dev | SUCCESS | rc=0 >>
discovery.type: ec2

参考

続きを読む

ZendeskのチケットデータをAmazon Elasticsearch Serviceへ自動的にアップロードする | Developers.IO

Amazon Elasticsearch ServiceはAmazon VPCプライベートサブネットに作成; Amazon API Gateway経由でAWS Lambdaを実行させる; Zendeskの自動化とwebhookでAmazon Elasticsearch Serviceへデータを入れるまでを自動化する; Amazon Elasticsearch Serviceへ入れるデータスキーマ … 続きを読む

センサデータを fluentd 経由で Amazon Elasticsearch Service に送信して可視化

1. はじめに

以前の記事 で、RaspberryPi で収集したセンサデータを、 さくらVPS上に構築した Elasticsearch に送信して、Kibana で可視化しました。
今回は勉強を兼ねて、データを Amazon Elasticsearch Service ( Amazon ES ) に送信するように構成を変更します。

2. 全体の構成

image.png

3. 設定

3-1. Server side ( Amazon ES )

Amazon ES を立ち上げます。

Amazon ES ダッシュボード

  • 画面右上で、東京リージョン( ap-northeast-1 )が選択されていることを確認します
  • 新しいドメインの作成ボタンを押します
image

ドメインの定義

  • ドメイン名と Elasticsearch のバージョンを設定します
image

クラスターの設定

  • 今回は最小構成にします
image

アクセスの設定

  • ダッシュボードは特定メンバーに公開したかったので、パブリックアクセスとして、IPアドレスでアクセス制限を設定しました
  • 本当は IAM Role で制限したかったのですが、Webブラウザからのアクセスが面倒になるので今回は見送りました ( ブラウザはIAM認証できない )
image

完了確認

  • 10分ほど待ちます
image
  • 設定の状態が「アクティブ」になれば完了です
image

3-2. Sensor side ( Raspberry PI )

前提条件

以前の記事 の状態が前提です。今回はこれに変更を加えます。

プラグインのインストール

  • fluentd から Elasticsearch に直接格納するためのプラグインをインストールします
  • なお、IAM 認証をする場合は fluent-plugin-aws-elasticsearch-service を使うようです
sudo fluent-gem install fluent-plugin-elasticsearch

fluentd の設定

  • fluentd の設定ファイルを編集して、データの送信先を変更して、fluentd を再起動します
/home/pi/fluent/fluent.conf
<source>
  @type tail
  format json
  path /home/pi/myroom.log
  pos_file /home/pi/myroom.log.pos
  tag log.myroom
</source>

<match log.myroom>
  @type copy
  <store>
    @type elasticsearch
    type_name myroom
    logstash_format true
    logstash_prefix myroom
    reload_connections false
    hosts https://search-myroom-********.ap-northeast-1.es.amazonaws.com
  </store>
</match>

4. 確認

データが送信されていることを確認しました。
image.png

続きを読む

RaspberryPi で収集したセンサデータを Amazon ES に格納

1. はじめに

前回の記事 では、RaspberryPi で収集したセンサデータを、 さくらVPS上に構築した Elasticsearch に格納しました。
今回は勉強を兼ねて、データを Amazon Elasticsearch Service ( Amazon ES ) に格納するように構成変更します。

2. 全体の構成

image.png

3. 設定

3-1. Server side ( Amazon ES )

Amazon ES を立ち上げます。今回はそれだけです。

Amazon ES ダッシュボード

  • 画面右上で、東京リージョン( ap-northeast-1 )が選択されていることを確認します
  • ドメインの作成ボタンを押します
image

ドメインの定義

  • ドメイン名と Elasticsearch のバージョンを設定します
image

クラスターの設定

  • 今回は最小構成にします
image

アクセスの設定

  • ダッシュボードは特定メンバーに公開したかったので、パブリックアクセスとして、IPアドレスでアクセス制限を設定しました
  • 本当は IAM Role で制限したかったのですが、Webブラウザからのアクセスが面倒になるので今回は見送りました ( ブラウザはIAM認証できない )
image

完了確認

  • 10分ほど待ちます
image
  • 設定の状態が「アクティブ」になれば完了です
image

3-2. Sensor side ( Raspberry PI )

前提条件

以前の記事 の状態が前提です。今回はこれに変更を加えます。

プラグインのインストール

  • fluentd から Elasticsearch に直接格納するためのプラグインをインストールします
  • なお、IAM 認証をする場合は fluent-plugin-aws-elasticsearch-service を使うようです
sudo fluent-gem install fluent-plugin-elasticsearch

fluentd の設定

  • fluentd の設定ファイルを編集して、データの送信先を変更して、fluentd を再起動します
/home/pi/fluent/fluent.conf
<source>
  @type tail
  format json
  path /home/pi/myroom.log
  pos_file /home/pi/myroom.log.pos
  tag log.myroom
</source>

<match log.myroom>
  @type copy
  <store>
    @type elasticsearch
    type_name myroom
    logstash_format true
    logstash_prefix myroom
    reload_connections false
    hosts https://search-myroom-q6f5bk4cwppojeescffv24dmkm.ap-northeast-1.es.amazonaws.com
  </store>
</match>

4. 確認

データが送信されていることを確認しました。
image.png

続きを読む

AWSでElastic Stack – 前回の続き Kibana Filebeatのアップグレード

はじめに

前回、KibanaとFilebeatもアップグレードするような記事を書いたのですが、途中で力尽きてElasticsearchのアップグレードで終わってしまったので、短くなりますが、KibanaとFilebeatもアップグレードしたいと思います。
前回の記事(前回中途半端で申し訳ないですが)の構成を参照して頂ければと思います。

AWSの小ネタ

本題とは関係ありませんが、一応AWSタグを付けているので、AWSで悩んだ話について。

IAMロールで起動したEC2インスタンスのプロキシ環境下にて、プロキシサーバのログに以下のログが大量に出力されていました。

TCP_MISS/404 609 GET http://169.254.169.254/latest/meta-data/network/interfaces/macs/xx:xx:xx:xx:xx:xx/local-ipv4s - HIER_DIRECT/169.254.169.254 text/html

それでxxになっているMACアドレスを持つサーバを調べると以下のログが連続して大量に出力されていました。

ec2net: [get_meta] Trying to get http://169.254.169.254/latest/meta-data/network/interfaces/macs/xx:xx:xx:xx:xx:xx/local-ipv4s

恐らくec2がmetadataを取りにいくのですが、プロキシサーバを経由してしまうせいで、
ご本人じゃありませんよとAWSのmetadataサーバに拒否されているんでしょうと推測しました。

プロキシ環境下では169.254.169.254はプロキシを経由しないようにNO_PROXYの設定を設定します。
http://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-http-proxy.html

自分もこの設定を入れていましたので、設定が有効になっていないかと悩まされることになりました。そこで一旦、exportしているプロキシの設定を削除しましたが、
やっぱりプロキシサーバを経由することを止められませんでした。

そこで他のプロキシを利用する設定を考えたところ、そういえば最初は全てのアクセスをプロキシ経由にするつもりが無くて、yumやwget,curlくらいしかInternetへのアクセスをしないので、それぞれのコンフィグにプロキシの設定を個別に書いていたなと思い至りました。

それで結局当たったのは、curlの.curlrcのプロキシの設定でした。
ここにはNO_PROXYの設定は書いていませんでした。
ここの設定が有効でプロキシサーバ経由でアクセスしているとは・・
ec2がmetadataを取得する際にはcurlで取りにいっているってことですかね?(分かってない)

1.アップグレード作業

では前回やり残したKibanaとFilebeatのアップグレード作業を実施したいと思います。

1.1.事前準備

公式のドキュメントを参考にしながら進めていきます。
Kibana
https://www.elastic.co/guide/en/kibana/current/rpm.html
Filebeat
https://www.elastic.co/guide/en/beats/filebeat/current/setup-repositories.html

あれ・・・前回見た時は6.0だったのに、どんどん更新されていきますね。

1.1.1.GPGキーのインストール

KibanaとFilebeatをインストールしているそれぞれのサーバにて実施します。

Kibanaをインストールしたサーバ(srv1)

# rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch

Filebeatをインストールしたサーバ(srv4)

# rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch

1.1.2.リポジトリの修正

6.0系のリポジトリを用意します。

Kibana

# vi /etc/yum.repos.d/kibana.repo
[kibana-6.x]
name=Kibana repository for 6.x packages
baseurl=https://artifacts.elastic.co/packages/6.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

Filebeat

# vi /etc/yum.repos.d/beats.repo
[elastic-6.x]
name=Elastic repository for 6.x packages
baseurl=https://artifacts.elastic.co/packages/6.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

1.2.アップグレード

Kibana

# yum update kibana
Loaded plugins: priorities, update-motd, upgrade-helper
42 packages excluded due to repository priority protections
Resolving Dependencies
--> Running transaction check
---> Package kibana.x86_64 0:5.6.2-1 will be updated
---> Package kibana.x86_64 0:6.1.1-1 will be an update
--> Finished Dependency Resolution

Dependencies Resolved

==============================================================================================================================
 Package                     Arch                        Version                        Repository                       Size
==============================================================================================================================
Updating:
 kibana                      x86_64                      6.1.1-1                        kibana-6.x                       63 M

Transaction Summary
==============================================================================================================================
Upgrade  1 Package

Total download size: 63 M
Is this ok [y/d/N]: y

Filebeat

# yum update filebeat
Loaded plugins: priorities, update-motd, upgrade-helper
Resolving Dependencies
--> Running transaction check
---> Package filebeat.x86_64 0:1.3.1-1 will be updated
---> Package filebeat.x86_64 0:6.1.1-1 will be an update
--> Finished Dependency Resolution

Dependencies Resolved

===================================================================================================================================================================================================
 Package                                        Arch                                         Version                                       Repository                                         Size
===================================================================================================================================================================================================
Updating:
 filebeat                                       x86_64                                       6.1.1-1                                       elastic-6.x                                        12 M

Transaction Summary
===================================================================================================================================================================================================
Upgrade  1 Package

Total download size: 12 M
Is this ok [y/d/N]: y

1.3.サービスの再起動

Kibana

# service kibana restart
kibana started

Filebeat

 service filebeat restart
2017/12/25 08:46:58.653044 beat.go:436: INFO Home path: [/usr/share/filebeat] Config path: [/etc/filebeat] Data path: [/var/lib/filebeat] Logs path: [/var/log/filebeat]
2017/12/25 08:46:58.653113 metrics.go:23: INFO Metrics logging every 30s
2017/12/25 08:46:58.653234 beat.go:443: INFO Beat UUID: 1267efb0-a1af-4f02-9e18-d7120d6bc2bc
2017/12/25 08:46:58.653256 beat.go:203: INFO Setup Beat: filebeat; Version: 6.1.1
2017/12/25 08:46:58.653386 client.go:123: INFO Elasticsearch url: http://192.100.0.4:9200
2017/12/25 08:46:58.653586 module.go:76: INFO Beat name: ip-192-100-0-36
Config OK
Stopping filebeat:                                         [  OK  ]
Starting filebeat: 2017/12/25 08:46:58.773001 beat.go:436: INFO Home path: [/usr/share/filebeat] Config path: [/etc/filebeat] Data path: [/var/lib/filebeat] Logs path: [/var/log/filebeat]
2017/12/25 08:46:58.773063 metrics.go:23: INFO Metrics logging every 30s
2017/12/25 08:46:58.773112 beat.go:443: INFO Beat UUID: 1267efb0-a1af-4f02-9e18-d7120d6bc2bc
2017/12/25 08:46:58.773132 beat.go:203: INFO Setup Beat: filebeat; Version: 6.1.1
2017/12/25 08:46:58.773280 client.go:123: INFO Elasticsearch url: http://192.100.0.4:9200
2017/12/25 08:46:58.773479 module.go:76: INFO Beat name: ip-192-100-0-36
Config OK
                                                           [  OK  ]

1.4.確認

KibanaとFilebeatのバージョンやログが取れているか等確認します。

Filebeatアップグレード前

# filebeat -version
filebeat version 1.3.1 (amd64)

Filebeatアップグレード後

# filebeat -version
filebeat version 6.1.1 (amd64), libbeat 6.1.1

Kibanaアップグレード前
kibana-version.png

kibanaアップグレード後
kibana6.1ver.png

あ~~ elasticsearchとバージョンが一致しないって怒られてますね。
マイナーバージョンも一致が必要なのは作業的に面倒ですね・・

というわけでまた前回の記事と同じようにアップグレードしてきました。

# curl -XGET 'localhost:9200/'
{
  "name" : "node001",
  "cluster_name" : "my-cluster",
  "cluster_uuid" : "e06BKBFFSpiSkFwNT3kWLw",
  "version" : {
    "number" : "6.1.1",
    "build_hash" : "bd92e7f",
    "build_date" : "2017-12-17T20:23:25.338Z",
    "build_snapshot" : false,
    "lucene_version" : "7.1.0",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

# curl -XGET 'http://localhost:9200/_cat/plugins?v'
name    component         version
node002 analysis-kuromoji 6.1.1
node002 x-pack            6.1.1
node003 analysis-kuromoji 6.1.1
node003 x-pack            6.1.1
node001 analysis-kuromoji 6.1.1
node001 x-pack            6.1.1

改めてKibanaを確認してみます。

kibana6-1.png

エラー直りました。通常のログイン後の画面に。
先ほどのエラー画面だから画面の色合いが違うのかと思っていたのですが、普通に落ち着いた感じになっております。
改めてバージョンを確認します。

kibana_ver6-1.png

OKですね。

では、次にfilebeatからデータが送られているかを確認します。

filebeat1.png

(新しいデータが)有りません

そこでfilebeatのログを確認してみたところ・・・

2017-12-27T07:53:01Z INFO Home path: [/usr/share/filebeat] Config path: [/etc/filebeat] Data path: [/var/lib/filebeat] Logs path: [/var/log/filebeat]
2017-12-27T07:53:01Z INFO Beat UUID: 1267efb0-a1af-4f02-9e18-d7120d6bc2bc
2017-12-27T07:53:01Z INFO Metrics logging every 30s
2017-12-27T07:53:01Z INFO Setup Beat: filebeat; Version: 6.1.1
2017-12-27T07:53:01Z INFO Elasticsearch url: http://192.100.0.4:9200
2017-12-27T07:53:01Z INFO Beat name: ip-192-100-0-36
2017-12-27T07:53:01Z INFO filebeat start running.
2017-12-27T07:53:01Z INFO Registry file set to: /var/lib/filebeat/registry
2017-12-27T07:53:01Z INFO Loading registrar data from /var/lib/filebeat/registry
2017-12-27T07:53:01Z INFO Total non-zero values:  beat.info.uptime.ms=3 beat.memstats.gc_next=4473924 beat.memstats.memory_alloc=3081016 beat.memstats.memory_total=3081016 filebeat.harvester.open_files=0 filebeat.harvester.running=0 libbeat.config.module.running=0 libbeat.output.type=elasticsearch libbeat.pipeline.clients=0 libbeat.pipeline.events.active=0 registrar.states.current=0
2017-12-27T07:53:01Z INFO Uptime: 3.375689ms
2017-12-27T07:53:01Z INFO filebeat stopped.
2017-12-27T07:53:01Z CRIT Exiting: Could not start registrar: Error loading state: Error decoding states: json: cannot unmarshal object into Go value of type []file.State

なんかエラー出て、filebeatが起動していない感じですかね。
そのエラーについて調べてみたところ、同じような状態になった方がおり、解決されていました。
https://discuss.elastic.co/t/exiting-could-not-start-registrar-error-loading-state-error-decoding-states-eof/74430

/var/lib/filebeat/registryを削除してから起動すれば良いようですね。
この環境は壊れても失うのは時間だけなので、やってみます。

# rm /var/lib/filebeat/registry
# service filebeat start
# cat /var/log/filebeat/filebeat

2017-12-27T08:14:08Z INFO Home path: [/usr/share/filebeat] Config path: [/etc/filebeat] Data path: [/var/lib/filebeat] Logs path: [/var/log/filebeat]
2017-12-27T08:14:08Z INFO Beat UUID: 1267efb0-a1af-4f02-9e18-d7120d6bc2bc
2017-12-27T08:14:08Z INFO Metrics logging every 30s
2017-12-27T08:14:08Z INFO Setup Beat: filebeat; Version: 6.1.1
2017-12-27T08:14:08Z INFO Elasticsearch url: http://192.100.0.4:9200
2017-12-27T08:14:08Z INFO Beat name: ip-192-100-0-36
2017-12-27T08:14:08Z INFO filebeat start running.
2017-12-27T08:14:08Z INFO No registry file found under: /var/lib/filebeat/registry. Creating a new registry file.
2017-12-27T08:14:08Z INFO Loading registrar data from /var/lib/filebeat/registry
2017-12-27T08:14:08Z INFO States Loaded from registrar: 0
2017-12-27T08:14:08Z INFO Loading Prospectors: 1
2017-12-27T08:14:08Z WARN DEPRECATED: input_type prospector config is deprecated. Use type instead. Will be removed in version: 6.0.0
2017-12-27T08:14:08Z INFO Starting Registrar
2017-12-27T08:14:08Z INFO Starting prospector of type: log; ID: 5240556406633074861
2017-12-27T08:14:08Z INFO Loading and starting Prospectors completed. Enabled prospectors: 1
2017-12-27T08:14:08Z INFO Harvester started for file: /var/log/secure
2017-12-27T08:14:09Z INFO Connected to Elasticsearch version 6.1.1
2017-12-27T08:14:09Z INFO Loading template for Elasticsearch version: 6.1.1
2017-12-27T08:14:09Z INFO Elasticsearch template with name 'filebeat-6.1.1' loaded

criticalなエラーは解決したようです。

しかしながら新たなエラーが。

2017-12-27T09:24:40Z ERR  Failed to publish events: temporary bulk send failure

そういえば、WARNもありますね。まずこれが気になるのでfilebeat.reference.ymlを見ながら修正してみました。

修正したfilebeat.yml

filebeat.modules:
- module: kafka
  log:
    enabled: true
filebeat.prospectors:
- type: log
  enabled: false
  paths:
    - /var/log/secure.log
output.elasticsearch:
  hosts: ["192.100.0.4:9200"]
setup.template.settings:
setup.kibana:
logging.to_files: true
logging.files:

filebeatを再起動することでWARNは消えました。

# cat /var/log/filebeat/filebeat
2017-12-27T09:49:12Z INFO Home path: [/usr/share/filebeat] Config path: [/etc/filebeat] Data path: [/var/lib/filebeat] Logs path: [/var/log/filebeat]
2017-12-27T09:49:12Z INFO Metrics logging every 30s
2017-12-27T09:49:12Z INFO Beat UUID: 1267efb0-a1af-4f02-9e18-d7120d6bc2bc
2017-12-27T09:49:12Z INFO Setup Beat: filebeat; Version: 6.1.1
2017-12-27T09:49:12Z INFO Elasticsearch url: http://192.100.0.4:9200
2017-12-27T09:49:12Z INFO Beat name: ip-192-100-0-36
2017-12-27T09:49:12Z INFO Enabled modules/filesets: kafka (log),  ()
2017-12-27T09:49:12Z INFO filebeat start running.
2017-12-27T09:49:12Z INFO Registry file set to: /var/lib/filebeat/registry
2017-12-27T09:49:12Z INFO Loading registrar data from /var/lib/filebeat/registry
2017-12-27T09:49:12Z INFO States Loaded from registrar: 1
2017-12-27T09:49:12Z INFO Loading Prospectors: 2
2017-12-27T09:49:12Z INFO Starting Registrar
2017-12-27T09:49:12Z INFO Starting prospector of type: log; ID: 15188226147135990593
2017-12-27T09:49:12Z INFO Loading and starting Prospectors completed. Enabled prospectors: 1

ERRが出力されるのかしばらく待ちます。

ERRも出なくなってました。しかし肝心のデータがkibanaで表示されない・・・

 おわりに

今回はこれで終わりにしたいと思います。
また来年続きやります・・・

こんなんばっかりや・・

続きを読む

Amazon Linux 2 に elasticsearchのbenchmarkツールrallyをインストールして、Amazon Elasticsearch Serviceの性能評価を行う.

Amazon Linux 2 に elasticsearchのbenchmarkツールrallyをインストールして、Amazon Elasticsearch Serviceの性能評価を行う.

Amazon Elasticssearch Serviceのパフォーマンスを調査する為に、Elasticsearchが提供するベンチマークツールのrallyを導入したEC2インスタンスを立ち上げ、性能評価を行います。

AMIは、最近発表された
Amazon Linux 2 LTS Candidate AMI 2017.12.0 (HVM), SSD Volume Type - ami-7707a10f
を利用してみます.

rallyは、python3上で動作する為、python3をインストールが必要になります.
AMIとして利用するAmazon Linux2に標準でインストールされているpythonは、version2系(Python 2.7.5)の為、python3系をインストールします。

$ sudo amazon-linux-extras install python3
$ python3 --version
Python 3.6.2

rally用のpython3環境とする為、python3の仮想環境を作ります.

$ python3 -m vent .py-esrally-venv
$ source .py-esrally-venv/bin/activate

rallyのインストール,実行時に不足するライブラリをインストールします.

$ sudo yum install gcc python3-devel git

rallyをインストールします.

(.py-esrally-venv) $ pip3 install esrally
(.py-esrally-venv) $ esrally configure
 # Press Enter to skip. 

elasticsearch serviceへのアクセスは、 Signature Version 4でアクセスする必要がある為、rallyから直接接続するすることができません. そこで Elasticsearch serviceにアクセスする為のproxyを立ち上げます.
今回は、 nodeベースのproxy aws-es-proxyを利用します.

nodeをインストールする為にnvmのインストールを行い、その後、nodeをインストールし、 aws-es-proxyを導入します.

(.py-esrally-venv) $ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
(.py-esrally-venv) $ source .bashrc
(.py-esrally-venv) $ nvm install  v8.9.3
(.py-esrally-venv) $ npm init
(.py-esrally-venv) $ npm install --save aws-es-proxy

proxyを起動します.
なお、aws credentials情報(access_key_id, aws_secret_access_key)は、aws cliで設定しておいてください.

(.py-esrally-venv) $ node_modules/aws-es-proxy/bin/aws-es-proxy --port 9200 --profile default --region [region]  [endpoint]

proxy経由でElasticsearch Serviceにアクセスできることを確認します.

(.py-esrally-venv) $ curl http://localhost:9200/

rallyを実行します. target-hostsとして、proxyのアドレスを指定します。

(.py-esrally-venv) $ esrally --pipeline=benchmark-only --target-hosts=localhost:9200
    ____        ____
   / __ ____ _/ / /_  __
  / /_/ / __ `/ / / / / /
 / _, _/ /_/ / / / /_/ /
/_/ |_|__,_/_/_/__, /
                /____/

[INFO] Writing logs to /home/xxxxx/.rally/logs/rally_out_20171225T052238Z.log

************************************************************************
************** WARNING: A dark dungeon lies ahead of you  **************
************************************************************************

Rally does not have control over the configuration of the benchmarked
Elasticsearch cluster.

Be aware that results may be misleading due to problems with the setup.
Rally is also not able to gather lots of metrics at all (like CPU usage
of the benchmarked cluster) or may even produce misleading metrics (like
the index size).

************************************************************************
****** Use this pipeline only if you are aware of the tradeoffs.  ******
*************************** Watch your step! ***************************
************************************************************************
    :
  • 参考
    利用させていただいたproxy.
    https://github.com/joona/aws-es-proxy
    esrallyのドキュメント
    https://esrally.readthedocs.io/en/latest/index.html

  • 残件
    Amazon Elasticsearch Serviceの構成変更での性能評価を目的としている為、異なるproxyを利用する必要はないと想定しているが、go言語で実装された aws-es-proxyを使った場合の比較などもやっておくべきかもしれない. proxyで、パフォーマンスに差が出ると、性能指標の基準が低くなってしまうはず..
    trackを指定することで、異なるデータパターンでの評価を行うことができるので、サービスでの利用方法に近いtrackでの評価を実施すべき..デフォルト(オプション指定無)は、geonames.

  • 備考
    インスタンスタイプがt2.microだと、途中で異常終了してしまうようです. 評価中、CPU Creditを、使い切って途中で異常終了しました.
    また、Amazon Elasticsearch Service側の構成として、簡単に1台で立ち上げられますが、1台構成の場合、StatusがYellowの為、デフォルトでは、測定できません。 以下のようなERRORを出力して、測定が中断します.
    [ERROR] Cannot race. ('Could not execute benchmark', Cluster did not reach status [green]. Last reached status: [yellow])
    どうしても1台構成で実行する場合は、rally実行時に、 --cluster-health=yellow optionを付与する必要があります。

続きを読む

ALBのアクセスログに対してElasticStackのMachine Learningを試してみた

はじめに

Advent Calendar25日目ということでクリスマスですね!:santa:
でも、いつもと変わらないですね!

ということで、
今回は、異常検知してくれる?ElasticStackのX-Packの中のMachine Learningについて試してみましたので書きたいと思います( ゚Д゚)ゞビシッ1

こんな流れで話すよ

  1. ログ取込フロー
  2. 環境について
  3. ALBのログを出力して、LogstashからElasticsearchにストア
  4. Machine Learning使うよ!

ログ取込フロー

AWSでWebサービスを提供している環境で、WebAPサーバの前段にはALBを配置してます。
以下の流れでログを取り込みます。

image.png

  1. ALBログを指定バケットに出力
  2. LogstashがS3からALBのログを収集
  3. LogstashがElasticsearchにストア

環境について

  • ALB
  • Amazon Linux AMI 2017.09.1 (HVM)
  • Logstash 6.0
  • logstash-input-s3
  • Elasticsearch 6.0
  • Kibana 6.0
  • X-Pack 6.0

ElasticStackは、事前にインストールしていることを前提にしてます。
インストールされていない環境は、以下を参考にして頂ければと思います。

ALBのログを出力して、LogstashからElasticsearchにストア

ALBのロギングを有効化については以下を参考にしてください。

ここからは、S3に格納されているALBログをLogstashで取得するための方法について書きます。

S3 input pluginをインストール

S3からログを取得するには、Logstashのプラグインである”S3 input plugin”をインストールする必要があります。

インストール方法を以下に書きます。

$ cd /usr/share/logstash
$ bin/logstash-plugin install logstash-input-s3

ALBのログを取り込むための準備

ALBのログは、以下の形式で出力されます。

### Log Format
type timestamp elb client:port target:port request_processing_time target_processing_time response_processing_time elb_status_code target_status_code received_bytes sent_bytes "request" "user_agent" ssl_cipher ssl_protocol target_group_arn trace_id

### Sample Log
http 2016-08-10T22:08:42.945958Z app/my-loadbalancer/50dc6c495c0c9188 
192.168.131.39:2817 10.0.0.1:80 0.000 0.001 0.000 200 200 34 366 
"GET http://www.example.com:80/ HTTP/1.1" "curl/7.46.0" - - 
arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067
"Root=1-58337262-36d228ad5d99923122bbe354"

この出力されたログを取り込むために、Grok Patternを作成したり、型変換をLogstashで施す必要があります。

フィールド定義

それでは、ログフォーマットからフィールド名と型の定義を行います。
ALBが受け付けてからクライアントに返すまでの処理時間を表すフィールドをfloatにします。
対象は、”request_processing_time”、”target_processing_time”、”response_processing_time”です。

Log Field Type
type type string
timestamp date date
elb elb string
client:port client_port string
target:port target_port string
request_processing_time request_processing_time float
target_processing_time target_processing_time float
response_processing_time response_processing_time float
elb_status_code elb_status_code string
target_status_code target_status_code string
received_bytes received_bytes long
sent_bytes sent_bytes long
request ELB_REQUEST_LINE string
user_agent user_agent string
ssl_cipher ssl_cipher string
ssl_protocol ssl_protocol string
target_group_arn target_group_arn string
trace_id trace_id string

Grok Pattern

ALBのログに正規表現をかけて、構造化するため、Grokする必要があります。
Grokを直接Logstashのconfファイルに書くことも可能ですが、可読性を重視するため、パターンファイルとして外出しします。

以下が、ALBのログをよしなに取り込むためのGrok Patternファイルです。

alb_patterns
### Application Load Balancing
ALB_ACCESS_LOG %{NOTSPACE:type} %{TIMESTAMP_ISO8601:date} %{NOTSPACE:elb} (?:%{IP:client_ip}:%{INT:client_port}|-) (?:%{IP:backend_ip}:%{INT:backend_port}|-) (:?%{NUMBER:request_processing_time}|-1) (?:%{NUMBER:target_processing_time}|-1) (?:%{NUMBER:response_processing_time}|-1) (?:%{INT:elb_status_code}|-) (?:%{INT:backend_status_code}|-) %{INT:received_bytes} %{INT:sent_bytes} \"%{ELB_REQUEST_LINE}\" \"(?:%{DATA:user_agent}|-)\" (?:%{NOTSPACE:ssl_cipher}|-) (?:%{NOTSPACE:ssl_protocol}|-) %{NOTSPACE:target_group_arn} \"%{NOTSPACE:trace_id}\"

Multiple Pipelines

Logstashのconfファイルを呼び出すためにMultiple Pipelinesを使用します。
Pipeline.ymlの定義は、以下です。

pipelines.yml
- pipeline.id: alb
  pipeline.batch.size: 125
  path.config: "/etc/logstash/conf.d/alb.cfg"
  pipeline.workers: 1

Pipelineの設定については、以下を参考にして頂ければと思います。

Logstashのディレクトリ構成

ここまで準備しましたが、以下の様に各ファイルを配置します。

/etc/logstash
  ├ logstash.yml
  ├ conf.d
  │ └ alb.cfg
  ├ jvm.options
  ├ log4j2.properties
  ├ alb_patterns
  └ pipelines.yml
  • ALBのalb.cfgをconf.d配下に配置
  • ALBのGrok PatternファイルをLogstash配下に配置
  • alb.cfgを呼び出すpipeline.ymlをLogstash配下に配置

ALBのconfファイルを作成するよ

  • Input: S3からALBのログを取得する2

  • Filter: 取得したログに対してフィルタをかける

  • Output: Elasticsearchにストア

alb.cfg
input {
  s3 {
    region => "ap-northeast-1"
    bucket => "hoge"
    prefix => "hoge"
    ### S3へのポーリング間隔を指定
    interval => "60"
    sincedb_path => "/var/lib/logstash/sincedb_alb"
  }
}
filter {
  ### 読み込むGrok Patternファイルを"patterns_dir"で指定
  grok {
    patterns_dir => ["/etc/logstash/alb_patterns"]
    match => { "message" => "%{ALB_ACCESS_LOG}" }
  }
  date {
    match => [ "date", "ISO8601" ]
    timezone => "Asia/Tokyo"
    target => "@timestamp"
  }
  ### グローバルIPから国などをマッピングするために指定
  geoip {
    source => "client_ip"
  }
  ### デフォルトの型がstringのため、フィールド定義で定義した型に変換
  mutate {
    convert => [ "request_processing_time", "float" ]
    convert => [ "response_processing_time", "float" ]
    convert => [ "target_processing_time", "float" ]
    convert => [ "received_bytes", "int" ]
    convert => [ "sent_bytes", "int" ]
    ### 不要なフィールドを削除
    remove_field => [ "date", 'message' ]
  }
}
output {
  elasticsearch {
    hosts => [ "localhost:9200" ]
  }
}

ここまで整ったらLogstashを起動

$ initctl start logstash
logstash start/running, process 3121

Machine Learning使うよ!

KibanaでアクセスしてMachine Learingをクリックします。
新しくジョブを作成するので、”Create new job”をクリックします。

以下の画面で”Single metric”をクリックします。

image.png

“Aggregation”と”Filed”を指定します。
Filedは、”target_processing_time”にすることで、バックエンドのサーバへリクエストしてから返ってくるまでの時間をみます。
そうすることで、サーバ内の処理遅延が発生しているかを確認できます。
画面の右上から期間を指定します。

image.png

“Name”と”Description”を入力し、”Create job”をクリックします。

image.png

ジョブが実行され、結果を表示するため”View Results”をクリックします。

image.png

指定期間の中で普段より乖離している部分を赤やオレンジでマークされます。

image.png

今回は、Single metricでやりましたが、Multi metricを使うことで、
グローバルIPアドレスやUserAgentと合わせて検出することも可能です。

さいごに

いかがでしたか?ログを取り込んでジョブを作成するだけで簡単に実行できました。
今までは、人の目で判断していたところをMachine Learningを用いることで、普段の傾向から乖離している部分を自動で検出してくれるのは便利ですね。

Advent Calendar最終日ですが、これにておしまいです。
ありがとうございました!


  1. Machine Learningは、X-Packという有償プラグインですが、期間限定で試すことが可能です 

  2. S3バケットへのアクセスするためのIAM Roleが適用されていることを前提とする 

続きを読む

CloudWatchLogsAPIとfluent-plugin-s3を使ったLambdaログの保管と分析、可視化について

はじめに

これは、Sansan Advent Calendar 2017の24日目の記事です。

  • CloudWatchLogsはログを時系列で絞込検索がしにくいとか、見にくいし使いにくいツールである
  • 本番でLambdaの関数がxx 個以上動いており、障害発生時の調査にはCloudWatchLogsを頑張って使うしかない
  • apexでログを見る方法もないわけではないが、ずっとtailするのは難しい
  • CloudWatchLogsにずっと置いとくのもアレ
  • CloudWatchLogs早くいい感じになって欲しい

ということですでにfluentdなどで収集しているアプリケーションログやアクセスログと同様にS3に保管し、Elasticsearchに乗せてKibanaで検索、分析できるようにしたかったのです。CloudWatchLogsAPIとfluent-plugin-s3を使ってLambdaログの保管と分析、可視化をできるようにしました。

あきらめた案

fluent-plugin-cloudwatch-logsで収集しようともしていました。しかし、新たに生み出されるLogStreamの収集ができず、理由もよくわからず断念した。fluentdをpryで止めて結構デバッグしたものの、fluentd力もっとほしい…!となりました。
Lambdaのログは、CloudWatchLogsのLogGroup以下にLogStreamとしてつくられていくが、LogStreamに[$LATEST]というLambdaのバージョンプレフィックス的なやつが入るため、fluentdのbuffer_path設定と相性が悪かったです。(この仕様マジでやめてほしい。括弧とかドル記号とか入らないでほしい。)
また、50個以上のLogStreamsがある際に、このpluginではログを扱うArrayが予期せぬ入れ子構造になってしまっていたため修正しました。
どちらもマージされてはいるが、力不足によりこのプラグインでは収集を完遂できませんでした。

https://github.com/ryotarai/fluent-plugin-cloudwatch-logs/pull/80
https://github.com/ryotarai/fluent-plugin-cloudwatch-logs/pull/84

詳細な説明

ピタゴラ装置

Lambda

まずは、CloudWatchLogsのAPIを叩くためのLambdaをつくりました。Python3.6で実装しました。
このLambdaは、CloudWatchLogs.Client.create_export_taskを叩いています。
http://boto3.readthedocs.io/en/latest/reference/services/logs.html#CloudWatchLogs.Client.create_export_task

しかし、エクスポート対象にする期間の指定はコード上に置いておきたくありませんでした。(create_export_taskのfrom, toの指定)
そのため、前回実行時のタイムスタンプをS3上に置くようにし、これが無ければ現在からn時間分エクスポートし、あればfromにセットするという実装にしました。こうすることで、実行タイミングはCloudWatch EventsのRuleのみで与えられるようになります。

Lambdaの周辺

fluent-plugin-s3では、S3からログを取り込むことができます。S3イベント通知でSQSに流しています。あとはわりと普通です。

cloudwatchlogs-import-after.png

ちなみに

アレがこれであーなので、実はあと一歩のところで本番投入できていません。年内にはやっておきたいです。
現在の職場での特異的な話が絡むfluent-s3-plugin関連の設定についてなので、根底から覆るような話ではありません。もし同じような構成を考えている人がいたら安心してほしいです。

最後に

CloudWatchLogsが使いやすくなることや、Lambdaのログが自動的にS3へエクスポートし続ける設定がほしいです。LambdaのためにLambdaを作ることが減るといいなぁと思いますので、サンタさん(AWS)何卒よろしくお願いします。

続きを読む