SlideShare a Scribd company logo
1 of 27
Download to read offline
ストリーム処理エンジン「Zero」
開発と運用
佐藤栄一
株式会社サイバーエージェント
技術本部 秋葉原ラボ
オレシカナイト第3回 @ 渋谷プライムプラザ (2017/9/27)
技術本部 :: 秋葉原ラボ
● @秋葉原
● 現在30名強が在籍
○ エンジニア
○ データサイエンティスト
● 共通機能を提供
○ ログ解析基盤
○ レコメンド
○ 検索
○ スパムフィルタ
○ データマイニング
※画像は弊社HPより引用
What is Zero ?
SELECT
count(*) AS foo,
sum(`...`) AS bar
FROM
flume(`.datetime`) DISTINCT ON `.uuid` FOR 10m
WHERE `
...
`
GROUP BY `{
user_id: ...
}`
PARTITION BY user_id
INTERVAL 1d, NONE
クエリ(ZeroQL)を登録すると ...
… 結果をリアルタイムに取得できます。
GET /v1/report.json?column.user_id=1
HTTP/1.1 200 OK
Content-type: application/json
{
"rows": [
{
"user_id": 1,
"foo": 100,
"bar": 200
}
]
}
ログの発生から結果に反映されるまで数秒程度。
結果のレスポンス時間は平均数ミリ秒 ~ 数十ミリ秒程度。
What is Zero ?
COUNT(*)
イベントの件数
SUM(…)
合計
What is Zero ?
MAX(…)
最大値
MIN(…)
最小値
What is Zero ?
LATEST(…)
最新値
LATEST_N(…,n)
最新のn件
LATEST_SET_N(…,n)
最新のn件(重複を除く)
What is Zero ?
WHERE `
.name == "jackson-jq"
and .language == "java"
and .url == "https://github.com/eiiches/jackson-jq"
`
● JSON形式のイベント(ログ)処理のためにjqに対応
SELECT
SUM(`if .action == "click" then 100 else 1 end`) AS score
ライブラリ(Java)としてjackson-jqを開発
GROUP BY `{
user_id: .user_id,
ad_id: .ads[].id
}`
利用例
● 広告配信システム @ MDH
○ 実績値のリアルタイムレポート (sum/count)
○ フリクエンシーキャップ & リターゲティング (sum/count)
○ オンライン予測に用いる素性 (sum/count/latest)
● その他、各種サービスで利用中
○ レコメンド、プッシュ通知等での配信制御 (sum/count/latest/latest_set_n)
○ リアルタイムレポート (sum/count)
本番環境では計70弱のクエリの登録がありました
Architecture
Monoid Storage (Apache HBase, Amazon DynamoDB, ...)
Cache (Redis)Dedup (Redis)
SELECT
COUNT(*) AS total,
SUM(`if .type == "click" then 1 else 0 end`) AS click,
LATEST_N(`.url`, 3) AS urls
FROM flume(`.datetime`) DISTINCT ON `.uuid` FOR 10m
WHERE `headers.service = "foo"`
GROUP BY `{
user_id: .user_id
}`
ApacheZookeeper
ServiceDiscovery
Configuration
Event Processor Query Server
Event (JSON)
Apache Flume, HTTP, ...
Result (JSON)
Event ProcessorとQuery Serverの中身は同一
SpringBoot (Java) で実装
前提
● イベントは重複して届くことがある (at least once)
● イベントが届く順序は保証されない
● 一定時間内に到着した同一のイベントを除外する
● Redisに処理したイベントIDを記録しておく(厳密ではない)
● どのような順序で到着しても問題ないように処理する
● 可換モノイドとしてデータ構造と処理を抽象化
モノイド
● 条件を満たす「値」と「二項演算」の組み合わせ
○ 結合則: a + (b + c) = (a + b) + c
○ 単位元: a + e = e + a = a
「交換則: a + b = b + a」を追加すると
「可換」モノイドに。
(int, +)
(int, ×)
(int, max)
(int, min)
(int, ÷)
モノイド
(Pair<Time, T>, newer)
(List<Pair<Time, T>>, newer_n)
(List<Pair<Time, T>>, newer_set_n)
プリミティブ型に限らず、定義できる
Event Processor
1. イベントを受信
SUM(`.quantity`)
{
"action": "buy",
"quantity": 10,
"user_id": "sato"
}
2. モノイドに変換
4. 書き込みキューにいれる
Apache
HBase
5. ストレージに書く
Increment
Put
CheckAndPut
Amazon
DynamoDB
UpdateItem
Redis
Redis
Redis
6. キャッシュを無効化
Redis
Redis
Redis
3. 重複チェック
+10
+5
書き込みキュー
● 条件を満たすまでtake()出来ない
○ 最大サイズ(設定値)の90%以上のキュー長になった場合
○ または、put()されてから、最小滞在時間(設定値)経過した場合
● put()時に、キーが重複する場合にモノイドが(+)される
A
imp: 1
put() take()
最大サイズ(設定値)
☠
B
click: 3, imp: 9
A
click: 1, imp: 2
B
click: 3, imp: 9
初期の実装:
「1秒貯めてから書き込み」or「貯めずに直接書き込み」
→ 貯めて書いての繰り返しなので負荷が安定しない
Query Server
1. リクエストを受信
3. ストレージから読み込み
Get
Scan
Query
2. キャッシュに問い合わせ
(ネガティブキャッシュあり)
Apache
HBase
Amazon
DynamoDB
Redis
Redis
Redis
{
"user_id": "sato"
}
Rate
Limiter
Request
Coalescing
503 Service Unavailable
Circuit
Breaker
Rate Limiting
● クエリ毎に「同時リクエスト数」が一定を超えた場合に503を返却
○ 障害時の影響範囲を限定。
○ クライアント側は“必要に応じて”リトライ
■ 指数バックオフ + ジッタ推奨
● クエリ毎に「秒間リクエスト数」が一定を超えた場合に503を返却
○ 障害時に一時的に設定する、などを想定。平常時は設定していない。
☠
例えば、HBaseのサーバーダウンなど一部の障害が、本来関係のな
いサービスに影響することをを防ぎます。
☠
後からだと503を返して問題ないか確認が必要なので、最初からいれておいたほうが良いです。
・・・まだ対応が終わっていない箇所が・・・
Request Coalescing
● ストレージへの同一のREADリクエストは束ねる
Storage
READ 10
READ 10
READ 10{id: 10}
{id: 10}
wait
Request Coalescing
ほぼ同一のリクエスト
☠
例えば、リクエスト元にキャッシュがあり、そのキャッシュがexpireした場
合に、実装次第で同一のリクエストが届く。
また、レスポンス時間が伸びるほど問い合わせが来る(悪循環)
※ thundering herd もしくは cache stampede として知られています。
キャッシュ
● Redisは速いが、1台では限界がある => Consistent Hashingで分散
○ ノードの追加・削除時、キャッシュの再配置をなるべく避ける。
Node 1
Node 2
Node 3
0
Key B
Key A
Key C
事前にNodeのハッシュ値を計算しておく。
1. Keyのハッシュ値を計算。
2. (反)時計回りにNodeを探す。
ハッシュ値域
[0, 256)
☠
※ 実際には、割り当ての偏りを少なくするために、仮想Nodeを使います。
最初は1台でしたが、負荷が上がっ
て急いで対応しました><
キャッシュ (オートスケーリング)
● キャッシュサーバーもオートスケーリングしたい!
○ => キャッシュノード自身が Zookeeperに自分を登録
○ ZBeacon
■ Zookeeperにエフェメラルノードを書くだけの小さなデーモン( Goで150行程度)
■ キャッシュノードで常駐させておく
○ Redisは1コアしか使用できないので、複数プロセス立ち上げる
zbeacon -hosts zk01.example.com,zk02.example.com,zk03.example.com 
-path /zero/cache-servers/`hostname -f`:6379
-data `hostname -f`:6379
☠
以前は小さなインスタンスをたくさん並べていたので、 IPアド
レスを無駄に消費してしまい・・・
キャッシュ (エラー処理)
● エラーの場合はキャッシュミス同様、ストレージから読み込み
○ タイムアウトは100msで設定。
○ キャッシュ読み込みは継続し、 read()自体は1000msでタイムアウト。
● キャッシュノード毎にCircuitBreaker処理
○ キャッシュへの同時リクエスト数が一定以上になった場合は最初から弾く。
☠
当初は setSoTimeout() していたが、ライブラリがエラーになったコネクションを再利用しない
ため、後続のリクエストで瞬間的に再接続が頻発して不安定に・・・
運用
● 現在3クラスタ: プライベートクラウド / AWS (HBase用、DynamoDB用)
● AWS環境
○ オートスケーリングを活用
○ デプロイは独自ツール (Git-versioned Red-black Deployment)
■ ELB以外のリソース(ASG, LC, etc.)は毎回新規作成
○ アプリに特化したAMIは作っていない(共通AMIにdocker追加)
■ インスタンス起動時に ECRのイメージをdocker run
■ --security-opt seccomp=unconfined --network=host --iptables=false
● ほぼCPUオーバーヘッドなし (conntrack, seccomp, etc.)
● プライベートクラウド環境
○ Query Server : docker-compose, kubernetes
○ Event Processor : docker-compose
○ Redis Cache / Dedup : ansible
※ zk, redisは共用
監視
● InfluxDB + Grafana alerting
○ Dropwizard Metricsでアプリケーションメトリクスを JMXで公開
○ Javaエージェントでほぼ全ての JMXメトリクスをまとめて InfluxDBに10秒おきに送信
■ https://github.com/eiiches/java-influxdb-metrics-agent
● Zabbix
○ 自動登録機能 + シャットダウン時にホスト無効化、でオートスケーリングに対応
○ 基本的なインスタンスの監視
■ ディスク容量, etc.
○ Redis (cache, dedup) の監視
○ APIの死活監視
これはGrafana移行予定
Apache HBase Hadoop上の分散NoSQL
Column Family 1 Column Family 2 ...
A B A B C
...
aaaa 7 5 23
bbbb 3 11 29
...
zzzz 17 13 1 19
...
昇順
新
旧
Region
Region
Server
1
Region
Server
2
HBase Storage
● スキーマ設計
○ 後から変えるのはしんどい。
○ 理由がない限り、行キーの先頭にはハッシュ値 (1,2byte)を付ける。
■ 負荷が偏ると運用が厳しい。事前にハッシュ値境界で分割 (split)しておく。
● CheckAndPut操作
○ リトライするときは指数バックオフだけでなくジッタもいれる。
○ 同じサーバーからは同じ行への変更が同時にされないようにロックを掛ける。
● ASYNC_WAL (WAL = Write-Ahead Log)
○ 障害時にごく短時間の書き込みロストが許容できる場合は有効に。
Tuning Apache HBase
● -XX:+UseG1GC
○ CMS等に比べてYouAreDeadExceptionで死ぬ頻度を減らせる。
● RegionServer Group based Assignment
○ 本来はHBase 2(未リリース)の機能。一部のディストリビューションで使える。
○ 「このテーブルはこのサーバーに配置したい」を指定できる。
■ 障害時の影響範囲を限定するのに有効。
● CallQueueの分割 (write/read/scan)
○ 「書き込みの負荷が読み込みに影響する」を防止できる。
● hbase.assignment.zkevent.workers = 1
○ HMasterがデッドロックするバグの回避。
● hbase.ipc.server.reservoir.enabled = false
○ バッファの確保サイズは大きくなる一方なのである時死ぬバグの回避。
Patching Apache HBase
● [HBASE-14460] スレッドの競合でread-modify-writeが遅くなる
○ HBaseチームでパッチ作成 (HBASE-14460のパッチとは別)
○ Fix: 忘れました
● [HBASE-17072] ThreadLocal内のハッシュテーブルで負荷高騰
○ ハッシュテーブルの primary clustering
○ 不要なキャッシュロジックをごっそり削除(乱暴)
○ Fix: 2.0.0, 1.4.0, 0.98.24, cdh5.10.0
● [HBASE-18042,...] Scannerをサーバー側で早期クローズ
○ 何故かScannerが大量に残ってFullGCで死ぬことがあり、そもそも早期クローズで回避。
○ branch-1.3のコミットをバックポート
○ Fix: 1.3.2
まとめ
● ストリーム処理エンジン「Zero」の紹介
○ == 手軽にリアルタイムにデータを活用できる汎用的な仕組み
○ jqを組み合わせたSQLライクなクエリ言語
○ モノイドによる処理の抽象化
● 安定性向上のための工夫の紹介
○ 他のシステムでもある程度一般的に適用できるはず (?)
● デプロイ・監視などの運用の紹介
● 今後の開発予定
○ Apache Phoenix / Redis / Apache Kafka / Amazon Kinesis
○ 集約関数追加 / Join機能(?)

