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
7.1k
広告配信システムでのトラフィック計測と実装方法 #ScalaAkiMatsuri
Scala秋祭りで発表した資料です
Kurochan
September 16, 2019
Tweet
Share
More Decks by Kurochan
See All by Kurochan
サイバーエージェント流クラウドコスト削減施策「みんなで金塊堀太郎」
kurochan
4
2.2k
AWS Elemental MediaPackageと格闘🤼
kurochan
2
59
サイバーエージェントでのSlack活用事例 @ 2025
kurochan
5
90
15年入社者に聞く! これまでのCAのキャリアとこれから
kurochan
1
280
入門 電気通信事業者
kurochan
13
5.7k
AWS x さくらのクラウドのハイブリッドクラウドによる安価なフレッツ閉域網接続の実装
kurochan
9
5.9k
GoでTCP Proxyを実装してみよう
kurochan
1
1.2k
サイバーエージェントの広告配信におけるIPoEトラフィックの概況
kurochan
0
510
スケールするというのはどういうことなのか
kurochan
14
5k
Other Decks in Technology
See All in Technology
Railsの話をしよう
yahonda
0
170
AI時代におけるデータの重要性 ~データマネジメントの第一歩~
ryoichi_ota
0
710
生成AIを安心して活用するために──「情報セキュリティガイドライン」策定とポイント
gree_tech
PRO
0
230
ヘンリー会社紹介資料(エンジニア向け) / company deck for engineer
henryofficial
0
320
AWS UG Grantでグローバル20名に選出されてre:Inventに行く話と、マルチクラウドセキュリティの教科書を執筆した話 / The Story of Being Selected for the AWS UG Grant to Attending re:Invent, and Writing a Multi-Cloud Security Textbook
yuj1osm
1
120
[OCI Skill Mapping] AWSユーザーのためのOCI – IaaS編(Compute/Storage/Networking) (2025年10月8日開催)
oracle4engineer
PRO
1
180
クラウドとリアルの融合により、製造業はどう変わるのか?〜クラスメソッドの製造業への取組と共に〜
hamadakoji
0
350
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
12
81k
データ戦略部門 紹介資料
sansan33
PRO
1
3.8k
SQLAlchemy の select(User).where(User.id =="123") を理解してみる/sqlalchemy deep dive
3l4l5
1
190
Introduction to Sansan for Engineers / エンジニア向け会社紹介
sansan33
PRO
5
43k
AI時代、“平均値”ではいられない
uhyo
8
2.2k
Featured
See All Featured
Navigating Team Friction
lara
190
15k
Designing for humans not robots
tammielis
254
26k
The Cost Of JavaScript in 2023
addyosmani
55
9.1k
Reflections from 52 weeks, 52 projects
jeffersonlam
353
21k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
9
930
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
285
14k
4 Signs Your Business is Dying
shpigford
185
22k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
10
880
Code Review Best Practice
trishagee
72
19k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.5k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
36
6.1k
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/ /
ありがとうございました