こんにちは。Yahoo!広告 ディスプレイ広告エンジニアの小杉です。 私は、広告配信をおこなうシステムの開発を担当しています。
ディスプレイ広告は 10年以上前から存在するプロダクトで、最大で数十万 QPS をさばく大規模なシステムです。常に大規模なトラフィックをさばくシステムの機能を停止せずに、約2年半の時間を掛けてシステムをモダン化しました。
この記事では、どのようにして大規模システムのモダン化を実現したのか、紹介します。
背景
Yahoo!広告では SSP(Supply Side Platform) と DSP(Demand Side Platform)を所有しています。それらのシステムは10年以上前から存在しているためさまざまな課題が存在していました。 その解決のため、広告配信プラットフォームのモダン化プロジェクトが発足しました。
プロジェクト開始前の状況(2021年6月時点)
プロジェクト開始前のシステム構成は下の図1 の通りで、大きく 3点の課題が存在していました。
- システムがレガシーだった
- SSP と DSP の I/F が業界標準とは異なった
- SSP と DSP の役割分担があいまいだった
図 1. プロジェクト開始前のシステム構成
1. システムがレガシーだった
図1 より SSP・DSP が複数の言語の異なるシステムを持っていて、 レガシーな言語を使用しているため運用コストも高くなっていました。 そのため、3つのシステムを 1つに統合してモダンな言語に刷新しました。
2. SSP と DSP の I/F が業界標準とは異なった
SSP と DSP の I/F は、さまざまな会社と広告のやりとりをおこなうため、オンライン広告の技術的標準規格の策定をおこなう IAB が業界標準の I/F として Open RTB を 2011年に定義しています。
しかし、ヤフーでは Open RTB の定義以前から広告配信をしていたため、その後も10年以上、ヤフー独自仕様が用 いられている状態でした。 他社が Open RTB を利用する中で、ヤフー独自の I/F の利用を続けていたため、下記の課題が発生しました。
- 社外の SSP・DSP に直接接続できない
- 下のようなシステムを構築する必要がある
- 社外の SSP・DSP と接続するための中間システム(前の章の図の社外 SSP 用 DSP)の構築が必要
- システムが増えるので運用コストが増加する
そのため、運用面と今後の発展性を考えると独自 I/F より、業界標準の Open RTB の I/F へ統一することが望ましかったのです。
3. SSP と DSP の役割分担があいまいだった
ヤフーでは SSP・DSP の両方のシステムを持っているため、 下の図のようにサプライ側が持つ広告掲載面の情報を DSP が直接参照して情報を取得しています。 ちなみにデータベース(以下DB) はサプライ側のもので、領域を点線でわけています。
図 2. 役割分担があいまいな SSP と DSP
図2 のように DSP がサプライの領域に侵入してデータを取得しているため、役割が適切に分担されているとはいえません。 そのため、データの取得の経路を一本化して SSP と DSP の担当領域を適切に分担しました。
課題の解決方法
SSP と DSP には前述した 3点の課題が存在しているため下記の対応を取りました。
- レガシーなシステム
- システムの統合
- モダンな言語(Go)への刷新
- 業界標準とは異なる SSP と DSP の I/F
- Open RTB の I/F に変更
- SSP と DSP の役割分担があいまい
- データの取得の経路を一本化
プロジェクト開始前の状況
- 3つの SSP(PHP, C++, Node.js)
- 2つの DSP(C++, Go)
- SSP と DSP の I/F が XML と JSON 形式の 2つ
プロジェクト完了後の状況(2023年9月時点)
- 1つの SSP(Go)
- 1つの DSP(Go)
- SSP と DSP の I/F が Open RTB 形式のみ
図 4. プロジェクト完了後のシステム構成
システムのモダン化を完了させると、広告プラットフォームは図4 のようにシンプルな構成となりました。
広告の配信プラットフォームのモダン化プロジェクト
前の章で記述したさまざまな課題を解決すると、システム構成から I/F まですべて変更となる大規模改修となり、一段階で解決するのは非常にリスクが高いといえます。 そのため、2年半という長いスパンで以下の段階を踏んで対応しました。
- 言語刷新
- システム統合
- SSP・DSP のあいまいな枠割分担の解消と独自 I/F からの脱却
1. 言語刷新
レガシーな言語のままシステムを統合すると開発やメンテナンスが大変であるため、最初に既存のシステムをモダンな言語(Go)に言語刷新しました。 なお、SSP に関しては web と S2S の処理が近いため、言語刷新で新しいシステムを作成するときに統合をしました。
また、アプリの SSP と DSP の言語刷新に関しては、Tech Blog にまとめているので詳細はそちらをご覧ください。
2. システム統合
システム統合では、SSP と DSP のそれぞれで対応をおこないましたが、システム統合の全体を通して下記のような効果が生まれました。
- リリース時間が 50% 以上減少
- 20% 程度のレイテンシの改善
- CPU リソースなどのリソース削減
SSP
SSP は 3つのシステムが存在するため、一度で対応すると改修規模が大きくなるため、言語刷新とあわせて下記の順でシステム統合をおこないました。
図 5. SSP のシステム統合の流れ
- web・S2S の SSP を統合したシステム(Supply Service)を Go で実装(言語刷新 + システム統合)
- 既存のアプリの SSP を Go で実装(言語刷新)
- 2 で作成した SSP を Supply Service に統合(システム統合)
なお、アプリの SSP を最初から Supply Service に統合しなかったのは、アプリと web・S2S はユーザーからのリクエスト・レスポン スが異なり、一度に対応するのが難しかったからです。そのため、段階を踏んで対応しました。
DSP
DSP のシステム統合に関しては先ほど紹介した「広告配信システムの統合とモダン化 〜10年分のレガシー脱却~」で広告配信サーバーと広告最適化サーバーを統合したと紹介がありました。さらに社外 SSP 用の DSP も DSP(Demand Service)に統合しました。
DSP を一つに統合することで、リソースの削減・サーバー間の通信が減り、レイテンシの向上といった成果が得られました。
言語刷新とシステム統合のまとめ
言語刷新とシステム統合により、開発しやすい環境を作成し開発コストが減少し、 開発しやすい環境下で I/F の刷新に取り組めました。
3. SSP・DSP のあいまいな役割分担の解消と独自 I/F からの脱却
ヤフーの SSP・DSP は独自の I/F でディスプレイ広告自体にも独自の仕様が存在するため、単純に I/F のパラメータを置き換えるだけでは I/F の刷新はできません。
下記の課題の解決を図りつつ Open RTB の I/F に切り替えるため、比較的難易度の高い取り組みでした。
- 課題
- 業界標準とは異なる SSP と DSP の I/F
- SSP と DSP の役割分担があいまい
なお、Open RTB の I/F はさまざまな version が存在しますが、 DSP が他社 SSP との接続でも利用して知見のある Open RTB 2.5 を採用しました。
業界標準とは異なる SSP と DSP の I/F
基本的には Open RTB の仕様に従って既存の I/F のパラメータを連携しますが、仕様に当てはまらないパラメータが発生しました。
そのパラメータを連携しないとディスプレイ広告の機能要件を満たせなくなるため、 どのように連携するのか検討しました。Open RTB の仕様で独自のパラメータは、Ext(Extension)に要素を連携できたため、その方式を利用してパラメータを連携しました。
ただし、ヤフー独自の Ext は 30項目以上となるため Open RTB の I/F ですが、ヤフーの独自色が強い状況になっています。
SSP と DSP の役割分担があいまい
SSP と DSP の役割分担があいまいの章で説明したとおり、DSP がサプライ側の DB を参照して掲載面の情報を取得しています。 それらの役割を適切に分担するためには DSP が取得していた掲載面の情報を SSP が取得して、SSP から DSP へのリクエスト(Bid Request)に組み込む必要があります。
しかし、SSP が DB から取得した値をもとに Bid Request を生成するのはコストが掛かるため、下記の工夫をおこないました。
- DB に掲載面の情報を含む Bid Request を連携
- リクエストに応じて変化する値は SSP で値を埋める
役割分担を変更した後の SSP・DSP・DB の関係はこのようになりました。
図 6. 役割分担を変更した SSP と DSP
役割分担前は DSP がサプライ側の領域に踏み込んでいました。しかし役割分担を適切に変更することで、DSP がサプライ側の DB を参照せずに、SSP と DSP の役割が明確になりました。
機能差分が生じていないことを確認するためのテスト
言語刷新および I/F の刷新をおこなう場合、機能面・性能面でデグレーションが発生していないことが重要です。
特に広告配信プラットフォームでデグレーションが発生した場合、売上を損なうだけではなく、広告掲載面や広告主などさまざまな方面に迷惑を掛けてしまうため、慎重にテストをおこなわなければなりません。
そのため、下記の観点を意識してテストをおこないました。
- 結合試験
- I/F に想定通りのパラメータが連携されるか確認
- すべての広告種別の広告引き当て・表示確認の実施
- 性能試験
- 新・旧で同等のリクエストを投げてレイテンシなどのメトリクスを比較
- リプレイテスト
- 既存のリクエストをもとに新・旧でリクエストを投げてレスポンスに差分が生じないか比較
これらのテストをおこなえば、機能面・性能面において、デグレーションが発生していないことを確認できます。
結合試験
結合試験では本番環境と同等のシステム構成のテスト環境で、すべての広告種別を引き当てられるように、広告掲載面の配信設定や広告の入稿をおこなっています。
ま た、結合試験時のシステム構成は本番環境と変わらず web ページの閲覧等をおこない、サーバーのログ確認して I/F に想定通りのパラメータが連携されているか、 掲載面で広告の表示がくずれていないか確認をしています。
図 7. 結合試験の構成
旧来の結合試験(図7)では、新環境・旧環境のレスポンスなどの情報を手動で取得・差分確認をおこなっていました。しかし効率が悪いため、取得から差分確認まで自動でおこなうテストツールの作成をおこない、テストの効率化も図りました。
それらの試験内容を新・旧環境で実施してデグレーションが発生していないことを確認しています。
性能試験
性能試験では、本番環境と同程度の性能を持つ性能試験環境で、本番環境の広告引き当てをおこないます。
性能試験では対象となるシステムの性能を正確に測らなければならないため、後続のシステムの影響を受けないように mock サーバーを用意して性能試験を実施しています。
図 8. 性能試験の構成
試験時は広告リクエストのピーク時の 1.5倍のリクエスト数、10分間連続でリクエストを流してシステムの SLO を満たすか確認しました。 試験では SLO を満たす結果が得られたため、性能面で問題が発生していないことが確認できました。
リプレイテスト
リプレイテストは事前に保存した広告リクエスト時のデータを用いて、同一のリクエストを流したときに同一のレスポンスが返却されるか確認します。
リプレイテストの流れは図9 です。
- リプレイテスト用のログを取得
- mock の Demand Service リプレイテスト用のレスポンスを登録
- クライアントが広告レスポンスを取得
- クライアントが落とすログとリプレイテスト用のログが一致するか検証
図 9. リプレイテストの構成
過去にアプリ用SSPサーバー言語刷新の紹介で 1,000件のデータを用いてリプレイテストを実施していると紹介しましたが、今回の対応ではリプレイテストをさらに発展させました。
発展させたポイントとしては、下記の 2点です。以前よりも信頼性の高いテストをおこなえました。
- テストデータは前日分の実際のリクエストを自動で取得して利用する
- web, s2s, アプリの各リクエストを 10,000件ずつ取得
各段階でのリリース
一度にすべてのリクエストを新しいシステムに切り替えるのはリスクが高いため、一部の広告掲載面で 10%、50%、100% → 全体の広告掲載面:10%、50%、100%と、段階的にリリースをおこないました。
リリース後に新・旧のシステムでの 広告のクリック率(CTR)や広告の viewable 率等の KPI を比較して、差分が生じていなければ次のリリース・段階に進むという方法をとりました。 このリリースフローを「言語刷新」「システム統合」「I/F 刷新」ごとに繰り返しました。 KPI の確認では新・旧の KPI を日次集計し、 Tableau で可視化して、異常検知できました。
リリース → KPI 確認 → リリース → ... を繰り返して、安定してすべてのリリースが完了できました。
まとめ
ディスプレイ広告の配信プラットフォームのモダン化プロジェクトは、完了まで 2年半という長期間を掛けて言語刷新から I/F の刷新まで完了しました。
プロジェクトが遅延なく完了した要因は 2点あるのでまとめます。
- 一度にすべてを対応せず、適切な中間目標を設けて進めていくこと
- 機能差分が生じていないことを念入りにテストすること
一度にすべてを対応せず、適切な中間目標を設けて進めていくこと
言語刷新・システム統合・I/F 刷新と難易度の高い対応を一度にすべておこなわず、 「SSP の言語刷新のリリースを完了させる」「DSP を統合してリリースを完了させる」など、 半年単位でやるべき対応を検討・実行を繰り返してきました。 プロジェクトの完了まで一歩一歩段階を踏んで進んだからこそ、プロジェクトの当初の目論見どおりに遅延も発生せず完了ができたといえます。
大規模なプロジェクトの場合、どこをどの期間で対応するのか見積もりを適切にし、実行することで、プロジェクトは遅延せずに完了できるのではないかと考えています。
機能差分が生じていないことを念入りにテストすること
機能差分が生じるとさまざまな方面に影響を 与えてしまうため、結合試験・性能試験・リプレイテストを実施して品質の担保に努めました。 また、今までのテストで非効率な部分を自動化して効率よくテストが実施できたため、より信頼性の高いテストが実施できました。
自分たちが作ったシステムはそれらのテストすべて通ったため、大丈夫であろうという気持ちからイケると自信を持てました。 つまり、自信が確信に変わったともいえます。 テストを実施する前に、テスト自体を効率化できないか検討・改善に取り組んだ上でテストを進めることが大事だと感じました。
最後に
以上の 2点がプロジェクトが遅延なく完了した要因です。 記載している内容は当たり前ともいえる内容ではありますが、当たり前をしっかりとやり抜くことが重要であると考えています。
今後、大規模システムで大規模な刷新する際に参考になれば幸いです。