More Related Content

What's hot

MongoDBのアレをアレする
MongoDBのアレをアレするMongoDBのアレをアレする
MongoDBのアレをアレするAkihiro Kuwano
 
MongoDBのはじめての運用テキスト
MongoDBのはじめての運用テキストMongoDBのはじめての運用テキスト
MongoDBのはじめての運用テキストAkihiro Kuwano
 
ZabbixによるAWS監視のコツ
ZabbixによるAWS監視のコツZabbixによるAWS監視のコツ
ZabbixによるAWS監視のコツShinsukeYokota
 
Introduction to MongoDB
Introduction to MongoDBIntroduction to MongoDB
Introduction to MongoDBmoai kids
 
Webサーバの性能測定
Webサーバの性能測定Webサーバの性能測定
Webサーバの性能測定Ryo Maruyama
 
Lisp Tutorial for Pythonista : Day 4
Lisp Tutorial for Pythonista : Day 4Lisp Tutorial for Pythonista : Day 4
Lisp Tutorial for Pythonista : Day 4Ransui Iso
 
Black jumbodogの新機能(webapi)~自動テストにおけるsmtpモックとして
Black jumbodogの新機能(webapi)~自動テストにおけるsmtpモックとしてBlack jumbodogの新機能(webapi)~自動テストにおけるsmtpモックとして
Black jumbodogの新機能(webapi)~自動テストにおけるsmtpモックとしてShinichi Hirauchi
 
