elasticsearch+nodejs+dynamodbで作る全社システム基盤
DESCRIPTION
2/7にリクルートテクノロジーズで行われた、elasticsearch勉強会での資料です。TRANSCRIPT
Elasticsearch+ DynamoDB
+Node.jsで作る全社基盤
http://www.flickr.com/photos/67810830@N07/8015511503/sizes/l/
あいのや なおき
相野谷 直樹 ainoya2013. 09~ リクルートテクノロジーズAWS 上でのシステム開発運用・検討など
アジェンダ
• 背景• システム構成• Elasticsearch の使い方• ログ可視化・モニタリングへの活用• まとめ
スマホアプリのための Push 通知基盤を作った話
Push 通知
スマホアプリのための Push 通知基盤
社員 API
Push!Push!
スマートデバイスへのプッシュ通知を実現するシステム
• Push 通知の典型的な機能– 全デバイス指定配信
– デバイス指定
– 条件指定
• リクルートの全アプリを対象
• 社内のビックデータ基盤とスムーズに連携させるために自分たちで開発
Push通知
社員 API
Push!
システム構成
全体のシステム構成
•AWS
インフラ•E
lastic Beanstalk
デプロイ
•Cloudformation
構成管理
•Node.js
開発言語
•DynamoDB
DB
•Elasticsearch
検索
DynamoDB
Elasticsearchクラスタ
デバイス登録 リクエスト
APNs/GCMサーバ
登録 API
データ登録
Push 配信 リクエスト
配信者
配信worker
SQS
SQS登録worker
配信者側 Web アプリ
システム管理・操作用Web UI管理 API
プッシュ配信基盤システム構成
データ参照
DynamoDB
Elasticsearchクラスタ
デバイス登録 リクエスト
APNs/GCMサーバ
登録 API
データ登録
Push 配信 リクエスト
配信者
配信worker
SQS
SQS登録worker
配信者側 Web アプリ
システム管理・操作用Web UI管理 API
プッシュ配信基盤システム構成
データ参照
スマホアプリが自社 SDK 経由でプッシュ配信基盤にデバイス情報を登録
DynamoDB
Elasticsearchクラスタ
デバイス登録 リクエスト
APNs/GCMサーバ
登録 API
データ登録
Push 配信 リクエスト
配信者
配信worker
SQS
SQS登録worker
配信者側 Web アプリ
システム管理・操作用Web UI管理 API
プッシュ配信基盤システム構成
データ参照
デバイス情報をDynamoDB( マスターデータ ) とElasticsearch クラスタに登録
DynamoDB
Elasticsearchクラスタ
デバイス登録 リクエスト
APNs/GCMサーバ
登録 API
データ登録
Push 配信 リクエスト
配信者
配信worker
SQS
SQS登録worker
配信者側 Web サーバ
システム管理・操作用Web UI管理 API
プッシュ配信基盤システム構成
データ参照
配信者 or 配信側 Web サーバがPush 配信リクエスト
DynamoDB
Elasticsearchクラスタ
デバイス登録 リクエスト
APNs/GCMサーバ
登録 API
データ登録
Push 配信 リクエスト
配信者
配信worker
SQS
SQS登録worker
配信者側 Web サーバ
システム管理・操作用Web UI管理 API
プッシュ配信基盤システム構成
配信者 or 配信側 Web サーバがPush 配信リクエスト
配信タイプに応じてDynamoDB or Elasticsearchのデバイス情報を参照対象デバイスに Push 配信
DynamoDB
Elasticsearchクラスタ
デバイス登録 リクエスト
APNs/GCMサーバ
登録 API
データ登録
Push 配信 リクエスト
配信者
配信worker
SQS
SQS登録worker
配信者側 Web サーバ
システム管理・操作用Web UI管理 API
プッシュ配信基盤システム構成
① 配信者 or 配信側 Web サーバがPush 配信リクエスト
② 配信タイプに応じてDynamoDB or Elasticsearchのデバイス情報を参照対象デバイスに Push 配信
③• 全件指定配信• ID 指定配信
時にデータ参照
④条件検索指定配信
時にデータ参照
条件指定 Push の実現アプリごとに指定されたタグで対象デバイスを検索して Push
プッシュ配信 API
管理用 Web UI Push 配信条件を指定 ✔ 対象アプリ : アプリB ✔起動回数 : 10 回以上 ✔ 年齢 : 18 歳以上
デバイス登録 API
Bアプリ B
{ “ アプリ起動回数” : 120, “ 好きなジャンル” : “ お笑い” , “ 年齢” :”18”}
付加情報 !
Elasticsearch が必要な理由
• DynamoDB は KVS → 検索が苦手• 検索エンジンが別途必要
• 多数アプリからの大規模な利用• 高速・スケーラブル
• アプリごとに自由な付加情報• スキーマレス
Elasticsearch の使い方
Elasticsearch で条件指定配信するために
クラスタ構成
性能• Scan• Node.jsとの組み合わせ• 更新
リストア
Elasticsearch クラスタ構成
– クラスタリング• ec2 プラグイン
– Auto scaling Group• min-size = max-size で台数を一定
化–MultiAZ 構成
• 2AZ に配置• Replica 数
– AZ 障害を想定– ceil(n/2)
» 4 台構成なら 2
Auto scaling Group
Availability Zone 1
Availability Zone 2
Internal ELB
性能• Scan• Node.jsとの組み合わせ• 更新
このシステムでの検索の特徴
•条件指定 Push•条件にヒットした全端末に Push•検索結果をすべて取得•ページングが必要•Scan を使用
search_type : scan• scan/scroll– 検索時にソートしないので Deep scrolling に強い– ページング時のデータ抜けも防げる
• 簡単な使い方Search_type=scan でリクエストを送ると scroll_id が返る
{ "hits": {…},…, "_scroll_id": "c2Nhbjs5…NzA0MDMxOw==“}
Elasticsearch が内部で作った Scroll objectの id
レスポンス :
curl -XGET 'localhost:9200/_search?search_type=scan&scroll=10m&size=50' –d $query
scroll_id を指定して検索結果セット (scroll object) を scroll していく
curl -XGET 'localhost:9200/_search/scroll?scroll=10m' –d $scroll_id
リクエスト毎に size 分だけの検索結果が返る{“hits”: {…},…}
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-search-type.html#scan
Scan/scroll 利用時のオプションなど最初の scan で scroll object を生成する時
‘localhost:9200/hoge_index/_search?search_type=scan&scroll=10m&size=50’ –d $query
scroll=10m
size=50
Elasticsearch 内部で Scroll Object を保持する期間
1 回の scroll リクエストで取り出す検索結果数※ Elasticsearch 内部では shard*size の件数ぶんだけ結果を引くので ドキュメント数が多い場合やサーバのメモリが少ない場合は注意
Scroll 時 :
curl -XGET 'localhost:9200/_search/scroll?scroll=10m' –d $scroll_id
Index 指定の Scroll でも root path へのリクエストであることに注意
性能• Scan• Node.jsとの組み合わせ• 更新
Node.js から Elasticsearch を使う
• Elastical client
• 独自のスキーマ構成を反映した Wrapper を用意
https://github.com/ramv/node-elastical
var client = new elastical.Client('example.com', {port: 1234});
client.search({query: 'welcome'}, function (err, results, res) { do_something();});
var deviceIndex = exports.elasticSearch.indexes.deviceIndex;
deviceIndex.search(searchInfo.appId, query, options, function(err, total, hits) { if (err) { return cb(err); } cb(null, total, hits);});
Wrapper 側に用意した‘ deviceIndex’ のスキーマで フィールドの型を js の型にマッピング
hits オブジェクトを 型付きの状態でそのまま利用できる →煩雑な型定義からの解放
データ抽出 Stream
データ形式変換Stream
配信 Stream
配信処理レポートStream
Node.js の Stream で検索結果処理
Stream : データの流れを抽象化したインタフェース
検索から push 通知までの一連を非同期 I/O で実装して処理高速化 ➜ Stream API を使って簡潔に記述
Push 配信 Queue
条件指定
全件
ID指定
アプリ ID:xxx配信タイプ : 全件 /ID指定 /条件指定配信メッセージ :hogehoge
配信リクエスト
Push!
Push!
各処理の Stream を繋いでパイプライン化 対象を抽出しつつ配信を行う
各処理の Stream を繋いでパイプライン化 対象を抽出しつつ配信を行う
var searchStream = new SearchStream(query); // scan/scroll 処理の stream 実装
// 検索結果を解釈して、 Push 配信を行い、配信結果を保存する SearchStream.pipe(transferStream) // データ変換用 stream .pipe(resultStream) //Push 配信 stream .pipe(resultStream); // 結果格納用の stream
Node.js の Stream で検索結果処理
性能• Scan• Node.jsとの組み合わせ• 更新
データ更新時の負荷平滑化
Auto scaling Group
Auto scaling Group
CloudWatch
CloudWatch
登録 API 登録 Workerデバイス登録
QueueELB
DynamoDB
Elasticsearch
EC2の CPU使用率に応じオートスケール
Queueのメッセージ数に応じオートスケール
リクエスト負荷がElasticsearch の更新性能を超え
る場合も安定稼働多数デバイスからの同時リクエスト
リストア
DynamoDB からのリストア• マスターデータはあくまで DynamoDB• Elasticsearch はいつ落ちても復旧できるようにしてお
く
DynamoDB
Elasticsearch
復旧スクリプト
まとめ
まとめ • AWS 上で Elasticsearch を使った検索機
能 ✔ ec2 plugin ✔ Internal ELB ✔ Auto scaling group
➜ 簡単にクラスタ構築して利用可能
• Node.js から Elasticsearch を使う– JSON Object を扱いやすい
• JSON レスポンスの階層が深く結果の取り出しが若干大変– Stream で検索結果を効率よく処理 相性良いです➜
まとめ
ありがとうございました
採用募集