Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
広告配信システムでのトラフィック計測と実装方法 #ScalaAkiMatsuri
Search
Kurochan
September 16, 2019
Technology
1
6.9k
広告配信システムでのトラフィック計測と実装方法 #ScalaAkiMatsuri
Scala秋祭りで発表した資料です
Kurochan
September 16, 2019
Tweet
Share
More Decks by Kurochan
See All by Kurochan
入門 電気通信事業者
kurochan
12
5.2k
AWS x さくらのクラウドのハイブリッドクラウドによる安価なフレッツ閉域網接続の実装
kurochan
9
5.1k
GoでTCP Proxyを実装してみよう
kurochan
1
840
サイバーエージェントの広告配信におけるIPoEトラフィックの概況
kurochan
0
390
スケールするというのはどういうことなのか
kurochan
14
4.5k
サイバーエージェントのGitHub Copilot導入と 開発生産性
kurochan
45
42k
Cloudflare Zero Trustを利用したセキュアな開発環境へのアクセス手法の確立
kurochan
10
3.1k
セキュキャンを卒業してその後
kurochan
0
1.3k
サイバーエージェントの実践×実験Snowflake 導入の経緯から最新機能のトライアルまで / How Snowflake Is Used In CyberAgent - Go To the Future
kurochan
1
1k
Other Decks in Technology
See All in Technology
ノーコードデータ分析ツールで体験する時系列データ分析超入門
negi111111
0
410
Amazon Personalizeのレコメンドシステム構築、実際何するの?〜大体10分で具体的なイメージをつかむ〜
kniino
1
100
OCI Security サービス 概要
oracle4engineer
PRO
0
6.5k
オープンソースAIとは何か? --「オープンソースAIの定義 v1.0」詳細解説
shujisado
7
810
開発生産性を上げながらビジネスも30倍成長させてきたチームの姿
kamina_zzz
2
1.7k
Exadata Database Service on Dedicated Infrastructure(ExaDB-D) UI スクリーン・キャプチャ集
oracle4engineer
PRO
2
3.2k
SSMRunbook作成の勘所_20241120
koichiotomo
2
130
ハイパーパラメータチューニングって何をしているの
toridori_dev
0
140
Oracle Cloud Infrastructureデータベース・クラウド:各バージョンのサポート期間
oracle4engineer
PRO
28
12k
Making your applications cross-environment - OSCG 2024 NA
salaboy
0
190
【令和最新版】AWS Direct Connectと愉快なGWたちのおさらい
minorun365
PRO
5
750
B2B SaaSから見た最近のC#/.NETの進化
sansantech
PRO
0
750
Featured
See All Featured
Done Done
chrislema
181
16k
Designing the Hi-DPI Web
ddemaree
280
34k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
29k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
229
52k
Thoughts on Productivity
jonyablonski
67
4.3k
Rails Girls Zürich Keynote
gr2m
94
13k
Fashionably flexible responsive web design (full day workshop)
malarkey
405
65k
How to Think Like a Performance Engineer
csswizardry
20
1.1k
Building Adaptive Systems
keathley
38
2.3k
Git: the NoSQL Database
bkeepers
PRO
427
64k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
93
16k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
169
50k
Transcript
広告配信システムでのトラフィック計測と 実装⽅法 #ScalaAkiMatsuri 株式会社サイバーエージェント AI事業本部 黒崎 優太 (@kuro_m )
黒崎 優太 • Dynalyst 開発責任者 • 業務は Scala + AWS
• イラスト図解でよくわかる ITインフラの基礎知識 書きました • AWSのAZ(アベイラビリティーゾーン)とは?AZ障 害が起きたときどうすればよいのか 最近ちょっとバズりました @kuro_m @kurochan
Scala Matsuri • Wi-Fiを担当しました • かなり好評だったようでよかったです • ネットワークの⼀部にScalaを導⼊ • 発表
https://speakerdeck.com/kurochan/wi-fi-x-scala-implementing-captive-portal-in-scala-and- deploy-into-number-scalamatsuri
最近事業部名がかわりました • アドテク本部 → AI事業本部
インターネット広告
RTBのしくみ • RTB = Real Time Bidding 441 %41T
RTBのしくみ • Webページがロードされ、広告タグが発⽕ 441 %41T
RTBのしくみ • 枠情報やユーザ情報とともにbid requestがくる 441 %41T CJESFRVFTU
RTBのしくみ • ⼊札額と表⽰する広告を決定 441 %41T "% "% "% CJESFRVFTU ԁ
ԁ ԁ
RTBのしくみ • Open RTBというプロトコルで⼊札 441 %41T "% "% "% ԁ
ԁ ԁ
RTBのしくみ • ⼊札額が⼀番⾼い事業者が勝利する 441 %41T "% "% "% ԁ ԁ
ԁ XJO
RTBのしくみ • SSPに広告クリエイティブが送られる 441 %41T "% "% "% ԁ ԁ
ԁ "% XJO
RTBのしくみ • SSP経由で落札した事業者の広告が展開される 441 %41T "% "% "% ԁ ԁ
ԁ "% XJO "%
RTBのしくみ • これを⾼速に繰り返す 441 %41T "% "% "% ԁ ԁ
ԁ "% XJO "% औҾNTҎʹྃ͠ͳ͚ΕͳΒͳ͍
Dynalystとは • Dynamic Retargeting for Games スマホ向けリターゲティング広告配信プラットフォーム トップセールス @⽇本のスマホゲームの中でも⾼いシェア ⽇本、アメリカを含む7カ国に配信中
ユーザごとに最適化した広告を配信 IUUQXXXEZOBMZTUJP
開発している広告システム概況 • ⼊札リクエスト量: 数⼗万リクエスト / 秒 • ⼊札トラフィック: 約8Gbps •
レスポンスタイム: 100ms以内 • ログの量: 数TB / Day(圧縮状態) ຊͷೖࡳϦΫΤετඵ ຊΞϝϦΧͷϨεϙϯελΠϜ NTFD https://logmi.jp/tech/articles/
最近⾒ていて楽しい画⾯ • オートスケーリング系のメトリクス
Contents • 計測サーバの実装 計測の種類 Akka HTTPを利⽤した計測サーバの実装 • 計測パラメータの引き回し 広告で起こる困ったこと パラメータの引き回しを楽にする⼯夫
• ログの転送‧集計 Amazon Kinesisを活⽤した⾃作ログ転送システム Amazon EMRを活⽤した集計システム
計測サーバの実装
計測の種類
計測の種類 • 広告の表⽰の計測 • 広告のクリックの計測/遷移 • Dynalystはリターゲティング広告配信システムのため外部の計測ツール経由 でユーザの情報を同期しないといけない • 例:
ユーザがある広告主のゲームをインストールした、ログインした、課⾦した
Akka HTTPを⽤いた計測サーバの 実装
Akka HTTP • HTTPサーバのフレームワーク • Akka Streamsで実装されている • HTTPで受けたリクエストからパラメータをパースしてファイルに吐き出すの が基本
• 特に変わった使い⽅はしていません • Dynalystではもともとsprayを使っていたのでAkka HTTPに移⾏しました
Akka HTTPの実装例 https://doc.akka.io/docs/akka-http/current/introduction.html
外部計測ツールとの連携 "% DMJDL ֎෦ܭଌπʔϧ
外部計測ツールとの連携 DMJDLαʔό "% DMJDL ֎෦ܭଌπʔϧ
外部計測ツールとの連携 DMJDLαʔό "% DMJDL ֎෦ܭଌπʔϧ DMJDL௨
外部計測ツールとの連携 DMJDLαʔό "% DMJDL ֎෦ܭଌπʔϧ DMJDL௨ 0,
外部計測ツールとの連携 DMJDLαʔό "% DMJDL ֎෦ܭଌπʔϧ SFEJSFDU DMJDL௨ 0,
外部計測ツールとの連携 DMJDLαʔό "% ֎෦ܭଌπʔϧʹ௨͔ͯ͠ΒϦμΠϨΫτ͢Δ DMJDL ֎෦ܭଌπʔϧ SFEJSFDU DMJDL௨ 0,
外部計測ツールとの連携 • 多くの広告主は外部の計測ツールを使ってインストールや起動を計測している • 広告のクリックを計測ツールに連携すると広告主は複数の広告配信事業者を横断して 成果を⽐較することができるため、Dynalystの広告経由のクリック発⽣時に 計測ツールに通知する必要がある • Akka Http
Clientを使って通知を送信する
DynamoDBへのアクセスを多重化する • AWS SDK for Java . が公開され、nettyベースの実装が追加された • nettyを使うとリクエスト部分がノンブロッキングになる
• Dynalystでは端末情報はDynamoDBに保存しているため、 リクエストの処理の並列度を⾼めるのは重要 • レスポンスがJavaのCompletableFutureで返ってくるので変換が必要 • scala-java -compatを使ってFutureに変換 • CompletableFutureはfail時にExceptionをCompletionExceptionでラップするので注意
計測パラメータの引き回し
計測パラメータの引き回し
計測パラメータとは • レポート作成、分析、外部システム連携のためのパラメータがたくさんあります • トランザクションID • 端末ID • 広告主ID •
キャンペーンID • 通貨レート • ⼊札時の各種予測値(CTR, CVR, CPM等) • 全部で40〜50種類程度
パラメータを引き回さないといけない理由 • ⼊札時のログがあるならばトランザクションIDのみURLパラメータで引き回 して、表⽰計測のログと⼊札時のログで集計時にJOINすればよいのでは? • 理論的にはそう • 実際はログの量が多く、あまりやりたくない… • ⼊札のログ:
1⽇5TBくらい • 広告成果(アプリ起動や課⾦等)について、過去1週間分の⼊札ログと紐付けてレポートを作成 するといったようなユースケースがあるとすぐつらくなる • 集計で必要になるパラメータはURLパラメータを使って表⽰計測サーバまで引き回す
パラメータの引き回しを楽にする ⼯夫
困っていたこと • パラメータ数が多い • パラメータを追加するごとに計測URLを⽣成/パースする部分のテストコードに修正が… • 気軽にA/Bテストしたいので追加するハードルを下げたい • URLが⻑い •
使われなくなったパラメータが残りがち(3ヶ⽉前に⼊札した広告の計測が⾶んできたり, 後⽅互換性…) • 実装上の都合でパラメータ名をわかりやすくしようとするとURLが⻑くなる • 暗号化処理 • 機械学習の予測値等、内部パラメータはひとつひとつ暗号化していた • URLパラメータ改ざんへの耐性 • 不正なリクエストを送って不正に広告収益をあげようとする⼈たちがいる • 改ざん検知のコードのメンテが⾯倒だった
Protocol Buffers • Googleが開発したプログラミング⾔語/プラットフォーム⾮依存のデータシ リアライズ/デシリアライズのフォーマットとその実装 • protoファイルでデータ構造を記述すると各種⾔語向けのクラス定義やシリ アライズ/デシリアライズのコードが⾃動⽣成できる • 後⽅互換性が保ちやすい設計
https://developers.google.com/protocol-buffers/
Scala x Protocol Buffers • コードを⾃動⽣成したかったのでScalaPBを採⽤
Protocol Buffersのシリアライズ • 標準でバイナリに変換することはできる • toByteArray(), parseFrom(bytes: Array[Byte]) • URLパラメータに埋め込みたいのでバイナリはそのまま扱えない
Protocol BuffersをURLパラメータに埋め込む • Base を採⽤ • 他⾔語でも容易に扱えるため • バイナリを毎回Base に変換するコードを書くのは避けたい、
できればあまり意識したくない
Protocol BuffersにScalaPBの拡張を⽤いる • ⽣成されるcase class/objectに⾃作traitを継承させる
Protocol BuffersにScalaPBの拡張を⽤いる ࣗ࡞USBJU
URLを短くしたい • ProtocolBuffersにしただけでも可変⻑変数やURLパラメータ名分短くなる 等、以前よりURLが短くなるような要素はある • ProtocolBuffersのwire formatからすると同じような表現が繰り返されそう なので何かしら圧縮はできそうである • Deflateを採⽤
• 動作が軽めで他⾔語にもライブラリが存在しそうな汎⽤的なアルゴリズム • 前述のtraitにBase に変換する前にDeflateするメソッドを追加(その逆も)
暗号化したい • AES / Cipher Block Chaining / PKCS Padding
• 多くのJVMはIntel CPUのAES-NIが使えるので⼗分な速度で処理が可能 • 前述のtraitにDeflateして暗号化してからBase に変換するメソッドを実装(その逆も) https://ja.wikipedia.org/wiki/ %E % A% %E % F%B %E % %A %E % %A %E % %A %E % %BC%E % %
リプレイ攻撃に対する対処 • AES- はInitialization Vectorに128bit必要 • Base にエンコードすると22⽂字くらい必要 • IVはデコード側にも渡さないといけない
• IVは固定する, 先頭にnonceを⼊れる • URLパラメータでIV分のデータ量を消費せず済む(衝突確率を考慮した上で128bit以下にする) • 前⽅にトランザクションIDが含まれているのでなくても⼤丈夫かもしれない • 例: 現在時刻のミリ秒を16bitで切り捨てて⼊れる
値が⼊っていない状態を表現する • Protocol Buffers(ver )だとoptional/requiredという概念が存在しない • プリミティブ値に値がセットされていない場合はプリミティブのデフォルト 値で埋められる (例: uint
=> ) • google/protobuf/wrappers.proto を使って解決
ログの転送
Amazon Kinesisを活⽤した ⾃作ログ転送システム
ログ転送の仕組み ܭଌαʔό qVFOUE ,JOFTJT ετϦʔϜ ࠓճ࡞ͬͨͷ͜͜ 4 ετϨʔδ
Amazon Kinesis Data Firehose • これでできることとほぼ⼀緒では… https://aws.amazon.com/jp/kinesis/data-firehose/
⾃作したかった理由 • Firehoseは「書き込まれる Amazon S オブジェクトに含まれる最も古いレ コードのおおよその到達タイムスタンプ」を⾒てファイルのアップロード先 パスを決定する • /path/to/
/ / / /に配置されるログには2019/09/15 23:59のログが混ざっている可 能性がある • リカバリ作業等で古いログをストリームに投げても Firehoseは最新の時刻のパーティションにログを配置する • ログのアップロード時刻ではなく、ログ中のタイムスタンプを⾒て パーティショニングがしたい
Akka Streams • Source: メッセージを吐き出すコンポーネント(始点) • Flow: メッセージを受け取ってメッセージを送るコンポーネント • Sink:
メッセージを受け取るコンポーネント(終点)
Akka Streams • それぞれのinとoutの型が⼀致している • Source,Sinkの2番⽬, Flowの3番⽬の型パラメータは省略
Akka Streams https://doc.akka.io/docs/akka/ . . /scala/stream/stream-quickstart.html
処理の流れ • それぞれのinとoutの型が⼀致している • Source,Sinkの2番⽬, Flowの3番⽬の型パラメータは省略
処理の流れ • Kinesisからレコードを取り出す • ログをバッファリングする • (⼀定のサイズ/時間が経過したら)S にレコードをアップロードする • Kinesisのチェックポイントを更新する
• チェックポイント = ストリームをどこまで読み進めたか
Kinesis Client LibraryをSourceとして使う • Kinesis Client Library = KCL •
Kinesisを使ったストリーミング処理が簡単に書けるAmazon公式Javaライブラリ • KCLをAkkaStreamのSourceとして使うことができるライブラリがある • AkkaStreamsのおかげでKinesisのキャパシティを 詰まることなくぴったり使い切れる https://github.com/StreetContxt/kcl-akka-stream
kcl-akka-streamの使い⽅ • 最後にmarkProcessed()を 呼ぶことでKCLのDynamoDBの チェックポイントを更新する • 処理前に呼ぶ: at most once
• 処理後に呼ぶ: at least once
ログをバッファリングするFlowの⾃作
• パーティションごとにLocalのストレージにログをバッファリングする • ファイルにバッファリングさせることでメモリの消費量を抑えたかった • パーティションはログの中⾝のタイムスタンプで決定する • ⼀定容量/⼀定時間経過するとS にPutObjectする •
KinesisRecordを引き回す必要がなければ半分くらいメモリ消費を抑えられ たが… • PutObjectが成功したらアップロードされたオブジェクトのS Pathと関係す るcontextのリストをpushする ログをバッファリングするFlowの⾃作
Amazon EMRを活⽤した 集計システム
Amazon EMR • Apache Spark on Amazon EMR • クラスタコンピューティングフレームワーク
• 分散共有メモリモデル • ノードを増やすことでスケールする • Spark MLibという機械学習ライブラリも &.3$MVTUFS .BTUFS 4MBWF 4MBWF 4MBWF 4MBWF
Apache Sparkで集計を実装する • 例: 広告主 x ⽇時の粒度で クリック数をカウントする 42-Ͱॻ͍ͨ߹ 4QBSLͰॻ͍ͨ߹
いいところ • スケールする • サーバを増やせば… (多い時でCPU Core / Memory TBくらいのクラスタが稼働しています)
• テストコードが書ける • テストコードがないと複雑な集計を実装するのは厳しい • 例: 広告主やSSPの国に応じて外部DBからタイムゾーンを取得し、 通貨単位も変換して集計する • 可⽤性をあまり落とさずにスポットインスタンスを活⽤して 格安でクラスタ運⽤ができる • Sparkのおかげで⼀部のワーカーが落ちても ⾃動でリカバリ & 集計は中断されない https://developers.cyberagent.co.jp/blog/archives/ /
ありがとうございました