カジュアルにMongo dbのbackup機能説明
カジュアルにMongo dbのbackup機能説明カジュアルにMongo dbのbackup機能説明
カジュアルにMongo dbのbackup機能説明Masakazu Matsushita
 
Web Service on SSD
Web Service on SSDWeb Service on SSD
Web Service on SSDKazuho Oku
 
Custom Scan API - PostgreSQL Unconference #3 (18-Jan-2014)
Custom Scan API - PostgreSQL Unconference #3 (18-Jan-2014)Custom Scan API - PostgreSQL Unconference #3 (18-Jan-2014)
Custom Scan API - PostgreSQL Unconference #3 (18-Jan-2014)Kohei KaiGai
 
東京Node学園#3 Domains & Isolates
東京Node学園#3 Domains & Isolates東京Node学園#3 Domains & Isolates
東京Node学園#3 Domains & Isolateskoichik
 
Fabricでサーバー管理をDRYにしよう
Fabricでサーバー管理をDRYにしようFabricでサーバー管理をDRYにしよう
Fabricでサーバー管理をDRYにしようmax747
 
エコなWebサーバー
エコなWebサーバーエコなWebサーバー
エコなWebサーバーemasaka
 
MongoDB Configパラメータ解説
MongoDB Configパラメータ解説MongoDB Configパラメータ解説
MongoDB Configパラメータ解説Shoken Fujisaki
 
ソーシャルゲームにおけるMongoDB適用事例 - Animal Land
ソーシャルゲームにおけるMongoDB適用事例 - Animal LandソーシャルゲームにおけるMongoDB適用事例 - Animal Land
ソーシャルゲームにおけるMongoDB適用事例 - Animal LandMasakazu Matsushita
 
2日間Fabricを触った俺が
 色々解説してみる
2日間Fabricを触った俺が
 色々解説してみる2日間Fabricを触った俺が
 色々解説してみる
2日間Fabricを触った俺が
 色々解説してみるairtoxin Ishii
 
Reactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単にReactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単にYoshifumi Kawai
 
分割と整合性と戦う
分割と整合性と戦う分割と整合性と戦う
分割と整合性と戦うYugo Shimizu
 

What's hot (20)

MongoDBのアレをアレする
MongoDBのアレをアレするMongoDBのアレをアレする
MongoDBのアレをアレする
 
MongoDBのはじめての運用テキスト
MongoDBのはじめての運用テキストMongoDBのはじめての運用テキスト
MongoDBのはじめての運用テキスト
 
ZabbixによるAWS監視のコツ
ZabbixによるAWS監視のコツZabbixによるAWS監視のコツ
ZabbixによるAWS監視のコツ
 
Introduction to MongoDB
Introduction to MongoDBIntroduction to MongoDB
Introduction to MongoDB
 
Webサーバの性能測定
Webサーバの性能測定Webサーバの性能測定
Webサーバの性能測定
 
Lisp Tutorial for Pythonista : Day 4
Lisp Tutorial for Pythonista : Day 4Lisp Tutorial for Pythonista : Day 4
Lisp Tutorial for Pythonista : Day 4
 
Black jumbodogの新機能(webapi)~自動テストにおけるsmtpモックとして
Black jumbodogの新機能(webapi)~自動テストにおけるsmtpモックとしてBlack jumbodogの新機能(webapi)~自動テストにおけるsmtpモックとして
Black jumbodogの新機能(webapi)~自動テストにおけるsmtpモックとして
 
カジュアルにMongo dbのbackup機能説明
カジュアルにMongo dbのbackup機能説明カジュアルにMongo dbのbackup機能説明
カジュアルにMongo dbのbackup機能説明
 
