Data Engineering
at VOYAGE GROUP
JAWS DAYS 2015
2015/03/22
@suzu_v
自己紹介
• 鈴木健太、すずけん、@suzu_v
• http://suzuken.hatenablog.jp/
• ソフトウェアエンジニア
• アドテクノロジー事業(SSP, DMP)に従事
https://www.facebook.com/voyagegroup/photos/a.365470036810049.90562.176439939046394/752116391478743/?type=3&permPage=1
データエンジニアリング
• 日々増え続けるデータをビジネスに活かし、ユーザ
に恩恵を届けるためには、信頼性の高いデータの保
持、処理、そしてクエリ可能な状態をつくる必要が
ある。そのために、スケーラブルで信頼性の高いデー
タ基盤をつくり、データのパイプラインを組み立て
るエンジニアリングのこと
私達とAWS
• 2009年から利用開始
• 2011年からアドテクノロジー領域でも利用を開始
• 今日はアドテクノロジー領域でのAWS利用につい
てお話します
ディスプレイ広告
広告リクエスト
ブラウザ アドサーバ
そのときどきで良さそうな
広告を選んで
ブラウザ アドサーバ
広告
広告
広告
広告を表示する
ブラウザ アドサーバ
広告
広告
広告
ex. 行動ターゲティング基盤
アーキテクチャ
行動ターゲティングの課題
• なるべく速く書き込みたい。ユーザが何かをみたら、
すぐにターゲティング可能な状態にしてほしい。反
映が速ければ速いほどいい。
• 案件や対象ユーザが増えても、システム全体が問題
なくスケールすること
• 読み込みが安定して低レイテンシであること。でき
れば5ms以内。
Targeting
Infrastructure
ELB
EC2
EC2 EC2
EC2
request
EC2
S3
DynamoDB
EMR ELB
EC2
EC2 EC2
EC2
http api
fluentd
fluentd
(aggregator)
out_exec_filter
out_dynamodb servlet (scala)
dynamic-dynamo
EC2
Growth
Forecast
EC2
EC2
VPC 1
VPC 1
VPC 2
(targeting)
VPC Peering
VPC Peering
ephemeral
cluster
ELB
EC2
EC2 EC2
EC2
request
EC2
S3
DynamoDB
EMR ELB
EC2
EC2 EC2
EC2
http api
fluentd
fluentd
(aggregator)
out_exec_filter
out_dynamodb servlet (scala)
dynamic-dynamo
EC2
Growth
Forecast
EC2
EC2
VPC 1
VPC 1
VPC 2
(targeting)
VPC Peering
VPC Peering
ephemeral
cluster
配信用VPC
ターゲティング
基盤VPC
ELB
EC2
EC2 EC2
EC2
request
EC2
S3
DynamoDB
EMR ELB
EC2
EC2 EC2
EC2
http api
fluentd
fluentd
(aggregator)
out_exec_filter
out_dynamodb servlet (scala)
dynamic-dynamo
EC2
Growth
Forecast
EC2
EC2
VPC 1
VPC 1
VPC 2
(targeting)
VPC Peering
VPC Peering
ephemeral
cluster
Fluentdの
forwardで連携
ELB
EC2
EC2 EC2
EC2
request
EC2
S3
DynamoDB
EMR ELB
EC2
EC2 EC2
EC2
http api
fluentd
fluentd
(aggregator)
out_exec_filter
out_dynamodb servlet (scala)
dynamic-dynamo
EC2
Growth
Forecast
EC2
EC2
VPC 1
VPC 1
VPC 2
(targeting)
VPC Peering
VPC Peering
ephemeral
cluster
Event Streamノード
c3.xlarge複数台
td-agent2
ELB
EC2
EC2 EC2
EC2
request
EC2
S3
DynamoDB
EMR ELB
EC2
EC2 EC2
EC2
http api
fluentd
fluentd
(aggregator)
out_exec_filter
out_dynamodb servlet (scala)
dynamic-dynamo
EC2
Growth
Forecast
EC2
EC2
VPC 1
VPC 1
VPC 2
(targeting)
VPC Peering
VPC Peering
ephemeral
cluster
out_exec_filterでログを加工
DynamoDBに書き込み
ELB
EC2
EC2 EC2
EC2
request
EC2
S3
DynamoDB
EMR ELB
EC2
EC2 EC2
EC2
http api
fluentd
fluentd
(aggregator)
out_exec_filter
out_dynamodb servlet (scala)
dynamic-dynamo
EC2
Growth
Forecast
EC2
EC2
VPC 1
VPC 1
VPC 2
(targeting)
VPC Peering
VPC Peering
ephemeral
cluster
ユーザのセグメント情報を書き込み
全てのログ
http://www.slideshare.net/repeatedly/fluentd-unified-logging-layer-at-fossasia
http://www.slideshare.net/repeatedly/fluentd-unified-logging-layer-at-fossasia
シンプルなストリーム処理
in_forwardで受け入れたレコード
out_exec_filterで加工
{id: "hoge", segment: "seg1", created: 1426406962, ...}
DynamoDBテーブルへ
{id: "hoge", url: "http://fuga.com/kuke", user_agent: ..}
{id: "hoge", url: "http://hoge.com/a", user_agent: ..}
if (domain(url) == "fuga.com") seg = "seg1"
<match hoge.log>
type exec_filter
command ./our/special/filter/command
buffer_type file
buffer_path /path/to/ephemeral/disk/hoge
</match>
!
<match filtered.hoge.log>
type dynamodb
dynamo_db_table our_targeting_table
buffer_type file
buffer_path /path/to/ephemeral/disk/filtered
...
<secondary>
type s3
s3_bucket your-bucket
s3_region ap-northeast-1
s3_object_key_format ...
buffer_type file
buffer_path /path/to/ephemeral/disk/filtered.secondary
...
</secondary>
</match>
in_forwardでおくられてきた
ログをうけとり、フィルターする
filterしたログをDynamoDBに書き込む
batchWriteItemを利用
もし書き込みが失敗したらs3へ
書ききれてませんが、s3への転送もしてます
<match hoge.log>
type exec_filter
command ./our/special/filter/command
buffer_type file
buffer_path /path/to/ephemeral/disk/hoge
</match>
!
<match filtered.hoge.log>
type dynamodb
dynamo_db_table our_targeting_table
buffer_type file
buffer_path /path/to/ephemeral/disk/filtered
...
<secondary>
type s3
s3_bucket your-bucket
s3_region ap-northeast-1
s3_object_key_format ...
buffer_type file
buffer_path /path/to/ephemeral/disk/filtered.secondary
...
</secondary>
</match>
バッファは全てファイル
ephemeral diskに
EventStreamノードの運用
• ノードを作り直す場合にはforward側からフェイルしたノー
ドを外し、全ての転送が終わったら落とす
• Output先を詰まらせないこと。fluentdにバッファをなる
べく貯めないことが望ましい。定常的にバッファが貯まる
ようなら改善が必要。
• バッファがたまってしまった場合は原因を特定して詰まり
を解消した上で、強制的にflush
• $ pkill -USR1 -f fluentd
ストリーム処理における状態
プロセッサ
データ
ストリーム処理における状態
プロセッサ
id: 1
k: 2
データ
あるidがk: 1を満たしていたら通したい
ストリーム処理における状態
プロセッサ
id: 1
k: 2
データ
NG
あるidがk: 1を満たしていたら通したい
ストリーム処理における状態
プロセッサ
データ
あるidがk: 1を満たしていたら通したい
ストリーム処理における状態
プロセッサ
データ
id: 1
k: 1
あるidがk: 1を満たしていたら通したい
ストリーム処理における状態
プロセッサ
データ
id: 1
k: 1 OK!
あるidがk: 1を満たしていたら通したい
ストリーム処理における状態
プロセッサ
データ
id: 1
k: 1
プロセッサにとどまる
時間は限りなく短い
あるidがk: 1を満たしていたら通したい
留めるデータが増えるケース
プロセッサ
id: 1
k: 2
データ
あるidがk: 1とk: 2両方を満たしていたら通したい
プロセッサ
id: 1
k: 2
データ stay
あるidがk: 1とk: 2両方を満たしていたら通したい
留めるデータが増えるケース
プロセッサ
id: 1
k: 3
id: 1
k: 2
id: 1
k: 1
データ 条件がくるまで
滞留させる必要がある
あるidがk: 1とk: 2両方を満たしていたら通したい
留めるデータが増えるケース
プロセッサ
id: 1
v: ok
データ
条件をみたしたのでOK
あるidがk: 1とk: 2両方を満たしていたら通したい
留めるデータが増えるケース
ストリーム処理における状態
プロセッサ
id: 1
k: 3
id: 1
k: 2
id: 1
k: 1
データ 条件がくるまで
滞留させる必要がある
対象とする時間の幅(window)が長くなれば
なるほど多くのデータをストリーム処理可能
な場所に保持する必要がある。データの流量
が増えるとそれだけ多くのリソース(RAM
等)が必要になる。
あるidがk: 1とk: 2両方を満たしていたら通したい
行動ターゲティングの課題
(再掲)
• なるべく速く書き込みたい。ユーザが何かをみたら、
すぐにターゲティング可能な状態にしてほしい。反
映が速ければ速いほどいい。
• 案件や対象ユーザが増えても、システム全体が問題
なくスケールすること
• 読み込みが安定して低レイテンシであること。でき
れば5ms以内。
いろいろ試した結果
• シンプルなmap処理のみリアルタイムに
• (30日前にページAをみた and さっきページBをみ
た)というセグメントにも対応しなければいけなかっ
た・・。のでバッチも併用することに。
• 結果横に並べればシンプルなmap処理についてはス
ケールする構成になったので良かった
ELB
EC2
EC2 EC2
EC2
request
EC2
S3
DynamoDB
EMR ELB
EC2
EC2 EC2
EC2
http api
fluentd
fluentd
(aggregator)
out_exec_filter
out_dynamodb servlet (scala)
dynamic-dynamo
EC2
Growth
Forecast
EC2
EC2
VPC 1
VPC 1
VPC 2
(targeting)
VPC Peering
VPC Peering
ephemeral
cluster
EMRでDynamoDBとS3からデータ抽出
再集計してDynamoDBへ書き込み
EMR / Hive
• Amazon Hadoop 2.4.0, Hive 0.13.1, core: m1.xlarge * 30,
task: c3かr3系統をspot instanceで。専用のSecurity Group
を用意。基本的にRCFileで扱う。
• 200クエリ / 日。1日1クラスタ立ち上げて、ひたすらそこに投
げている。DynamoDBとs3からデータを読み込み、集計し、s3
に書き出している。使うHiveクエリは管理ツールから自動生成
or リポジトリにコミットしてJenkinsからs3に上げている。
• アドホックに使う場合には都度別クラスタを立ち上げている。
分析者も手元からThrift経由で。
SET dynamodb.throughput.read.percent=0.8;
!
CREATE EXTERNAL TABLE IF NOT EXISTS users (
id string,
seg string,
created bigint
)
stored as rcfile
location 's3://path/to/my/user/table';
!
CREATE EXTERNAL TABLE if not exists
users_from_dynamodb (
id string,
seg string,
created bigint)
STORED BY
'org.apache.hadoop.hive.dynamodb.DynamoDBStorageHandler'
TBLPROPERTIES (
"hive.jdbc.update.on.duplicate" = "true",
"dynamodb.table.name" = "our_special_user_table_name",
"dynamodb.column.mapping" = "id:id,seg:seg,created:created");
!
INSERT OVERWRITE TABLE users SELECT * FROM users_from_dynamodb;
DynamoDBのthroughputをどれくらい使うか
DynamoDBカラムとHiveテーブルの
カラム対応関係
DynamoDBから全データを
抽出してs3に書き込み
EMRの利点と課題
• 利点
• Hadoopのバージョンアップなど、EMR側がやってくれるので楽
• 潰して、立ち上げなおして、が簡単にできる
• bootstrapを工夫すれば様々なHadoop関連ミドルウェアを手軽に試せる
• https://github.com/awslabs/emr-bootstrap-actions
• 課題
• クラスタ立ち上げは時間がかかる
• ジョブスケジューリングは自前で頑張る必要あり
• EMRコマンドのデバッグには極論EMRを立ち上げるしか無い
TODO
このへんで水を飲む
行動ターゲティングの課題
(再掲)
• なるべく速く書き込みたい。ユーザが何かをみたら、
すぐにターゲティング可能な状態にしてほしい。反
映が速ければ速いほどいい。
• 案件や対象ユーザが増えても、システム全体が問題
なくスケールすること
• 読み込みが安定して低レイテンシであること。でき
れば5ms以内。
DynamoDB、最高です
• ご存知フルマネージドNoSQL DB on AWS
• 2年半ほど継続して利用。AWSを使っていて最も選
んでよかったと思っているデータストア。
• 30億レコード入っている。1リクエスト3msで返る。
しかも1度もダウンしたことがない。
「DynamoDBからの読み込
み遅いんですけど・・・」
「(;・ ・)?」
ELB
EC2
EC2 EC2
EC2
request
EC2
S3
DynamoDB
EMR ELB
EC2
EC2 EC2
EC2
http api
fluentd
fluentd
(aggregator)
out_exec_filter
out_dynamodb servlet (scala)
dynamic-dynamo
EC2
Growth
Forecast
EC2
EC2
VPC 1
VPC 1
VPC 2
(targeting)
VPC Peering
VPC Peering
ephemeral
cluster
配信サーバからセグメントデータを読み込み
apache (prefork) + PHP
apacherequest DynamoDB
apache (prefork) + PHP
apacherequest
Process
DynamoDB
apache (prefork) + PHP
apacherequest
Process
DynamoDB
新規コネクション
( 10ms)
apache (prefork) + PHP
apacherequest
Process
DynamoDB
GetItem
apache (prefork) + PHP
apache
Process
DynamoDB
response
apache (prefork) + PHP
apache DynamoDB
response
apache (prefork) + PHP
apache DynamoDB
response
リクエストからレスポンスまで
30ms
秒間リクエスト数が増えた時
apache DynamoDB
秒間リクエスト数が増えた時
apache
request
Process
DynamoDB
requestrequestrequestrequestrequestrequestrequestrequestrequestrequestrequestrequest
Process
Process
Process
待ちプロセスが増える
= LAが上がる
• PHP製のapiをScalaで再実装。Servletを利用。
• DynamoDBへのコネクションをプールするように
• responseが早くなり、同時接続数が増えすぎるこ
となく、安定して稼働
fluentd「DynamoDB
つまって書けないんで
すけど」
私「( ゚д゚)」
ELB
EC2
EC2 EC2
EC2
request
EC2
S3
DynamoDB
EMR ELB
EC2
EC2 EC2
EC2
http api
fluentd
fluentd
(aggregator)
out_exec_filter
out_dynamodb servlet (scala)
dynamic-dynamo
EC2
Growth
Forecast
EC2
EC2
VPC 1
VPC 1
VPC 2
(targeting)
VPC Peering
VPC Peering
ephemeral
cluster
out_exec_filterでログを加工
DynamoDBに書き込み
書き込む量が増えてWrite capacityが
足りなくなった!
• 勝手にスケールするようにしよう!ということで
dynamic-dynamodbの導入
結果
Write
Capacity
Read
Capacity
Query
Latency
テーブル設計イメージ
user_id
String
(hash key)
segment
String
(range key)
created
Number
…
hoge seg1 1426406962
hoge seg2 1426406962
fuga seg1 1426406962
kuke seg1 1426406962
DynamoDB Tips
• 1Itemあたりのバイト数を小さくする(1KBを超え
ないように
• hot keyを作らないようにする(hash keyに同じID
が大量に存在する状態にしないようにする
• DynamoDB - EC2の新規コネクションはそれなり
にコストが高い( 10ms)ので、コネクションを
プールする(つながれば安定して速い
参考: http://www.slideshare.net/AmazonWebServicesJapan/aws-black-belt-tech-amazon-dynamodb
若手解析者「すずけんさん、Hive遅
いんすけど何とかならないっすか?」
私「(́・ω・`)」
アドホックな
データ分析
部分的にBigQueryを利用
• EC2 -> S3 -> SQS -> EC2(worker) -> GCS
• アドホックな分析用はこちらに移行中
https://cloud.google.com/bigquery/?hl=ja
BigQuery
• いいところ
• クラスタのメンテしなくていい。(Hadoopクラス
タの面倒見なくていいし)。速い。コンソールも
最初からついてる。Google Appsと連携できる。
• 使いづらい所
• 権限周り。まだAWSと比べて細かい制御が難しそ
う。UDFが(まだ)使えない。
現状の使い分け
• Large Batch: EMR + Hive
• Short Batch: BigQuery
• Stream Processing: Fluentd + out_exec_filter
参考: http://www.slideshare.net/tagomoris/hcj2014-sql
データと組織
プロダクトオーナーシップ
• インフラも、データも、サービスも、営業も
• 「このデータを取れるようにしたいだけど?」に対
して、全方面に答えられる必要がある。ログに10
バイト情報を増やすだけで、10バイト 250億だ
け月に扱う量が増える。帯域、ディスク、関連する
コストが増える。それらに見合うだけの価値があと
から出せるのかを考える必要がある。
–Amazon’s Leadership PrinciplesのOwnershipより
リーダーにはオーナーシップが必要です。リー
ダーは長期的な視野で考え、短期的な結果のた
めに、長期的な価値を犠牲にしません。リーダー
は自分のチームだけでなく、会社全体のために
行動します。リーダーは「それは私の仕事では
ありません」とは決して口にしません。
cf. Amazon
• Amazon Kinesis
Developer Managerの
Goさんの話
• AmazonのLeadership
PrinciplesのOwnership
について
• インフラチームもサービ
スチームもOwnershipを
ビジネス的な改善の重視
• VOYAGE GROUPのエンジニアは技術的なレビュー
を受ける。人事評価も影響する。
• 現場のエンジニアでもプロダクトの数値を「見え
る」ようにすることを意識させられる。
• データをうまく扱う環境をつくること -> ビジネス
を改善すること
参考: http://gihyo.jp/design/serial/01/creative/0006
まとめ
普通のことを普通にやる
• パフォーマンスも、運用も、コストも。データの配
置も、必要なところだけ、必要なことを。データや
トラフィックが増えても、普通のことを普通にやる。
エンジニア採用中です!
https://voyagegroup.com/adtechunit/

Data Engineering at VOYAGE GROUP #jawsdays