Upgrade to Pro — share decks privately, control downloads, hide ads and more …

モバイルゲームを支えるリソース管理基盤のつくりかた【DeNA TechCon 2021】/techcon2021-10

8a84268593355816432ceaf78777d585?s=47 DeNA_Tech
March 03, 2021

モバイルゲームを支えるリソース管理基盤のつくりかた【DeNA TechCon 2021】/techcon2021-10

大規模なモバイルゲーム開発におけるリソース管理では、高頻度の動的配信、高速なダウンロード、高速な暗号化と、高速なビルド、リソース解析によるネタバレ防止、柔軟なアドレッシングなど、安定したゲーム運用を高効率で支えるために様々な要求に応える必要があります。
本セッションでは、大規模なモバイルゲーム開発におけるリソース管理へ求められる性質と、DeNAがそれらに対してどのようなアプローチでどのようなモジュール構成で解決を図ったのかを解説します。

8a84268593355816432ceaf78777d585?s=128

DeNA_Tech

March 03, 2021
Tweet

Transcript

  1. Haruto Otake

  2. • (Unityを対象とした)モバイルゲームのリソース 管理基盤が解決すべき課題と、DeNAが取ったそ れらへの解決策 • 基盤ライブラリとフレームワークを分離するアプ ローチとその利点

  3. • 大竹 悠人 (Haruto Otake) • 経歴 ◦ 2009~2013 ドワンゴ

    ◦ 2013~ DeNA ▪ ブラウザやUnity製ゲームの新規開発/運用 ▪ 現在はUnity用ライブラリやSDK開発に従事
  4. モバイルゲームのリソース基盤が 解決すべき課題

  5. • 継続的なゲーム運営の為の差分管理 • 巨大な初期ダウンロード • アプリバイナリに組み込むリソースへの対応 • コンテンツ保護と高速なロードの両立 • アップデート実施までのリソースの秘匿

    • 開発のイテレーション速度を阻害しないビルド
  6. • ゲーム運営の為の継続的なコンテンツ追加 ◦ 月3,4回前後のイベント運用を行うには、アプリ更 新を伴わないリソース更新が必須 ◦ ネットワーク経由でのリソース公開 ▪ 必要な差分を適宜算出する

  7. • 追加が主だが、既存リソースの 差し替えも発生 • 更新のタイミングは利用者に依 る為、アップデート元が不定 • DL途中のアプリ終了の考慮 ◦ ダウンロード済みかどうかや、

    ファイル破損のチェック実施 A B C B’ D E A' Ver.1 Ver.2 Ver.3 Ver.4
  8. • 今のモバイルゲームでは1GB以上のダウンロード がインストールに発生してしまう事が多い • 利用者に待ち時間を強いると、離脱に繋がる • サイズが大きいと、利用者のモバイル通信容量を 無駄にする

  9. • 必要に応じてダウンロードする戦略もあるが... ◦ コンスタントに利用者の通信容量を消費する ◦ 非同期にアセットを見せる等の工夫が必要 ◦ すべての場面で適用出来るものではない

  10. • チュートリアル用など追加DLを挟まずに利用し たいリソースはアプリに組み込みたい ◦ iOSではAppStore規約上必須 • Android / iOS共に、アプリバイナリへのリソー スの組み込みには一定の制限が存在

  11. • Android ◦ 2021年後半からAndroid App Bundle(AAB)の適 用が義務化(OBBが利用不可に) ◦ OBBでは2GBまで配信可だが、AABでは150MB 以上は配信不可

    ▪ PlayAssetDeliveryの導入で1GB迄配信可 ◦ apk(zip)として格納されるため、ファイルアクセス の手段に制限が生まれる
  12. • iOS ◦ AppStoreの規約上、起動時にAppが正しく機能 するよう、バイナリに十分なコンテンツを含む 必要 がある ▪ チュートリアル等も含める為、巨大に ◦

    2GBまで配信可 ◦ OnDemandResources利用で+2GB迄配信可 ◦ 通常のファイルシステムとして扱える
  13. • 特に他社IPを使わせて頂くタイトルでは、暗号化 によるコンテンツ保護の仕組みが必要 • 暗号化による負荷がゲーム体験を損ねないよう に、高速なロードを両立する必要がある ◦ 特にUnityでは、長らくAssetBundleの暗号化と チャンク読み込みの両立が難しく、メモリを消費し がち

  14. • ゲームからまだ利用されていないリソースがダウ ンロード可能になると、攻撃者から解析される ◦ ”ネタバレ” / “解析” / “リーク” と呼ばれる

    ◦ イベントやキャラなどの情報が、公式な情報公開 前に広まる可能性が高い
  15. • リソースのビルド/デプロイが開発中の確認やリ リース作業を時間的に阻害するのを避ける ◦ 運用してきた時間に比例してビルド対象物は線形 に増加する

  16. • 継続的なゲーム運営の為の差分管理 • 巨大な初期ダウンロード • アプリバイナリに組み込むリソースへの対応 • コンテンツ保護と高速なロードの両立 • アップデート実施までのリソースの秘匿

    • 開発のイテレーション速度を阻害しないビルド
  17. これらの課題をどう解決するか?

  18. • 統合された1つのソリューションにせず、課題領 域を絞った複数のライブラリ/モジュールに分割 • 全体を通して見たときに、利用側が前述した課題 を全て解決できている状態を目指す

  19. • Aladin ◦ 空間効率に優れたリソースのリビジョン管理 と暗 号化 • AssetFetcher ◦ HTTP/2によるリソースの並列ダウンロード

    • Abdool ◦ 高速な増分AssetBundleビルド & ロード
  20. • ファイルベースのリソース管理ライブラリ • 特徴 ◦ Addressによるリソースへのアクセス ◦ 複数のリビジョンのリソースを効率的に保持 ◦ 高速なデプロイ

    ◦ 様々なストレージへの対応と透過的な利用 ◦ 透過的な暗号化 & 解析によるネタバレ防止
  21. • 特定のリビジョンのリソース全 体をTreeと呼ぶ • Tree毎に、Addressを識別子と した仮想的なストレージを持つ

  22. • リソースの実体は中 身をハッシュ化した 値をファイル名にし てBlobとして保存 • AddressとBlobの 紐付けをIndex として保持

  23. • リビジョン間で共通するリ ソースは同一Blobで保持 • 中身が同一なら、異なる Addressでも同一Blobで保持 • 追加/変更差分のストレージ 消費のみで複数リビジョン を同時に保持可能

  24. • ファイルを上書きしない 為、安全かつ高速なリビ ジョン切り替えが可能 • 中身のハッシュ値とファイ ル名を比較するだけで破損 チェックが可能

  25. • シリアライズしたIndexの ハッシュ値がリビジョン • IndexもBlob同様にハッシュ 値をファイル名として保持

  26. • ハッシュ値の先頭1バイトで サブディレクトリを作る ◦ 大量のファイルを1つのディ レクトリに保存することによる パフォーマンス低下を回避

  27. • Flatbuffersでデシリアライ ズ不要の問い合わせを可能に ◦ メモリ軽減 • Addressを64bitハッシュ化 ◦ ソート済のFlatbuffers上のリ スト構造を直接二分探索

  28. • Index同士の比較や、Indexに含まれるがストレー ジに存在しないBlobの特定 ◦ ダウンロードが必要なリソースの特定に利用 • 複数のリビジョンを指定して、どのTreeからも参 照されなくなったBlobの削除 ◦ リビジョン更新後の旧リソースの削除に利用

  29. 1. CLIツールからTreeの形式にリソースを変換 2. 変換結果をディレクトリごとCDNにデプロイ 3. デプロイ先のベースURLと最新のリビジョンから IndexのURLを特定してダウンロード 4. Indexを読み込み、未ダウンロードなBlobを列挙 5.

    Blobをダウンロード 6. Treeが読み込み可能に
  30. • 以前にデプロイしていないBlobのみを転送するだ けで済む為、極めて高速なデプロイが可能 • 上書きが発生しないので、サーバー側に存在する ファイルは転送する必要がない ◦ gsutils cpの-nオプションによって、サーバーに存 在しないファイルのみの転送を実現可能

    • デプロイ先のサーバーでも同時に多数のリビジョ ンを保持可能
  31. • ストレージへの読み書きは抽象化して実装 • アプリバンドルしたリソースとダウンロードした リソースを透過的に効率的に使い分ける • 対応するストレージ ◦ 通常のReadOnly/Writableなファイルシステム ◦

    AndroidのStreamingAssets ◦ Play Asset Delivery
  32. • Google Play Plugins for Unityを利用 • Play Asset Deliveryの任意のAsset

    Pack内に保 存したAladinのTreeを読み込む ◦ ファイルパスとOffsetとSizeを得られるため、範囲 を制限しただけのFileStreamとして少ないオー バーヘッドで読み込める
  33. • アプリ同梱のリソースとダウン ロードしたリソースを完全に透過 的に扱う事を可能にする • Decoratorによる宣言的な合成

  34. None
  35. • 暗号化後のデータをBlobとして保存 • 暗号化の実装は適宜入れ替えが容易に可能 • 標準はランダムアクセス可能なストリーム暗号 ◦ AssetBundle.LoadFromStreamに利用可能 ◦ 暗号化利用時もチャンクロードが可能

    ◦ unsafeで高速,アロケーションフリーに最適化 ▪ C#での相互運用性と速度を両立 ▪ Unity特化版としてBurstへの対応も進行中
  36. • クライアント内に隠した単一の鍵をコード解析等 で解読されるのが、ネタバレの主要要因 ◦ 難読化しても、一度暴かれた時点でアウト ◦ URLの難読化や、利用開始の直前までゲームか らダウンロードさせないことで以前は解決 • 鍵をクライアントが知るのが不可能なら、解析耐

    性は暗号化アルゴリズムの強度に依存
  37. • 暗号化鍵を複数かつTreeとは独立して配布可能 ◦ リソース毎に鍵IDを指定される ◦ ランタイムで取得できるのは鍵IDのみ、鍵IDに紐 づく鍵情報は別途利用開始前に公開 ◦ 公開済みの鍵は独自キーストアに格納 •

    イベント開始前のリソースの柔軟な配布が可能 ◦ 開始前に鍵を知ることが出来ないので、解読でき ない
  38. • 継続的なゲーム運営の為の差分管理 • 巨大な初期ダウンロード • アプリバイナリに組み込むリソースへの対応 • コンテンツ保護と高速なロードの両立 • アップデート実施までのリソースの秘匿

    • 開発のイテレーション速度を阻害しないビルド Aladin Aladin
  39. • 高速な並列リソースダウンローダ • 特徴 ◦ HTTP/2による高速並列ダウンロード ◦ 様々な配信方式に幅広く対応 ◦ ゲームエンジンを問わず利用可能

  40. • 指定されたリソースをストレージに展開すること に特化 ◦ URL,保存先,ハッシュ値の組のリストを受取る ◦ 指定されたURLから並列にダウンロード ◦ 結果のハッシュ値を計算し破損判定&リトライ ◦

    保存先に展開 • ダウンロードの必要性の判定は行わない ◦ Aladin側ですべて判定可能
  41. • HTTP/2では1接続で並列に大 量のリクエストとレスポンス のやり取りが可能 ◦ 効率的に並列数を上げられ る為、受信完了から次の受 信開始までの時間が短い ◦ 大量の小さなファイル向き

    イメージ図
  42. • 旧来でも1ファイルにアー カイブすることで転送効率 は高められる • Aladinのようにアーカイブ を行わない配信形式では HTTP/2は相性がよく、大 きな効果 イメージ図

  43. 163.93s から 20.93s HTTP/2での並列ダウ ンロードのあり無し で、約8倍もの差 5KB * 20000ファイル での計測

  44. • 配信にサーバーの対応状況を確認する ◦ 主要なCDNであれば殆ど問題ない • nginxなどでリバースプロキシを挟むと速度が出 ないことがある ◦ 開発用のIPアドレス制限などの利用に注意

  45. • ZIPアーカイブ対応 ◦ ダウンロードが完了したZIPの内容を、順番に保 存先ディレクトリに展開する ◦ ZIP形式のパッチを順に適用する形式をカバー • 独自アーカイブ(DnArchiver)対応 ◦

    リソース毎に圧縮の有無を選択できる独自のアー カイバでもZIP同様の運用が可能
  46. • libcurlをバックエンドとして、C++で実装 ◦ Unity向けにはネイティブプラグインとしてのイン ターフェースを用意 • Unityはもちろん、内製エンジン(LiftEngine)を 含むその他のエンジンでも利用可能 • macOS/Windows/Linux/iOS/Androidの5プラッ

    トフォームに対応
  47. • 継続的なゲーム運営の為の差分管理 • 巨大な初期ダウンロード • アプリバイナリに組み込むリソースへの対応 • コンテンツ保護と高速なロードの両立 • アップデート実施までのリソースの秘匿

    • 開発のイテレーション速度を阻害しないビルド Aladin Aladin AssetFetcher
  48. • AssetBundleビルド&ロードライブラリ • 特徴 ◦ VCSベースの高速インクリメンタルビルド機能 ◦ シンプルなアドレッシングと最適化された独自カタロ グ管理 ◦

    厳密な重複排除ポリシー ◦ ResourceManagerベースの柔軟なロード機能
  49. • Addressable Assets Systemの一部のみを利用 ◦ AddressableのバックエンドであるResource Manager, Scriptable Build Pipelineを利用

    ◦ ロード状況を見れるEvent Viewerも利用 • Addressable本体のAssetBundle管理機能は利用 しない
  50. • Scriptable Build Pipelineでカスタムしたパイプ ライン • Gitから以前のビルド以降で変化したアセットの リストを取得 ◦ interface経由で他のVCSにも対応可能な設計

    • アセット間依存を元に、ビルドする必要のある AssetBundleを特定した上で実ビルド • カタログを差分更新
  51. アセットごとにグローバルなアドレスを設定可 カタログファイルのシリアライズには Flatbuffersを採用し、アロケーションを回避 カタログは非常に大量の文字列を含む 基数木による文字列保持を実装し、共通化 アセットの読み込みは文字列のハッシュのみを使 い、文字列比較を排除

  52. • AssetBundleでは容易にアセットの重複が起こる ◦ Addressableの場合ではAnalyzerで重複を検知 できるが、その代替が必要 • ビルド中の全てのアセットに対して所属する AssetBundleが一意に定まれば重複しない ◦ 所属するAssetBundleが定まらないアセットがビ

    ルドされた際にエラーとなるように
  53. • AssetBundle構成はinterface経由で実装を注入 ◦ バンドル名, ファイルパス, アドレスの組のリストを 返せることと、幾つかの逆引きも要求 ◦ このinterfaceをPackRuleと呼ぶ •

    フォルダ単位のシンプルな物は標準実装 ◦ フレームワークやゲーム側でのポリシーにあわせ て個別に実装する
  54. • Locatorを実装し残りはResourceManagerを利用 ◦ Provider/Locatorの差し替えでカスタマイズ

  55. • ResourceManagerの管理機構をそのまま利用 ◦ ロード開始時に得られるHandleを ResourceManager.Releaseに渡すことで開放 ◦ 参照カウントも行う為、同じアセットを複数ロードし ていても意識する必要はない • AssetBundleは所属するアセットを全て開放した

    時点で自動的に開放される
  56. • Editorでの確認は 元アセットを AssetDatabase からロードしたい ◦ Locatorの差替 ◦ カタログを使わ ずPackRuleを

    利用
  57. • AssetBundle.LoadFromStreamを利用すること で、StreamからAssetBundleをロード可能 ◦ 固定長の内部バッファの消費のみで、高速なラン ダムアクセスを行ってくれる ▪ メモリフットプリントの大幅軽減 ▪ 暗号化の計算量の大幅削減

    • Aladinの暗号化Streamを扱うことで実現 ◦ 以前はAbdool側で実装していたが、全て移譲
  58. • 専用のLocator /Providerを利用 • 平文のものは通 常のProviderを 利用 ◦ LoadFromFile が利用可なら

    こちらが軽量
  59. • 継続的なゲーム運営の為の差分管理 • 巨大な初期ダウンロード • アプリバイナリに組み込むリソースへの対応 • コンテンツ保護と高速なロードの両立 • アップデート実施までのリソースの秘匿

    • 開発のイテレーション速度を阻害しないビルド Aladin Aladin AssetFetcher Abdool
  60. • 設計に柔軟性を持たせて幅広いユースケースに対 応できるということは、ユースケース毎にそれに 応じた引数等を注入しなければならない • 多くのタイトルに導入するにあたっては、これら を仲介する層が必要

  61. • 内製フレームワークの一部、Sharin.Resourcesが 直接的なフロントエンド ◦ Aladin, AssetFetcher, Abdoolを中心に他の基盤 モジュールも組み合わせ、よりユースケースを絞り 込んだフレームワークとして実装

  62. • 実機確認のイテレーション問題 ◦ リソースを実機確認する際にはアプリに組み込ん でビルドするか、サーバにアップロード&実機でダ ウンロードする必要がある ◦ 少しずつ調整しながら実機確認をしたい場合に何 回もアプリをビルドorアップロード・ダウンロードす る必要がある

    ◦ イテレーションが回しづらく開発効率が低下
  63. • PC上のリソースを直接参照してしまう事で解決 ◦ USB接続したPC上のリソースを実機のリソースの ように扱う 参照

  64. Aladin Abdool Sharin.Resources AssetFetcher Sharin’の その他の様々な モジュール Abdool + Aladin

    インテグレーション vfs ゲームタイトル devwire DebugFileSyste mから利用 TechCon2020で の講演を参照
  65. 65

  66. • フレームワークを導入しなくても、部分的に成果 を取り入れることが可能になる ◦ Sharin.Resourcesを使わないタイトルでも、同じラ イブラリの導入に成功 ◦ AssetFetcherに関しては非Unityでも導入済 • 問題を小さなサンプルで再現が可能に

    ◦ 問題のあるモジュールのみに集中できる ◦ 自動テストがしやすく、問題解決が容易に
  67. • ライブラリ側の責任範囲が限定的かつ明確になる ◦ それぞれを単純化でき、柔軟性を担保可能 ◦ 向き合う領域が単純な方が尖った設計を行えて、 競争力を持つ機能を開発できる ◦ ゲーム側での“決め”になる部分をフレームワーク層 に委ねることができる

    ▪ ライブラリが意思決定の速度的なボトルネックに なるのを避ける
  68. • モバイルゲームのリソース管理基盤には様々な課 題がある • 役割を絞って尖った機能性と柔軟性を持った様々 なライブラリを開発して課題解決を行った • わかりやすいインターフェースのフレームワーク 層を提供して使い手側に寄り添っている

  69. None