Web Service on SSD
Web Service on SSDWeb Service on SSD
Web Service on SSD
 
Fabric Essentials
Fabric EssentialsFabric Essentials
Fabric Essentials
 
Custom Scan API - PostgreSQL Unconference #3 (18-Jan-2014)
Custom Scan API - PostgreSQL Unconference #3 (18-Jan-2014)Custom Scan API - PostgreSQL Unconference #3 (18-Jan-2014)
Custom Scan API - PostgreSQL Unconference #3 (18-Jan-2014)
 
東京Node学園#3 Domains & Isolates
東京Node学園#3 Domains & Isolates東京Node学園#3 Domains & Isolates
東京Node学園#3 Domains & Isolates
 
Fabricでサーバー管理をDRYにしよう
Fabricでサーバー管理をDRYにしようFabricでサーバー管理をDRYにしよう
Fabricでサーバー管理をDRYにしよう
 
エコなWebサーバー
エコなWebサーバーエコなWebサーバー
エコなWebサーバー
 
MongoDB Configパラメータ解説
MongoDB Configパラメータ解説MongoDB Configパラメータ解説
MongoDB Configパラメータ解説
 
ソーシャルゲームにおけるMongoDB適用事例 - Animal Land
ソーシャルゲームにおけるMongoDB適用事例 - Animal LandソーシャルゲームにおけるMongoDB適用事例 - Animal Land
ソーシャルゲームにおけるMongoDB適用事例 - Animal Land
 
MySQLの冗長化 2013-01-24
MySQLの冗長化 2013-01-24MySQLの冗長化 2013-01-24
MySQLの冗長化 2013-01-24
 
2日間Fabricを触った俺が
 色々解説してみる
2日間Fabricを触った俺が
 色々解説してみる2日間Fabricを触った俺が
 色々解説してみる
2日間Fabricを触った俺が
 色々解説してみる
 
Reactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単にReactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単に
 
分割と整合性と戦う
分割と整合性と戦う分割と整合性と戦う
分割と整合性と戦う
 

Viewers also liked

Ameba広告の配信制御アーキテクチャを刷新した話 ~オレシカナイトvol.3~
Ameba広告の配信制御アーキテクチャを刷新した話 ~オレシカナイトvol.3~Ameba広告の配信制御アーキテクチャを刷新した話 ~オレシカナイトvol.3~
Ameba広告の配信制御アーキテクチャを刷新した話 ~オレシカナイトvol.3~Yusuke Komahara
 
DSPでgolangの屍を超えた話 (オレシカナイト Vol.2)
DSPでgolangの屍を超えた話 (オレシカナイト Vol.2)DSPでgolangの屍を超えた話 (オレシカナイト Vol.2)
DSPでgolangの屍を超えた話 (オレシカナイト Vol.2)Yuki Katada
 
goで末尾再帰最適化は使えるか?
goで末尾再帰最適化は使えるか?goで末尾再帰最適化は使えるか?
goで末尾再帰最適化は使えるか?mori takuma
 
1年目でgolangとscalaを触った話
1年目でgolangとscalaを触った話1年目でgolangとscalaを触った話
1年目でgolangとscalaを触った話yoshito oe
 
iQONを支えるクローラーの裏側
iQONを支えるクローラーの裏側iQONを支えるクローラーの裏側
iQONを支えるクローラーの裏側Takehiro Shiozaki
 
Test Yourself - テストを書くと何がどう変わるか
Test Yourself - テストを書くと何がどう変わるかTest Yourself - テストを書くと何がどう変わるか
Test Yourself - テストを書くと何がどう変わるかTakuto Wada
 
コンピュータビジョンの今を映す-CVPR 2017 速報より- (夏のトップカンファレンス論文読み会)
コンピュータビジョンの今を映す-CVPR 2017 速報より- (夏のトップカンファレンス論文読み会)コンピュータビジョンの今を映す-CVPR 2017 速報より- (夏のトップカンファレンス論文読み会)
コンピュータビジョンの今を映す-CVPR 2017 速報より- (夏のトップカンファレンス論文読み会)cvpaper. challenge
 
NIPS2015読み会: Ladder Networks
NIPS2015読み会: Ladder NetworksNIPS2015読み会: Ladder Networks
NIPS2015読み会: Ladder NetworksEiichi Matsumoto
 

Viewers also liked (9)

Ameba広告の配信制御アーキテクチャを刷新した話 ~オレシカナイトvol.3~
Ameba広告の配信制御アーキテクチャを刷新した話 ~オレシカナイトvol.3~Ameba広告の配信制御アーキテクチャを刷新した話 ~オレシカナイトvol.3~
Ameba広告の配信制御アーキテクチャを刷新した話 ~オレシカナイトvol.3~
 
DSPでgolangの屍を超えた話 (オレシカナイト Vol.2)
DSPでgolangの屍を超えた話 (オレシカナイト Vol.2)DSPでgolangの屍を超えた話 (オレシカナイト Vol.2)
DSPでgolangの屍を超えた話 (オレシカナイト Vol.2)
 
goで末尾再帰最適化は使えるか?
goで末尾再帰最適化は使えるか?goで末尾再帰最適化は使えるか?
goで末尾再帰最適化は使えるか?
 
1年目でgolangとscalaを触った話
1年目でgolangとscalaを触った話1年目でgolangとscalaを触った話
1年目でgolangとscalaを触った話
 
iQONを支えるクローラーの裏側
iQONを支えるクローラーの裏側iQONを支えるクローラーの裏側
iQONを支えるクローラーの裏側
 
Test Yourself - テストを書くと何がどう変わるか
Test Yourself - テストを書くと何がどう変わるかTest Yourself - テストを書くと何がどう変わるか
Test Yourself - テストを書くと何がどう変わるか
 
コンピュータビジョンの今を映す-CVPR 2017 速報より- (夏のトップカンファレンス論文読み会)
コンピュータビジョンの今を映す-CVPR 2017 速報より- (夏のトップカンファレンス論文読み会)コンピュータビジョンの今を映す-CVPR 2017 速報より- (夏のトップカンファレンス論文読み会)
コンピュータビジョンの今を映す-CVPR 2017 速報より- (夏のトップカンファレンス論文読み会)
 
