Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

Beatsのつくりかた - ヒープとGCを取得するJstatbeatsを実装してみた

Hello, world! @ です!
このエントリーはElasitcsearch Advent Calendarの20日目になります。


先日、Elastic{ON} Tour 2015 Tokyoが行われました。

世界各地で行われたイベントの中で最後となる東京では、無料イベントにも関わらず、
セッションは充実しているし、資料が印刷されて、しかも翻訳までされているし、
ランチに人形町今半のお弁当が配られるし
帰るときにもらったノベルティグッズが、なんとElasticロゴ入りモバイルバッテリーだったり、
とんでもないホスピタリティあふれるイベントでした。

Acroquestもelastic社のパートナーとして提携して、今回もデモスポンサーとして参加しましたが
それ以外にも何かイベントの盛り上げをお手伝いができないかなと思い、リアルタイムブログに挑戦してみました。

当日のブログ一覧 : http://acro-engineer.hatenablog.com/search?q=%23elasticon

同僚のサポートもあり、いずれもセッション終了から数分以内にはレポートをあげることができました!


ということでこのAdvent Calendar、元々はElastic{ON}のことを書こうかと思っていたのですが、
既に全部レポートしちゃったので、代わりに、Beatsの作り方について紹介したいと思います。

Beatsのつくりかた

Beatsとは何ぞやというところは、以前にPINOKIOが書いたエントリーを見てください。
acro-engineer.hatenablog.com

Beatsの作り方は、公式ドキュメントのDeveloper Guideにまとまっています。
https://www.elastic.co/guide/en/beats/libbeat/current/new-beat.html

この手順に沿いつつ、JavaのヒープサイズやGCの回数をjstatコマンドで取得する、
「Jstatbeat」を作ってみたいと思います。


なお、今回作成したコードは、Githubで公開しています。
https://github.com/cero-t/jstatbeat

こんな感じのダッシュボードを作ることができます。
f:id:acro-engineer:20151220045735p:plain
サクッと作れる割に、良い感じです。


ちなみにBeatsシリーズはGo言語で書かれているため、Goの開発環境を事前に作っておく必要があります。
僕はIntelliJ + golang-pluginを使っています。

Goは文法的にも取っつきやすく、チュートリアルも充実しており、習得しやすいと感じています。
クロスプラットフォーム向けコンパイルや、メモリフットプリントの小ささなどメリットも大きいので、
まだGoを学んでない方は、この機会にぜひ習得してみてください。

1. 概要を把握する

まずは簡単にBeatsの実装を知るために、Topbeatのソースコードを確認します。
https://github.com/elastic/beats/tree/master/topbeat

Topbeatの本体ソースコードは、4つしかありません。
各ソースの代表的な部分とともに紹介します。