ICCV 2017 速報
ICCV 2017 速報 ICCV 2017 速報
ICCV 2017 速報
 
NIPS2015読み会: Ladder Networks
NIPS2015読み会: Ladder NetworksNIPS2015読み会: Ladder Networks
NIPS2015読み会: Ladder Networks
 

Similar to ストリーム処理エンジン「Zero」の開発と運用

泥臭い運用から、プログラマブルインフラ構築(に行きたい)
泥臭い運用から、プログラマブルインフラ構築(に行きたい) 泥臭い運用から、プログラマブルインフラ構築(に行きたい)
泥臭い運用から、プログラマブルインフラ構築(に行きたい) Akihiro Kuwano
 
ZOZOTOWNで最大級のトラフィックを記録する福袋発売イベントで実施した負荷対策と、当日の監視体制について
ZOZOTOWNで最大級のトラフィックを記録する福袋発売イベントで実施した負荷対策と、当日の監視体制についてZOZOTOWNで最大級のトラフィックを記録する福袋発売イベントで実施した負荷対策と、当日の監視体制について
ZOZOTOWNで最大級のトラフィックを記録する福袋発売イベントで実施した負荷対策と、当日の監視体制についてMasaki Hirose
 
Lv1から始めるWebサービスのインフラ構築
Lv1から始めるWebサービスのインフラ構築Lv1から始めるWebサービスのインフラ構築
Lv1から始めるWebサービスのインフラ構築伊藤 祐策
 
LambdaでHello, World(2017/07/21 サーバレスアーキテクチャ勉強会)
LambdaでHello, World(2017/07/21 サーバレスアーキテクチャ勉強会)LambdaでHello, World(2017/07/21 サーバレスアーキテクチャ勉強会)
LambdaでHello, World(2017/07/21 サーバレスアーキテクチャ勉強会)Kousuke Ishikawa
 
負荷試験、どうしてる?(公開版)
負荷試験、どうしてる?(公開版)負荷試験、どうしてる?(公開版)
負荷試験、どうしてる?(公開版)miki koganei
 
負荷試験、どうしてる?
負荷試験、どうしてる?負荷試験、どうしてる?
負荷試験、どうしてる?miki koganei
 
Using Amazon Aurora for Enterprise Workloads
Using Amazon Aurora for Enterprise WorkloadsUsing Amazon Aurora for Enterprise Workloads
Using Amazon Aurora for Enterprise WorkloadsAmazon Web Services Japan
 
Auto Scaling x Spot Instances によるスケーラビリティと コストカット
Auto Scaling x Spot Instances によるスケーラビリティと コストカットAuto Scaling x Spot Instances によるスケーラビリティと コストカット
Auto Scaling x Spot Instances によるスケーラビリティと コストカットakitsukada
 
[DO13] 楽天のクラウドストレージ使いこなし術 Azure と OSS で少しずつ進めるレガシー脱却
[DO13] 楽天のクラウドストレージ使いこなし術 Azure と OSS で少しずつ進めるレガシー脱却[DO13] 楽天のクラウドストレージ使いこなし術 Azure と OSS で少しずつ進めるレガシー脱却
[DO13] 楽天のクラウドストレージ使いこなし術 Azure と OSS で少しずつ進めるレガシー脱却de:code 2017
 
国内レンタルサーバとAWSで負荷テストしてみました。
国内レンタルサーバとAWSで負荷テストしてみました。国内レンタルサーバとAWSで負荷テストしてみました。
国内レンタルサーバとAWSで負荷テストしてみました。株式会社雲屋ネットワーク
 
20120317 IT系勉強会 in 神戸
20120317 IT系勉強会 in 神戸20120317 IT系勉強会 in 神戸
20120317 IT系勉強会 in 神戸Takahiro Iwase
 
NHNグループ合同勉強会 ライブドア片野
NHNグループ合同勉強会 ライブドア片野NHNグループ合同勉強会 ライブドア片野
NHNグループ合同勉強会 ライブドア片野livedoor
 
別の角度からAWSを眺めてみた話
別の角度からAWSを眺めてみた話別の角度からAWSを眺めてみた話
別の角度からAWSを眺めてみた話Junichi Tanabe
 
コスト削減から考えるAWSの効果的な利用方法
コスト削減から考えるAWSの効果的な利用方法コスト削減から考えるAWSの効果的な利用方法
コスト削減から考えるAWSの効果的な利用方法Aya Komuro
 
2011年07月 JAWS-UG山口 AWSとの上手な付き合い方
2011年07月 JAWS-UG山口 AWSとの上手な付き合い方2011年07月 JAWS-UG山口 AWSとの上手な付き合い方
2011年07月 JAWS-UG山口 AWSとの上手な付き合い方Serverworks Co.,Ltd.
 
Echo server implementation for Python
Echo server implementation for PythonEcho server implementation for Python
Echo server implementation for PythonToshiki Tsuboi
 
弊社IoT事例とAlexaSkil開発レシピ
弊社IoT事例とAlexaSkil開発レシピ弊社IoT事例とAlexaSkil開発レシピ
弊社IoT事例とAlexaSkil開発レシピTakashi Kozu
 
Active record query interface
Active record query interfaceActive record query interface
Active record query interfaceTomoya Kawanishi
 
AWS Glueを使った Serverless ETL の実装パターン
AWS Glueを使った Serverless ETL の実装パターンAWS Glueを使った Serverless ETL の実装パターン
AWS Glueを使った Serverless ETL の実装パターンseiichi arai
 
ServerlessConf Tokyo2018 サーバーレスなシステムのがんばらない運用監視
ServerlessConf Tokyo2018 サーバーレスなシステムのがんばらない運用監視ServerlessConf Tokyo2018 サーバーレスなシステムのがんばらない運用監視
ServerlessConf Tokyo2018 サーバーレスなシステムのがんばらない運用監視Takanori Suzuki
 

Similar to ストリーム処理エンジン「Zero」の開発と運用 (20)

泥臭い運用から、プログラマブルインフラ構築(に行きたい)
泥臭い運用から、プログラマブルインフラ構築(に行きたい) 泥臭い運用から、プログラマブルインフラ構築(に行きたい)
泥臭い運用から、プログラマブルインフラ構築(に行きたい)
 
ZOZOTOWNで最大級のトラフィックを記録する福袋発売イベントで実施した負荷対策と、当日の監視体制について
ZOZOTOWNで最大級のトラフィックを記録する福袋発売イベントで実施した負荷対策と、当日の監視体制についてZOZOTOWNで最大級のトラフィックを記録する福袋発売イベントで実施した負荷対策と、当日の監視体制について
ZOZOTOWNで最大級のトラフィックを記録する福袋発売イベントで実施した負荷対策と、当日の監視体制について
 
Lv1から始めるWebサービスのインフラ構築
Lv1から始めるWebサービスのインフラ構築Lv1から始めるWebサービスのインフラ構築
Lv1から始めるWebサービスのインフラ構築
 
LambdaでHello, World(2017/07/21 サーバレスアーキテクチャ勉強会)
LambdaでHello, World(2017/07/21 サーバレスアーキテクチャ勉強会)LambdaでHello, World(2017/07/21 サーバレスアーキテクチャ勉強会)
LambdaでHello, World(2017/07/21 サーバレスアーキテクチャ勉強会)
 
負荷試験、どうしてる?(公開版)
負荷試験、どうしてる?(公開版)負荷試験、どうしてる?(公開版)
負荷試験、どうしてる?(公開版)
 
負荷試験、どうしてる?
負荷試験、どうしてる?負荷試験、どうしてる?
負荷試験、どうしてる?
 
Using Amazon Aurora for Enterprise Workloads
Using Amazon Aurora for Enterprise WorkloadsUsing Amazon Aurora for Enterprise Workloads
Using Amazon Aurora for Enterprise Workloads
 
Auto Scaling x Spot Instances によるスケーラビリティと コストカット
Auto Scaling x Spot Instances によるスケーラビリティと コストカットAuto Scaling x Spot Instances によるスケーラビリティと コストカット
Auto Scaling x Spot Instances によるスケーラビリティと コストカット
 
[DO13] 楽天のクラウドストレージ使いこなし術 Azure と OSS で少しずつ進めるレガシー脱却
[DO13] 楽天のクラウドストレージ使いこなし術 Azure と OSS で少しずつ進めるレガシー脱却[DO13] 楽天のクラウドストレージ使いこなし術 Azure と OSS で少しずつ進めるレガシー脱却
[DO13] 楽天のクラウドストレージ使いこなし術 Azure と OSS で少しずつ進めるレガシー脱却
 
国内レンタルサーバとAWSで負荷テストしてみました。
国内レンタルサーバとAWSで負荷テストしてみました。国内レンタルサーバとAWSで負荷テストしてみました。
国内レンタルサーバとAWSで負荷テストしてみました。
 
20120317 IT系勉強会 in 神戸
20120317 IT系勉強会 in 神戸20120317 IT系勉強会 in 神戸
20120317 IT系勉強会 in 神戸
 
NHNグループ合同勉強会 ライブドア片野
NHNグループ合同勉強会 ライブドア片野NHNグループ合同勉強会 ライブドア片野
NHNグループ合同勉強会 ライブドア片野
 
別の角度からAWSを眺めてみた話
別の角度からAWSを眺めてみた話別の角度からAWSを眺めてみた話
別の角度からAWSを眺めてみた話
 
コスト削減から考えるAWSの効果的な利用方法
コスト削減から考えるAWSの効果的な利用方法コスト削減から考えるAWSの効果的な利用方法
コスト削減から考えるAWSの効果的な利用方法
 
2011年07月 JAWS-UG山口 AWSとの上手な付き合い方
2011年07月 JAWS-UG山口 AWSとの上手な付き合い方2011年07月 JAWS-UG山口 AWSとの上手な付き合い方
2011年07月 JAWS-UG山口 AWSとの上手な付き合い方
 
Echo server implementation for Python
Echo server implementation for PythonEcho server implementation for Python
Echo server implementation for Python
 
弊社IoT事例とAlexaSkil開発レシピ
弊社IoT事例とAlexaSkil開発レシピ弊社IoT事例とAlexaSkil開発レシピ
弊社IoT事例とAlexaSkil開発レシピ
 
Active record query interface
Active record query interfaceActive record query interface
Active record query interface
 
AWS Glueを使った Serverless ETL の実装パターン
AWS Glueを使った Serverless ETL の実装パターンAWS Glueを使った Serverless ETL の実装パターン
AWS Glueを使った Serverless ETL の実装パターン
 
ServerlessConf Tokyo2018 サーバーレスなシステムのがんばらない運用監視
ServerlessConf Tokyo2018 サーバーレスなシステムのがんばらない運用監視ServerlessConf Tokyo2018 サーバーレスなシステムのがんばらない運用監視
ServerlessConf Tokyo2018 サーバーレスなシステムのがんばらない運用監視
 