1. /main.go (https://github.com/elastic/beats/blob/master/topbeat/main.go)
メイン関数です。実質的にはbeatを起動する処理を1行書くだけです。

func main() {
	beat.Run(Name, Version, topbeat.New())
}

2. /beat/config.go (https://github.com/elastic/beats/blob/master/topbeat/beat/config.go)
設定ファイルと1:1のパラメータを持つ構造体です。

type TopConfig struct {
	Period *int64
	Procs  *[]string
	Stats  struct {
		System     *bool `yaml:"system"`
		Proc       *bool `yaml:"process"`
		Filesystem *bool `yaml:"filesystem"`
		CpuPerCore *bool `yaml:"cpu_per_core"`
	}
}

3. /beat/sigar.go (https://github.com/elastic/beats/blob/master/topbeat/beat/sigar.go)
Topの情報を作成するための、gosigarのラッパー関数群です。詳細は割愛します。

4. /beat/topbeat.go (https://github.com/elastic/beats/blob/master/topbeat/beat/topbeat.go)
処理の本体です。一番重要な関数群です。

func (tb *Topbeat) Config(b *beat.Beat) error {
	// 略
}

func (tb *Topbeat) Setup(b *beat.Beat) error {
	// 略
}

func (t *Topbeat) Run(b *beat.Beat) error {
	// 略
}

func (tb *Topbeat) Cleanup(b *beat.Beat) error {
	return nil
}

func (t *Topbeat) Stop() {
	close(t.done)
}

この5つのメソッドを実装することで、beat本体となるBeaterを実装することができます。

参考: https://www.elastic.co/guide/en/beats/libbeat/current/new-beat.html#_developing_the_beat_specific_code


自分でbeatを作る際には、libbeatという共通ライブラリを利用することで実装量を抑えることができるため、
1、2、4に相当するコードだけを書けば良いわけです。

参考: https://www.elastic.co/guide/en/beats/libbeat/current/new-beat.html#_overview


要するに周辺作業はlibbeatがすべてやってくれるので、
個別のbeatはデータを取るところに注力すれば良いわけです。

2. libbeatのソースをgo get

よし作ってみよう、という気になったら、まずはlibbeatの取得をします。
参考: https://www.elastic.co/guide/en/beats/libbeat/current/new-beat.html#_getting_ready

公式ドキュメントの通りにtopbeatをgo getで取ってくれば、libbeatも一緒に取得できます。

go get github.com/elastic/topbeat

これで開発の準備ができました。

3. 設定ファイルと、設定の構造体を作る

まずは設定ファイルの作成と、その設定を読み込む処理を作成します。
参考: https://www.elastic.co/guide/en/beats/libbeat/current/new-beat.html#config-method


Jstatbeatでは「GC情報を取得する間隔(ミリ秒)」と、jpsを実行した時に取れる「プロセス名」の
2つを設定できるようにします。

設定ファイルはtopbeatのものをコピーして、設定部分だけ変えるのが良いでしょう。
https://github.com/elastic/beats/blob/master/topbeat/etc/topbeat.yml

/etc/jstatbeat/jstatbeat.yml

input:
  interval: 5000
  name: "Elasticsearch"

  # 略


そして、この設定ファイルに対応する構造体を作ります。

/beat/config.go

package beat

type JstatConfig struct {
	Interval *string `yaml:"interval"`
	Name     *string `yaml:"name"`
}

type ConfigSettings struct {
	Input JstatConfig
}


続いて、本体となるJstatbeatクラスのうち、設定ファイルを読み込むConfig関数を作成します。

/beat/jstatbeat.go

package beat

// import文は省略

type Jstatbeat struct {
	// from configuration
	interval string
	name     string // (1)

	// state
	pid     string
	isAlive bool
}

func (jsb *Jstatbeat) Config(b *beat.Beat) error { // (2)
	var config ConfigSettings
	err := cfgfile.Read(&config, "") // (3)
	if err != nil {
		logp.Err("Error reading configuration file: %v", err)
		return err
	}

	jsb.name = *config.Input.Name // (4)

	if config.Input.Interval != nil {
		jsb.interval = *config.Input.Interval
	} else {
		jsb.interval = "5000"
	}

	return nil
}


(1) Jstatbeat自身のフィールドとして interval と name を定義しておき
(2) Config関数の中で
(3) 設定ファイルを読み込んで
(4) 読み込んだ値を、フィールドに代入します。

これでConfig関数は完成です。
ね、簡単でしょう?

4. 起動時の処理を作る

続いて、起動時の処理を行うSetup関数を作成します。
起動時の処理では、jpsコマンドを実行して、監視対象となるJavaプロセスのプロセスIDを取得します。
参考: https://www.elastic.co/guide/en/beats/libbeat/current/new-beat.html#setup-method


/beat/jstatbeat.go

type Jstatbeat struct {
	// from configuration
	interval string
	name     string

	// state
	pid     string // (1)
	isAlive bool
}

func (jsb *Jstatbeat) Setup(b *beat.Beat) error { // (2)
	cmd := exec.Command("jps") // (3)

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		logp.Err("Error get stdout pipe: %v", err)
		return err
	}

	cmd.Start()

	// TODO: handle error when 'jps' command cannot be executed.

	scanner := bufio.NewScanner(stdout)
	for scanner.Scan() {
		line := scanner.Text()
		items := strings.Split(line, " ")

		if len(items) == 2 && items[1] == jsb.name { // (4)
			jsb.pid = items[0]
			break
		}
	}
	cmd.Wait()

	if len(jsb.pid) == 0 {
		logp.Err("No target process: %v", jsb.name)
		return errors.New("No target process: " + jsb.name)
	}

	return nil
}

(1) Jstatbeatのフィールドとして pid を定義しておき
(2) Setup関数の中で
(3) jpsコマンドを実行して
(4) 設定で指定した name に一致するプロセスの pid を取得します

5. メインの処理を作る。

いよいよ、一番のメイン処理となるRun関数の実装です。
https://www.elastic.co/guide/en/beats/libbeat/current/new-beat.html#run-method


処理が少し長いので、いくつかのブロックに分けて説明します。

/beat/jstatbeat.go

func (jsb *Jstatbeat) Run(b *beat.Beat) error {
	jsb.isAlive = true

	cmd := exec.Command("jstat", "-gc", "-t", jsb.pid, jsb.interval) // (1)
	stdout, err := cmd.StdoutPipe()

	if err != nil {
		logp.Err("Error get stdout pipe: %v", err)
		return err
	}

	cmd.Start()
	defer killProcess(cmd) // (2)

	// 略

	return nil
}

func killProcess(cmd *exec.Cmd) {
	if cmd.Process != nil {
		err := cmd.Process.Kill()
		if err != nil {
			logp.Err("Error killing jstat process: %v", err)
		}
	}
}

(1) jstatコマンドに-gcオプションと-tオプションをつけて実行します。
また、pidやintervalは、それぞれSetupとConfigで取得したものを渡します。

(2) コマンドを実行した後は、エラーなどで処理が止まってしまって良いように
deferでプロセス停止の関数を呼ぶようにしておきます。


/beat/jstatbeat.go

var blanks = regexp.MustCompile(`\s+`)

func (jsb *Jstatbeat) Run(b *beat.Beat) error {
	jsb.isAlive = true

	// 略

	scanner := bufio.NewScanner(stdout)
	var keys []string
	var version string
	for jsb.isAlive && scanner.Scan() { // (3)
		line := scanner.Text()

		values := blanks.Split(line, -1) // (4)

		if len(values) > 2 && values[0] == "Timestamp" {
			keys = values // (5)

			if strings.Contains(line, "CCSC") { // (6)
				version = "java8"
			} else {
				version = "java5"
			}

			continue
		}

		// 略
	}

	return nil
}

(3) jstatの結果を一行ずつ読み出しながら
(4) 正規表現を使って、空白で値を分割しています。
(5) 1行目(見出し行)の場合は、分割した値をkeysとして保持しておきます。
(6) また念のため、jstatで取れた情報から、JVMJava5〜7なのか、Java8だったのかを判断しています。
この判断結果は、elasticsearchのtypeとして利用します。


/beat/jstatbeat.go

func (jsb *Jstatbeat) Run(b *beat.Beat) error {
	// 略

	for jsb.isAlive && scanner.Scan() {
		line := scanner.Text()

		values := blanks.Split(line, -1)

		// 略

		event := common.MapStr{ // (7)
			"@timestamp": common.Time(time.Now()),
			"type":       version,
		}

		for i, key := range keys { // (8)
			if len(key) == 0 {
				continue
			}
			event[key] = toFloat(values[i+1]) // (9)
		}
		b.Events.PublishEvent(event) // (10)
	}

	return nil
}

func toFloat(str string) float64 {
	value, err := strconv.ParseFloat(str, 64)

	if err != nil {
		logp.Err("Cannot parser to float. Ignore this value: %v", err)
		return 0
	}

	return value
}

(7) jstat実行結果の2行目以降に対して、行に対応する内容をMapとして作成し、
(8) すべての項目に対して
(9) 項目 = 値となるように、Mapに格納しています。また値はstringではなくfloat64に変換してから渡しています。
(10) そして、それをlibbeatのPublishEvent関数を使って送信します。


要はRun関数では、Mapを作ってPublishEventする、ということです。

Java5とJava8の両方に対応させるため、若干、処理がややこしくなっていますが、
簡単なbeatを作るだけなら、ホントに十数行で済むんじゃないかと思います。

6. 終了時の処理を作る

残るCleanup関数とStop関数は、まとめて紹介します。
https://www.elastic.co/guide/en/beats/libbeat/current/new-beat.html#cleanup-method
https://www.elastic.co/guide/en/beats/libbeat/current/new-beat.html#stop-method


Cleanup関数は処理が終わるとき(正常時、異常時とも)の処理を書きますが、
ここでは特にやることがないので、何の処理も書いていません。

Stop関数は、SIGTERMを受信した時の処理を書きます。
ここではフラグを落として、ループが終わるようにしています。

/beat/jstatbeat.go

type Jstatbeat struct {
	// from configuration
	interval string
	name     string

	// state
	pid     string
	isAlive bool // (1)
}

func (jsb *Jstatbeat) Run(b *beat.Beat) error {
	jsb.isAlive = true // (2)

	// 略

	for jsb.isAlive && scanner.Scan() { // (3)

	// 略
}

func (jsb *Jstatbeat) Cleanup(b *beat.Beat) error {
	return nil
}

func (jsb *Jstatbeat) Stop() {
	jsb.isAlive = false // (4)
}

(1) フィールドとして定義した isAlive を
(2) Run関数で処理の前に true にしておき
(3) ループ中は必ず確認するようにして
(4) Stop関数が呼ばれた際に false にします。
こうすることで、SIGTERM受信時には処理が中断できるようになります。

7. main関数の作成

最後にメイン関数の作成です。
Jstatbeatのインスタンスを作成して、それをlibbeatに渡すだけです。
参考: https://www.elastic.co/guide/en/beats/libbeat/current/new-beat.html#_the_main_function


/beat/jstatbeat.go

func New() *Jstatbeat { // (1)
	return &Jstatbeat{}
}

/main.go

package main

import (
	jsatbeat "./beat" // (2)
	"github.com/elastic/libbeat/beat"
)

func main() {
	beat.Run("jstatbeat", "0.1", &jsatbeat.Jstatbeat{}) // (3)
}

(1) go言語お作法に従って、Jstatbeatのインスタンスを作成するNew関数を用意しておきます。
(2) また、beatという名前空間がlibbeat被るため、jstatbeatというエイリアスをつけておき
(3) main関数では、実質1行で処理を書いてしまいます。
このRunの第一引数で渡した"jstatbeat"は、設定ファイル名や、Elasticsearchのindex名などでも
利用するため重要です。index名で使う都合上、名前は英語の小文字だけにしてください。


これで本体ソースコードは完成です。
ほら、簡単でしょう?

8. いざ実行!

main.go、beat/config.go、beat/jstatbeat.goの3つのソースコードと、
jstatbeat.ymlを /etc/jstatbeat/jstatbeat.yml におけば、いよいよ実行です。

go run main.go

これでエラーなく動作するようであれば、Elasticsearchで確認しましょう。

http://(Elasticsearchのアドレス):9200/_cat/indices にアクセスして
jstatbeat-yyyy.MM.dd なindexができていれば成功です。

動作しない場合には、elasticsearchのログか、
Macの場合は /var/log/system.log 辺りを見ると、エラーが出ている可能性があります。


これだけでも動作自体には問題ないのですが、index定義をjsonとして作っておいたほうがより親切です。
topbeatのtemplateを参考にすると良いです。
https://github.com/elastic/beats/blob/master/topbeat/etc/topbeat.template.json

9. ダッシュボード

最後に、kibanaでダッシュボードを作りましょう。
今回は、こんな感じのダッシュボードを作ってみました。

f:id:acro-engineer:20151220045735p:plain

なお手動でダッシュボードを作ったあと、dashboardやvisualizationを
kibana上でexportしておくと、別の環境でもimportすることができます。

なのでexportしたものを配布物と一緒に提供するのが良いかと思います。

公開しました。

ということで、意外とさっくりとbeatを作れることが分かってもらえたかと思います。

今回は簡単にjstatを実行しただけなので、言ってしまえば別に、
jstatをファイルに出力してfilebeatやlogstashで送ってしまえばいいって話になります。

もう少し役立つものにするためには、複数プロセスや複数サーバに対応するとか
あるいはJMX経由でもう少し情報を取ってくるとか、そういうことが必要かと思います。
ただ逆に、そういうものを集める方法を統一するために、Beatsがピタっとハマりそうです。


冒頭にも書きましたが、今回作成したコードは、Githubで公開しています。
https://github.com/cero-t/jstatbeat

また、Windows/Mac/Linuxのそれぞれ向けのバイナリや
ダッシュボードの設定ファイルも含んだファイルをリリースしています。
https://github.com/cero-t/jstatbeat/releases

よかったら参考にしてください。


それでは、
Stay beats, See you!


Acroquest Technologyでは、キャリア採用を行っています。


  • 日頃勉強している成果を、AWSHadoop、Storm、NoSQL、SpringBoot、HTML5/CSS3/JavaScriptといった最新の技術を使ったプロジェクトで発揮したい。
  • 社会貢献性の高いプロジェクトに提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や対外的な勉強会の開催を通した技術の発信や、社内勉強会での技術情報共有により、技術的に成長したい。
  • OSSの開発に携わりたい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 キャリア採用ページ

Elastic{ON} Tokyo 2015レポート 〜Elasticスタックを使用したセキュリティ関連のユースケース #elasticon

本日最後のセッション、
Elasticsearchをセキュリティ用途で使えないかと注目している皆さんにとっては
インパクトある内容だったと思うのが、このセッション。

elasticのNicholas Limさんによる
「Security Use Cases with Elastic Stack」です。

f:id:acro-engineer:20151216170512j:plain

セッション中には、デモを交えた事例が紹介されました。

一つめが、AntiVirusのイベントログを分析することで
ウイルス感染した件数、感染したホスト数、影響を受けたユーザ数などを可視化するものです。
(食らった後の話かー!)

続いて、IDS/IPSのログから、イベントの総数や、攻撃者数、標的数などを可視化するダッシュボード。
また、Firewallのイベントログから、ソースIP、攻撃先IPとポート数などを可視化するダッシュボード。
(いずれも、私たちが作ろうとしているものに近いです、参考になる!)


そしてWatcherを通じて、メールやHipChatに通知を送ることができます。
HipChatとつなぐというアイデアは、星野リゾート様の事例にも出てきましたが
最近はチャットツールAPI経由でのアクセスが当たり前になってきているので
通知先としてもかなり有効です。


またセキュリティログを分析する際、情報ソースとなるFirewallやミドルウェア
プロダクトごとにログ形式は異なっており、自前で解析する必要があります。

そこで推奨されていたのが、標準に則ることです。
STIX/CEF/CIM/LEEFなどのセキュリティロギングの標準に従ってログ出力し
その解析をElasticsearchで行うというものです。


私はまだセキュリティ関係は勉強中なので、改めて復習します!(><)


さー、LTやでー!

Elastic{ON} Tokyo 2015レポート ~ElasticスタックとTipsの紹介 #elasticon

ElasticスタックとTipsの紹介

ここからは、テクニカルセッションです。
まずはelastic大谷さんによる、「ElasticスタックとTipsの紹介」です。

f:id:acro-engineer:20151216163256j:plain

冒頭に「Elasticsearch使ってるひとー」っていうアンケートというか客いじりがあったんですが
8割ぐらいが手を挙げるぐらい、今日はElasticsearchユーザの多いイベントでした。

Elastic{ON}とは言え、すごいですね。

Logstash

まずは、Logstashの紹介です。

セッションでも度々出てきたLogstashですが、
ここではApacheアクセスログの設定を例にして、具体的な設定が紹介されました。

grokでパースして、
dateで日付フォーマットを指定して、
useragentでユーザエージェントを加工して、
geoipで、IPアドレスから緯度と経度を取りました。

Tipsというよりはむしろこれこそが標準的な設定なので、
まずはここから始めましょう!
(個人的には、この機能をElasticsearch側にもつけて欲しいです!)

Elasticsearch

次はElasticsearchのノウハウ。
今回、説明されたのは、以下の4つでした。

1. Index template
2. multi_field
3. dynamic template
4. numeric_detection


Index templateは、要するにRDBMSで言うところのDDLみたいなものです。
スキーマレスなElasticsearchですが、ここは数値にしたいとか、ここはgeoipにしたいとか
また全文検索のような構文解析分かち書き)しなくて良い、という定義をしたくなります。
そのような定義ができるのが、index templateです。
https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates.html

multi_fieldは、一つのフィールドに対して、複数のフィールド定義を持たせるものです。
たとえば「国名」というフィールドに対して「分かち書きした国名」と「分かち書きしてない国名」の
両方を定義する、というようなことができます。
https://www.elastic.co/guide/en/elasticsearch/reference/current/_multi_fields.html

ただ、このような定義を、いちいち全部のindexに定義するのは面倒なものです。
そこで使えるのがdynamic templateです。
たとえば「stringはすべて分かち書きしない」とか
「こういう名前に一致するものは全部(日付ではなく)文字列とする」というような定義ができます。
https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic-templates.html

最後のnumeric_detectionは、文字列ではなく数値として定義するような機能です。
(ドキュメントが、見つからなかった・・・)

Kibana

次はKibanaアプリのSense。

すごく平たく言えば、
Elasticsearch用にカスタマイズされたREST API用クライアントです。

コマンドやindex名、クエリなどの補完が効くので、
ようやくクエリを学び始めた私みたいなエンジニアには便利すぎる機能です。
curlコマンド用の文字列としてコピーする機能もあるので、重宝します。


最後は、visualize-spy。
これ凄く気づきにくい機能なんですが、KibanaのVisualizationって
一番下に ▲ というボタンがあり、これをクリックすると、
Elasticsearchへのリクエスト、レスポンスなどを直接確認することができます。

Kibanaの出力が期待通りにならないから
ちょっと中を見てみたい、という時に使える機能です。
また、Kibanaが発行しているクエリを見て勉強するためにも使えます。

それにしても、気づきにくい機能ですよね。
spyなどと言わず、もっと目立って!


というTipsが多いセッションですが、いかがでしたか?
知らなかった、これ試したい、というものが多ければ私も嬉しいです!

Elastic{ON} Tokyo 2015レポート 〜事例紹介 その3 星野リゾート、ゴールドマンサックス #elasticon

事例紹介その3は、星野リゾートと、ゴールドマンサックスです。
これで事例紹介は最後となります。

星野リゾートにおけるELKを活用した可視化と共有の取り組み

続いては、星野リゾートの久本英司さんによる
星野リゾートにおけるELKを活用した可視化と共有の取り組み」です。

私たちも一緒に取り組みをさせていただいています!(><)


星野リゾートは創業101年のホテル・旅館の運営会社で、
メディアなどに取り上げられる機会も増えて、認知度が非常に高まっています。

一般的に、ホテルや旅館は縦割り組織が多く、
フロントはフロント、清掃は清掃、レストランはレストランという形ですが、
星野リゾートでは、いわゆる「多能工」で、スタッフはマルチタスクで動いています。

そのほかにも、全員で経営判断をできるようにするとか、フラットな組織文化にするなどして、
顧客満足と生産性の両立を目指しています。


特に経営判断に必要なのが、情報共有です。

星野リゾートでは積極的な情報共有を行っていますが、
既存のシステムが古くて使い物にならないものがあったり、
KPIを収集する仕組みが世の中の変化についていけないとか、
あるいはセキュリティ面での課題があり、改善が必要となりました。

改善のアプローチとして、あらゆる経営情報を蓄積しておける場所が必要となり
ここにAcroquestからの提案で、Elasticsearchを利用することにしました。

手書きの絵やマインドマップを使ったビジョン共有を行い、
必要最小限のダッシュボードを作って見せてフィードバックを受け取り、
また改善したものを見せてはディスカッションしてフィードバックを受け取り、
ということを数ヶ月繰り返しました。

そのようなものを利用したところ、

1泊宿泊制限が解除されたタイミングで急に予約数が増えることが分かった
 → 制限が解除されるまで、多少、予約が少なくても大丈夫

とか、
他にも予約が入るタイミングが年々早くなっていること、
会員数が順調に伸びていることなどが、はっきり可視化されました。


将来構想としては、あらゆるデータを投入し、
Timelionや、Sparkとの連動、HipChatなどとの連携を進めたり、
たとえば大量キャンセルなどのタイミングでアラートを上げるなどの
業務に直結する部分のシステム化を進めようとしています。

またIoTの導入による生産性や満足度の向上、
需要予測・稼働予測、稼働調整なども視野に入れています。


実際に動いているものを見たい方は、ぜひAcroquestのブースまで!(>▽<)ノ

Goldman Sachs Engineering

続いては、事例紹介としては最後となります、
Goldman SachsのIan Macleanさんによる「Elastic in Equity Finance」です。

ワークフローやトレーディングオーダーの検索、法規文書やレジュメの全文検索
JVMやリソースなどのメトリクス、アラート、データ解析など
幅広い範囲でElasticsearchを利用しています。

GitHubからElasticsearchのソースをクローンして内部でビルドしており、
独自プラグインを用いて、セキュリティやバックアップの強化を行っているとのことです。
(マジか!)


Elasticsearchのメリットとして、サポートを挙げているところが興味深かったです。
設計レビューやパフォーマンスチューニング、パッチの適用など
サポートで得られるメリットが大きいとのことです。


事例としては、オーダーの検索が説明されました。
オーダー情報はSybaseに保存していましたが、とにかくレコードが多すぎたため
DBをかなり分割しなくてはいけなくなりました。

また検索も時間が掛かり、数時間かかるものがありました。
そのため、意味のある分析をするのが難しかったのです。
(そうですよね、検索が遅いと、分析を試すこともなかなかできない)


そこでElasticsearchを導入しました。
履歴データをElasticsearchに入れ、取引時間中のデータもインデックスしておき、
分析や可視化に利用します。Aggregationを使った高速な分析も行うようにしました。

そして、独自に「Sharp-X」という名の、管理/分析ダッシュボードを作成しました。
オーダーのデータを市場ごとに分析できるダッシュボードです。
履歴データと現在のデータを比較した分析や、取引でエラーが起きてないかどうかの確認などができます。

結果、アーキテクチャソースコードも、かなりシンプルなものになりました。


Elasticsearchは、開発が容易で、スケーラブルな、Game changerです。
今後、RDBMSから、HadoopとElasticsearchを用いたシステムにを置き換えることを計画しています。
(なんか私たちとやりたことが似てる!)


どちらも刺激的なセッションですね。
星野リゾート様のセッションは技術寄りよりも経営寄りの興味深い話でしたし、
Goldman Sachsは力の入れ方に圧倒される一方で、次にやりたいことなどが
非常によく似ているので、ぜひディスカッションさせてもらいたいなと思いました。


さて、事例紹介は以上となり、次はテクニカルセッションです!

Elastic{ON} Tokyo 2015レポート 〜事例紹介 その2 日本経済新聞 #elasticon

記事検索とログ解析でのElasticsearch活用事例

続いては、日本経済新聞社デジタル編成局の梅崎裕利さんによる
「記事検索とログ解析でのElasticsearch活用事例」です。

f:id:acro-engineer:20151216142913j:plain

新聞記事の全文検索とか、なかなか胸が熱くなるタイプのヤツですね。

検索の需要がある中でSolrとElasticsearchの検証を進める中、
気がついたらElasticsearchがメインの仕事になっていたとのこと。
これ、Elasticsearchあるあるですかね。


コンテンツ検索とログ可視化の両方で使えるから、という理由でElasticsearchを採用したそうです。

コンテンツ検索は、200万のデータ(5GB)で、1日数千の更新頻度、リクエストは秒間100回ぐらい。
検索APIは、Django API + Elasticsearchで、マスターはMySQLに別途保存。
本番稼働を始めてから半年以上運用しているようです。

Kuromoji、ICU normalizerの利用、ngramと形態素解析の両方でインデックス作成、
また完全一致用にnot_analyzed(文節や単語で分かち書きしないやつです)も残しています。
(なるほど、検索のために全力だ)

また、新聞記事をスマホで撮ると、関連記事を検索する「もっと日経」というサービスが提供されていまして、
こちらは写真の画像をOCRして、Elasticsearchを用いて検索しています。
OCRの課題はあるそうですが、これは面白いサービスですね。


一方、アクセスログ解析の方は、いわゆるELK/EFK構成(Elasticsearch + Logstash/Fluentd + Kibana)

アクセスログは、1日約3億件(120GB)で、1週間分を保持。
r3.xlargeを6台で運用し、物理メモリ180GB(うちヒープは72GB)という構成。

それで月額20万円程度、もしスポットインスタンスが使えれば月約3万円ぐらいになること。
24時間分のログ集計に、10秒〜1分ぐらいかかるそうです。
検索回数が多くないので、この程度の台数で済んでいるとのこと。
(かなりサイジングの参考になる事例ですやん!)


アクセスログから、HTTPエラーやファイルごとの帯域の可視化、
どの地域からのアクセスが多いかなどを分析しているとのこと。

何よりも、これまでエンジニアが秘伝のソースで解析していたログを
Kibanaで可視化することで、URLや画像で共有できるようになったことが大きな改善ポイント。

また解析に掛かる時間も、当初10分〜1日以上というバッチだったところから
長くとも1分ぐらいになっている点で、フィードバックも早くなりました。

「Kibanaは楽しいから、気づいたら時間がすごい経ってる」というのは、私も共感するところです!


ということで、ここで休憩に入りました。


きゃー、LTの準備が進んでないー!!

Elastic{ON} Tokyo 2015レポート 〜事例紹介 その1 リクルートテクノロジーズ、Naver #elasticon

つづいて、各企業の事例紹介に移ります。
Elastic{ON}は、この東京だけでなく、Elastic{ON} Tourとして世界中をツアーしているのですが、
いずれの地域でも、必ずたっぷり事例紹介が行われています。

リクルート流Elasticsearchの使い方

そんな事例紹介の第一弾は、
株式会社リクルートテクノロジーズの中原裕成さんによる
リクルート流Elasticsearchの使い方」です。


検索基盤や通知基盤でElasticsearchを利用

全社検索基盤「QASS」や、全社プッシュ通知基盤「Pusna-RS」、
またそれらを含む様々なサービスの可視化などでElasticsearchを利用しています。


元々はApache Solrで、各サービスごとに検索エンジンクラスタを組んでいたが、
当時の構成の都合上、検索性能 / 更新性能に限界がありました。

検索品質を向上させるため、全サービス共通の、検索サービスの共通基盤を作ることにして、
その時に盛り上がっていたElasticsearchを採用することにしました。
それで出来たのが全社共通検索基盤「QASS」です。

Spark / Hadoopを用いた分析基盤があるため、これでelasticsearchの検索結果を分析し、
専門チームがelasticsearchの検索結果の継続的品質向上を行っているとのことです。
(何それすごい!)


続いてPusna-RSですが、これはリアルタイムなプッシュ通知を送るシステムです。

データをDynamoDBに保存しているのですが、単純な投入や全件取得は高速なのですが
検索条件を指定した検索は苦手で、そこでelasticsearchを利用することにした。

同じデータを、DynamoDBとelasticsearchの両方に投入し、用途に応じて使い分けている。
(マジか!!)


そして、それぞれのサービスは可視化しており、QASSの検索結果の指標や
プッシュ通知の登録状況や配信状況を可視化しています。

運用ノウハウ

ありがたいことに運用ノウハウの共有もありました。
1. プラグイン機構の利用
2. スナップショットの利用
3. Re-indexの手法


elasticsearchにで提供されているプラグイン機構を用いて、検索を最適化する、
スナップショット機能を利用してS3やHDFS、ディスクなどにスナップショットを残す、
スナップショットのリストアはJenkinsを用いて行うなどしています。

またre-indexですが、考え方的にはブルーグリーンデプロイメントと同様で
クラスタごと再構築を行い、データを流し込んでから、クラスタの切り替えを行っているそうです。


あと、バージョンアップでそれなりに内部構造も変わるので
バージョンアップは計画的に、とのことでした
(分かる!!)

Searching and Alerting for application logs with Elasticsearch at Naver

2社目は、NaverのJaeik Leeさん、Seungjin Leeさんによる
「Searching and Alerting for application logs with Elasticsearch at Naver」です。

最初にLINEを使っている人、という質問がありましたが、ほぼほぼ全員が手を挙げる感じでした。
ちなみにこのブログの写真も、他のメンバーに撮ってもらってLINEで共有しています。


さて、そんなNaver社のElasticsearchの使い方ですが、
元々、エラーログの収集や解析をするシステムを利用していたところ
収集や検索性能に限界を感じて、elasticsearchで再構築をしたとのことです。

スケールとしては、8クラスタ、229ノード、毎日2TBのログが集まっており
現在までに160TBのログが集まっているとのこと。
(半端ないんですけど、何すかそれ?)


Kafka + Kafka Riverを使ってElasticsearchにデータを流し込んでいたところ
パフォーマンス問題や、不安定さ、デバッグの難しさがあったため
Kafka + Stormの構成に変更し、改善させたそうです。

クラスタはマスターノード群、データノード群、クライアントノード群(or ロードバランサ)に分けるほか
直近1週間のデータはSSD、それより古いものはHDDに入れて、保存しているとのことです。


通知の仕組みとして、パーコレーターAPIを用いてこれに合致したものを
Kafkaに送り、そこで判定を行って通知を投げているそうです。
(パーコレーターAPIの一番正しい使い方ですよねこれ)

そしてKafka側で、設定された閾値と時間(たとえば5分間に10回、とか)に従って
ログイベントの通知判定を行って、通知しているとのこと。
通知ルールを変えた際には、Kafkaに通知して、キャッシュをクリアすることにしているとのこと。


2社とも相当なスケールの事例紹介で、少ないノードでなんとか回してる私としては圧倒される感もありますが
リカバリの方法や、通知の方法など、ぜひ取り入れたい学びもありました。

さぁ、続いてのセッションも楽しみですよ!

Elastic{ON} Tokyo 2015 キーノートレポート #elasticon

elastic須田さんの明るい挨拶から始まりました、基調講演。
堅苦しくない、会場のスーツ率も低めな、エンジニアのイベントという雰囲気あります!

f:id:acro-engineer:20151216120211j:plain

Elasticsearchが生まれたきっかけは?

最初はElasticのファウンダーでありCTOであるShay Banonから、
elasticsearchの生まれた経緯の紹介がありました。

奥様が使う検索システムとして、Java + luceneを使ったのがきっかけなんだとか。
やばい、初耳だけどいい話やん!

f:id:acro-engineer:20151216120159j:plain

事例紹介。NASAでも使ってるよ!

そして大きな事例紹介。
Wikipedia検索エンジンとしてElasticsearchを利用した。

またmozillaFirefoxのクラッシュレポートをelasticsearchで集めて、
セキュリティ問題への対策などを行った。

NASAは火星のRoverで取ったデータをElasticsearchに集めた。
マジか! 震える!!(うつった)

verizonはミッションクリティカルアプリケーションの中で
elasticsearchでを使って情報を集め続けた。


そんな事例たちです。

ちなみに英語のセッションですが、同時通訳されています。
ただ、パッと見で、半分ぐらいの人がイヤホンをつけてない感じがします。

Elastic{ON}に来る人たちの英語力の高さよ!!

Elasticのスタックたち

続いて、ELKスタックの紹介。


またプラグインで、さらに機能追加ができます。

この辺りは実案件で利用するには欠かせない機能たちですよね。

Elasticsearch 2.1

そして最近リリースされたElasticsearch 2.0/2.1の新機能や機能改善の話。
Elasticsearchはアップデートが早いので、1ヶ月単位でも色々と改善されます。

回復力、というか最近よく見るキーワードの「Resiliency」

  • リカバリ時間の短縮
  • 永続的な書き込み
  • Javaセキュリティマネージャ

パフォーマンス改善

  • クラスタの強化
  • メモリやストレージの削減。特に2.0からヒープをあまり使わない設定がデフォルトになりました。
  • キャッシュとスロットリングの改善

分析の強化

  • 列ストア。これまではJavaのヒープを使っていたけど、ファイルを使うようになった。
  • 時系列での計算。たとえば増加する数値の差分計算など。これを使ったUIがTimelionですね?
  • 予測と異常検知。何かと思ったらPipeline Aggregationでした、なるほど。
Elasticsearchの将来

もちろん現状だけでなく、次のロードマップ的なものも紹介されます。

機能強化

  • geoデータ分析の強化
  • クエリのプロファイリング

管理機能の強化

  • Reindex API
  • タスク管理API

特に管理機能のRe-index APIは、みんな欲しくなる機能ですよね。
いまはLogstashや、自前でコードを書くなどして頑張ってRe-indexしているので
これは早くサポートして欲しいところです!

Kibana 4.2 & 4.3 and Future

続いて、Kibanaの紹介。
Kibanaは可視化のダッシュボードです。
Kibana開発者であるRashid Khanからの発表で、
twitterでも「お世話になってます!」のメッセージが見えますw

f:id:acro-engineer:20151216120356j:plain

4.2では、バブルチャートやヒートマップの追加、
フィールドのフォーマット(数値にカンマ入れたりできるやつ!)や
地図のカスタマイズなどが強化されました。

4.3では、サーバ状態を閲覧できるページが追加されたほか(エラーの時だけ出てくるやつや!)
ログレベルの設定、オブジェクトのエクスポート、タイムゾーンのサポートなどが追加されました。
エクスポート機能なんてついてたんですね、知りませんでした。試してみます!

また紹介されませんでしたが、4.2だか4.3だかで、項目ラベルを自分でカスタマイズできる機能も追加されました。
これは地味に嬉しいやつで、この機能を求めるissueには、いっぱい +1 がついてました。
っていうかいまだにつき続けています。


Kibanaは将来的に、アプリケーションプラットフォーム化されていきます。
Angular + node.js + Elasticsearchを用いた可視化アプリを簡単に作るためのプラットフォームです。

ちなみにこの辺りはまだオフィシャルな情報はないのですが、Elasticsearch Advent Calendarの2日目エントリー、
「Kibanaプラットフォームでアプリケーションをつくってみよう」で紹介されています。
http://qiita.com/zoetro/items/cd66f79cedd6d435a645
私もKibanaアプリを作りたいっていうか、作らなきゃいけない感じになってきていますので
このページなど見ながら勉強したいと思います!

Timelion

Timelionというスペルで、アイコンもライオンなのに、「タイムライン」って発音するKibanaアプリ。
時系列データに特化したダッシュボードを作ることができ、
複数のグラフを重ね合わせたり、グラフ間での計算などができるようになりました。
Kibanaにこういう機能が欲しい、とリクエストされていたものが別の形になって表れた形ですね。

Logstash 2.1

Logstashとこの後のBeatsの説明は、Tanya Braginが行いました。
この方とは、以前、Mountain View訪問した際に打ち合わせをさせていただきました。

f:id:acro-engineer:20151216120257j:plain

Logstashは情報の収集を行うツールです。
(たぶん日本では「fluentdみたいなやつ」って言った方が、理解が早い気がします!)

Logstash 2.1ではシャットダウンの改善、パフォーマンスの改善、
デフォルトでの設定値の見直し、プラグインのオフラインインストール対応などが行われました。


今後はキューが大幅に見直され、永続化されるようになり、
またキューの長さも可変になり、デッドレターキューが追加されるなど、
キューとしてきちんと使える、つまりデータの中継地として活用できるようになってきました。

多数のサーバのシステムリソース収集やログ収集を始めると、
ログを集中的に収集して、中継するような仕組みが欲しくなるものなのですが、
そこにLogstashが入ってくる形ですね。

AWSで言うところのKinesisの役割を、Logstashが負ってくることを期待しています。

Beats & ES-Hadoop

Beatsは昨日震えたやつなので、そちらを参照してください。
acro-engineer.hatenablog.com

なお昨日は触れられていませんが、ログファイルをElasticsearch/Logstashに転送する「Filebeat」というBeatもあります。
これまで、Logstash forwarderやfluentdのtail pluginなどで実現していたところで、このFilebeatが使える形になります。


ES-Hadoopは名前のまんまですが、ElasticsearchとHadoopを連携するプロダクトです。

Elasticsearchから情報を取って、Hadoopで加工/分析/集計などを行って、
またElasticsearchに書き戻すことができるようにするための機能ですね。
MapReduce、Hive、Pig、Cascading、Spark、Stormに対応しています。

Elasticsearchを検索エンジンや、可視化のためのストレージだけでなく、
アプリケーションプラットフォームの中枢として用いることを狙っているように思うプロダクトですね。

拡張機能たち

まだまだ紹介は続きますよー! 続いては拡張機能たち。
これはSteve Mayzakから紹介されました。

Shieldはセキュリティプラグイン
LDAPと連携したSSOや、通信経路の暗号化、監査ログなどの機能を有しています。

Shield 2.1からindex(RDBMSで言うところのテーブル)レベルのセキュリティ制限だけでなく、
フィールド(RDBMSで言うところのカラム)レベルでのセキュリティ設定ができるようになりました。

将来的には、APIの強化や、管理UIの追加などが予定されています。
管理UIはよっ!


Watcherはアラートや通知を行うためのプラグイン
モニタリングの用途にElasticsearchを使う時には、絶対なくてはならないヤツですね。

Watcher 2.1で複数のデータソースに対する複合的な判定(と、その結果による通知)や
Pipeline Aggregationを用いた異常検知機能が追加されています。
この辺も、早く試してみなくては!

こちらも将来的に、管理UI、Kibanaとの統合などが計画されており、早く来て欲しいです!


MarvelはElasticsearch自体のモニタリングを行うためのプラグイン
こちらは既にKibanaアプリとして、Kibanaに統合されています。

Elasticsearchが動いているJavaプロセスのCPU使用率、メモリ使用量、ディスクの空きサイズ、
またindexの数や、検索/追加のスループットなども、すべて可視化されます。

現在はElasticsearchのモニタリングのみですが、
将来的にはLogstash、Kibana、Beatsのモニタリング機能や、アラート機能の追加が計画されています。

ELKの開発者にフルサポートされている「唯一の」マネージドElasticsearchサービス、Found

Elasticsearch as a Serviceの形で提供されているのが、Foundです。
唯一の、というところが強調されており、
AWS Elasticsearch Serviceへの対抗意識が垣間見えます。
そう、AWSのやつはOSSホスティングなので、上に書いた拡張機能が使えなかったり、
elastic社のサポートが受けられなかったりするのですよね。

どうあれ、
Elasticsearchの環境構築や運用というのは、それなりに大変だなと日々使っていて思うので、
この辺りを一気にアウトソーシングできるFoundは、かなり有用な気がします。


ということで、elasticの今とこれからを一気に紹介する、お腹いっぱいの基調講演でした。
午後からは、各社の事例紹介が続きます!


ちなみに、お昼はお弁当が用意されています。
無料イベントなのに、ありがたすぎます!!!