ストリーム処理エンジン「Zero」の開発と運用

  • 2. 技術本部 :: 秋葉原ラボ ● @秋葉原 ● 現在30名強が在籍 ○ エンジニア ○ データサイエンティスト ● 共通機能を提供 ○ ログ解析基盤 ○ レコメンド ○ 検索 ○ スパムフィルタ ○ データマイニング ※画像は弊社HPより引用
  • 3. What is Zero ? SELECT count(*) AS foo, sum(`...`) AS bar FROM flume(`.datetime`) DISTINCT ON `.uuid` FOR 10m WHERE ` ... ` GROUP BY `{ user_id: ... }` PARTITION BY user_id INTERVAL 1d, NONE クエリ(ZeroQL)を登録すると ... … 結果をリアルタイムに取得できます。 GET /v1/report.json?column.user_id=1 HTTP/1.1 200 OK Content-type: application/json { "rows": [ { "user_id": 1, "foo": 100, "bar": 200 } ] } ログの発生から結果に反映されるまで数秒程度。 結果のレスポンス時間は平均数ミリ秒 ~ 数十ミリ秒程度。
  • 4. What is Zero ? COUNT(*) イベントの件数 SUM(…) 合計
  • 5. What is Zero ? MAX(…) 最大値 MIN(…) 最小値
  • 6. What is Zero ? LATEST(…) 最新値 LATEST_N(…,n) 最新のn件 LATEST_SET_N(…,n) 最新のn件(重複を除く)
  • 7. What is Zero ? WHERE ` .name == "jackson-jq" and .language == "java" and .url == "https://github.com/eiiches/jackson-jq" ` ● JSON形式のイベント(ログ)処理のためにjqに対応 SELECT SUM(`if .action == "click" then 100 else 1 end`) AS score ライブラリ(Java)としてjackson-jqを開発 GROUP BY `{ user_id: .user_id, ad_id: .ads[].id }`
  • 8. 利用例 ● 広告配信システム @ MDH ○ 実績値のリアルタイムレポート (sum/count) ○ フリクエンシーキャップ & リターゲティング (sum/count) ○ オンライン予測に用いる素性 (sum/count/latest) ● その他、各種サービスで利用中 ○ レコメンド、プッシュ通知等での配信制御 (sum/count/latest/latest_set_n) ○ リアルタイムレポート (sum/count) 本番環境では計70弱のクエリの登録がありました
  • 9. Architecture Monoid Storage (Apache HBase, Amazon DynamoDB, ...) Cache (Redis)Dedup (Redis) SELECT COUNT(*) AS total, SUM(`if .type == "click" then 1 else 0 end`) AS click, LATEST_N(`.url`, 3) AS urls FROM flume(`.datetime`) DISTINCT ON `.uuid` FOR 10m WHERE `headers.service = "foo"` GROUP BY `{ user_id: .user_id }` ApacheZookeeper ServiceDiscovery Configuration Event Processor Query Server Event (JSON) Apache Flume, HTTP, ... Result (JSON) Event ProcessorとQuery Serverの中身は同一 SpringBoot (Java) で実装
  • 10. 前提 ● イベントは重複して届くことがある (at least once) ● イベントが届く順序は保証されない ● 一定時間内に到着した同一のイベントを除外する ● Redisに処理したイベントIDを記録しておく(厳密ではない) ● どのような順序で到着しても問題ないように処理する ● 可換モノイドとしてデータ構造と処理を抽象化
  • 11. モノイド ● 条件を満たす「値」と「二項演算」の組み合わせ ○ 結合則: a + (b + c) = (a + b) + c ○ 単位元: a + e = e + a = a 「交換則: a + b = b + a」を追加すると 「可換」モノイドに。 (int, +) (int, ×) (int, max) (int, min) (int, ÷)
  • 12. モノイド (Pair<Time, T>, newer) (List<Pair<Time, T>>, newer_n) (List<Pair<Time, T>>, newer_set_n) プリミティブ型に限らず、定義できる
  • 13. Event Processor 1. イベントを受信 SUM(`.quantity`) { "action": "buy", "quantity": 10, "user_id": "sato" } 2. モノイドに変換 4. 書き込みキューにいれる Apache HBase 5. ストレージに書く Increment Put CheckAndPut Amazon DynamoDB UpdateItem Redis Redis Redis 6. キャッシュを無効化 Redis Redis Redis 3. 重複チェック +10 +5
  • 14. 書き込みキュー ● 条件を満たすまでtake()出来ない ○ 最大サイズ(設定値)の90%以上のキュー長になった場合 ○ または、put()されてから、最小滞在時間(設定値)経過した場合 ● put()時に、キーが重複する場合にモノイドが(+)される A imp: 1 put() take() 最大サイズ(設定値) ☠ B click: 3, imp: 9 A click: 1, imp: 2 B click: 3, imp: 9 初期の実装: 「1秒貯めてから書き込み」or「貯めずに直接書き込み」 → 貯めて書いての繰り返しなので負荷が安定しない
  • 15. Query Server 1. リクエストを受信 3. ストレージから読み込み Get Scan Query 2. キャッシュに問い合わせ (ネガティブキャッシュあり) Apache HBase Amazon DynamoDB Redis Redis Redis { "user_id": "sato" } Rate Limiter Request Coalescing 503 Service Unavailable Circuit Breaker
  • 16. Rate Limiting ● クエリ毎に「同時リクエスト数」が一定を超えた場合に503を返却 ○ 障害時の影響範囲を限定。 ○ クライアント側は“必要に応じて”リトライ ■ 指数バックオフ + ジッタ推奨 ● クエリ毎に「秒間リクエスト数」が一定を超えた場合に503を返却 ○ 障害時に一時的に設定する、などを想定。平常時は設定していない。 ☠ 例えば、HBaseのサーバーダウンなど一部の障害が、本来関係のな いサービスに影響することをを防ぎます。 ☠ 後からだと503を返して問題ないか確認が必要なので、最初からいれておいたほうが良いです。 ・・・まだ対応が終わっていない箇所が・・・
  • 17. Request Coalescing ● ストレージへの同一のREADリクエストは束ねる Storage READ 10 READ 10 READ 10{id: 10} {id: 10} wait Request Coalescing ほぼ同一のリクエスト ☠ 例えば、リクエスト元にキャッシュがあり、そのキャッシュがexpireした場 合に、実装次第で同一のリクエストが届く。 また、レスポンス時間が伸びるほど問い合わせが来る(悪循環) ※ thundering herd もしくは cache stampede として知られています。
  • 18. キャッシュ ● Redisは速いが、1台では限界がある => Consistent Hashingで分散 ○ ノードの追加・削除時、キャッシュの再配置をなるべく避ける。 Node 1 Node 2 Node 3 0 Key B Key A Key C 事前にNodeのハッシュ値を計算しておく。 1. Keyのハッシュ値を計算。 2. (反)時計回りにNodeを探す。 ハッシュ値域 [0, 256) ☠ ※ 実際には、割り当ての偏りを少なくするために、仮想Nodeを使います。 最初は1台でしたが、負荷が上がっ て急いで対応しました><
  • 19. キャッシュ (オートスケーリング) ● キャッシュサーバーもオートスケーリングしたい! ○ => キャッシュノード自身が Zookeeperに自分を登録 ○ ZBeacon ■ Zookeeperにエフェメラルノードを書くだけの小さなデーモン( Goで150行程度) ■ キャッシュノードで常駐させておく ○ Redisは1コアしか使用できないので、複数プロセス立ち上げる zbeacon -hosts zk01.example.com,zk02.example.com,zk03.example.com -path /zero/cache-servers/`hostname -f`:6379 -data `hostname -f`:6379 ☠ 以前は小さなインスタンスをたくさん並べていたので、 IPアド レスを無駄に消費してしまい・・・
  • 20. キャッシュ (エラー処理) ● エラーの場合はキャッシュミス同様、ストレージから読み込み ○ タイムアウトは100msで設定。 ○ キャッシュ読み込みは継続し、 read()自体は1000msでタイムアウト。 ● キャッシュノード毎にCircuitBreaker処理 ○ キャッシュへの同時リクエスト数が一定以上になった場合は最初から弾く。 ☠ 当初は setSoTimeout() していたが、ライブラリがエラーになったコネクションを再利用しない ため、後続のリクエストで瞬間的に再接続が頻発して不安定に・・・
  • 21. 運用 ● 現在3クラスタ: プライベートクラウド / AWS (HBase用、DynamoDB用) ● AWS環境 ○ オートスケーリングを活用 ○ デプロイは独自ツール (Git-versioned Red-black Deployment) ■ ELB以外のリソース(ASG, LC, etc.)は毎回新規作成 ○ アプリに特化したAMIは作っていない(共通AMIにdocker追加) ■ インスタンス起動時に ECRのイメージをdocker run ■ --security-opt seccomp=unconfined --network=host --iptables=false ● ほぼCPUオーバーヘッドなし (conntrack, seccomp, etc.) ● プライベートクラウド環境 ○ Query Server : docker-compose, kubernetes ○ Event Processor : docker-compose ○ Redis Cache / Dedup : ansible ※ zk, redisは共用
  • 22. 監視 ● InfluxDB + Grafana alerting ○ Dropwizard Metricsでアプリケーションメトリクスを JMXで公開 ○ Javaエージェントでほぼ全ての JMXメトリクスをまとめて InfluxDBに10秒おきに送信 ■ https://github.com/eiiches/java-influxdb-metrics-agent ● Zabbix ○ 自動登録機能 + シャットダウン時にホスト無効化、でオートスケーリングに対応 ○ 基本的なインスタンスの監視 ■ ディスク容量, etc. ○ Redis (cache, dedup) の監視 ○ APIの死活監視 これはGrafana移行予定
  • 23. Apache HBase Hadoop上の分散NoSQL Column Family 1 Column Family 2 ... A B A B C ... aaaa 7 5 23 bbbb 3 11 29 ... zzzz 17 13 1 19 ... 昇順 新 旧 Region Region Server 1 Region Server 2
  • 24. HBase Storage ● スキーマ設計 ○ 後から変えるのはしんどい。 ○ 理由がない限り、行キーの先頭にはハッシュ値 (1,2byte)を付ける。 ■ 負荷が偏ると運用が厳しい。事前にハッシュ値境界で分割 (split)しておく。 ● CheckAndPut操作 ○ リトライするときは指数バックオフだけでなくジッタもいれる。 ○ 同じサーバーからは同じ行への変更が同時にされないようにロックを掛ける。 ● ASYNC_WAL (WAL = Write-Ahead Log) ○ 障害時にごく短時間の書き込みロストが許容できる場合は有効に。
  • 25. Tuning Apache HBase ● -XX:+UseG1GC ○ CMS等に比べてYouAreDeadExceptionで死ぬ頻度を減らせる。 ● RegionServer Group based Assignment ○ 本来はHBase 2(未リリース)の機能。一部のディストリビューションで使える。 ○ 「このテーブルはこのサーバーに配置したい」を指定できる。 ■ 障害時の影響範囲を限定するのに有効。 ● CallQueueの分割 (write/read/scan) ○ 「書き込みの負荷が読み込みに影響する」を防止できる。 ● hbase.assignment.zkevent.workers = 1 ○ HMasterがデッドロックするバグの回避。 ● hbase.ipc.server.reservoir.enabled = false ○ バッファの確保サイズは大きくなる一方なのである時死ぬバグの回避。
  • 26. Patching Apache HBase ● [HBASE-14460] スレッドの競合でread-modify-writeが遅くなる ○ HBaseチームでパッチ作成 (HBASE-14460のパッチとは別) ○ Fix: 忘れました ● [HBASE-17072] ThreadLocal内のハッシュテーブルで負荷高騰 ○ ハッシュテーブルの primary clustering ○ 不要なキャッシュロジックをごっそり削除(乱暴) ○ Fix: 2.0.0, 1.4.0, 0.98.24, cdh5.10.0 ● [HBASE-18042,...] Scannerをサーバー側で早期クローズ ○ 何故かScannerが大量に残ってFullGCで死ぬことがあり、そもそも早期クローズで回避。 ○ branch-1.3のコミットをバックポート ○ Fix: 1.3.2
  • 27. まとめ ● ストリーム処理エンジン「Zero」の紹介 ○ == 手軽にリアルタイムにデータを活用できる汎用的な仕組み ○ jqを組み合わせたSQLライクなクエリ言語 ○ モノイドによる処理の抽象化 ● 安定性向上のための工夫の紹介 ○ 他のシステムでもある程度一般的に適用できるはず (?) ● デプロイ・監視などの運用の紹介 ● 今後の開発予定 ○ Apache Phoenix / Redis / Apache Kafka / Amazon Kinesis ○ 集約関数追加 / Join機能(?)