Skip to main content
ダウンロード時間を大幅減!
~大量のアセットをさばく高速な実装と運用事例の共有~
© SEGA
ゲームコンテンツ&サービス事業本部 技術本部 開発技術部
竹原 涼
自己紹介
【登壇歴】
CEDEC 2020 「技術同人作家になろう ~働き方改革時代におけるエン
ジニアのレベルアップの一例~」
Unite Tokyo 2019 「大量のアセットも怖くない!~HTTP/2による高
速な通信の実装例~」
CEDEC 2018、CEDEC 2016、CEDEC 2015 プロダクション関連のラ
ウンドテーブル
GDC2016 報告会 「GDC16にみる自動化技術とテストのトレンド」
祝・HTTP/3 RFC発行(間近)!
© SEGA
ゲームコンテンツ&サービス事業本部 技術本部 開発技術部
山田 英伸
自己紹介
【登壇歴】
CEDEC 2020
「技術同人作家になろう
~働き方改革時代におけるエンジニアのレベルアップの一例~」
Unite Tokyo 2019
「大量のアセットも怖くない
~HTTP/2による高速な通信の実装例~」
© SEGA
• 本講演内容の撮影、SNS投稿は OK
• 後日、CEDIL で資料を公開
• 講演中の質疑が可能です。
コメントに書き込んでください
• 資料に記載されている会社名、システム名、製品名、サービス名は各社の登録商標または
商標です
• Android ロボットは、Google が作成および提供している作品から複製または変更したもの
であり、
クリエイティブ・コモンズ表示 3.0 ライセンスに記載された条件に従って使用しています
© SEGA
• CDN に配置したアセットを端末にダウンロード
• HTTP/1.1 と HTTP/2 の差に注目
効果を先にお見せします
© SEGA
• HTTP/2 なら接続数が少なくても、
HTTP/1.1 より圧倒的に早い (待ち時間短縮)
HTTP/2による効果
プロトコル 速度 完了までの時間 備考
HTTP/2 約 280 Mbps 約 3.6 s 1 Connection
HTTP/1.1 約 110 Mbps 約 9.2 s 6 Connection
HTTP/1.1 約 59 Mbps 約 17.2 s 3 Connection
諸条件
Pixel3 (Android10) 使用
AWS CloudFront 使用(国内リージョン)
総数 2000 ファイル / 1ファイル64KB
※ 300-340Mbps が出る回線にて Wi-Fi 接続状態
© SEGA
• ゲーム開発者向け HTTP/2 仕様の説明
• HTTP/2 を使うための実装について
• HTTP/2 導入時の勘所
• HTTP/2 トラブル集
• HTTP/2 の採用によるインターネット全体への波及効果
• まとめ
本講演の流れ
© SEGA
ゲーム開発者のための HTTP/2
© SEGA
• HTTP/2 2015年 標準化完了&公開
– HTTP/1.1 を基本的に継承
• 現在の普及率 約45.6% (w3techs.com 2021/06時点)
ゲーム開発者のための HTTP/2
© SEGA
• 多重化
• HPACK
• バイナリフレーム
(ゲームと関連性の深いものに限定)
HTTP/2 の仕様
© SEGA
HTTP/2 多重化
© SEGA
• 1つのコネクションに複数の HTTP リクエスト
多重化 – HTTP/2 の仕様
GET
GET
GET
APP SRV
Connection
ストリーム
© SEGA
• HTTP の Head of Line Blocking:HoLB (HTTP/1.1)
– 何らかの要因で先行リクエスト処理に時間が掛かると
後続のリクエスト処理が遅れてしまう
HTTP/1.1の課題 - 多重化 – HTTP/2 の仕様
1.png
2.png
3.png
この分の遅れが後続に響く
1.png
© SEGA
• HTTP/2 は HTTP の HoLB を回避
– 複数ストリームの多重化により
後続のリクエストを並行に処理可能
多重化でHoLB回避 - 多重化 – HTTP/2 の仕様
1.png この分の遅れは
他のリクエストに影響しない
1.png
2.png
3.png
© SEGA
• HTTP/1.1 と HTTP/2 通信状態の比較
帯域の利用 - 多重化 – HTTP/2 の仕様
HTTP/1.1 HTTP/2
時間
使用可能な
回線帯域
時間
HTTP/1.1 は Keep Alive 有効を想定.
但しファイルサイズが小さいと広帯域を活用できない.
© SEGA
• HTTP/2 は使える帯域を有効活用
帯域の利用 - 多重化 – HTTP/2 の仕様
HTTP/1.1 HTTP/2
時間
使用可能な
回線帯域
時間
帯域を活用できていない 多重化で帯域をしっかり活用
© SEGA
 細かいアセットダウンロードに有効
 効率的に回線帯域を使用
 クライアント・サーバ間通信
 RTT による待ち時間削減
(モバイル回線 など)
ゲームとの関連 – 多重化 – HTTP/2の仕様
RTT
RTT
APP SRV
SRV
APP
1RTT 分で複数リクエスト
RTT
HTTP/1.1
HTTP/2
© SEGA
HTTP/2 HPACK
© SEGA
• HTTP ヘッダを圧縮する仕組み (RFC 7541)
• 技術要素
 Huffman coding
 Indexing Table
Static Table
Dynamic Table
HPACK – HTTP/2 の仕様
© SEGA
• 出現頻度の高い文字に短いビット列を割当てて圧縮
Huffman coding - HPACK – HTTP/2 の仕様
HTTP/1.1 HTTP/2
10 BYTES
から
8 BYTES へ
© SEGA
• 出現頻度の高い文字に短いビット列を割当てて圧縮
Huffman coding - HPACK – HTTP/2 の仕様
※ < > 内はパディング. オクテット境界に揃える
© SEGA
• 出現頻度の高い文字に短いビット列を割当てて圧縮
Huffman coding - HPACK – HTTP/2 の仕様
HTTP/1.1 HTTP/2
59 BYTES 48 BYTES
※ 参考値です。実際に送信されるバイト数とは異なります
約 81.4% に削減
HTTP/2
63 BYTES
© SEGA
• インデックス値を用いた圧縮機構
– Static Table
– Dynamic Table
Indexing Table - HPACK – HTTP/2 の仕様
© SEGA
• 事前定義されているテーブルのインデックス値を使う
Static Table - Indexing Table - HPACK – HTTP/2 の仕様
HTTP/2
※ 参考値です。実際に送信されるバイト数とは異なります
31 BYTES
63 BYTES
約 49.2% に削減
© SEGA
• 通信に使用したデータをテーブルに登録し、
テーブルのインデックス値を使う
Dynamic Table - Indexing Table - HPACK – HTTP/2 の仕様
※ 参考値です。実際に送信されるバイト数とは異なります
5 BYTES
約 8.4% に削減
テーブルに登録
同内容でリクエスト時
© SEGA
• フレーム: ストリーム上を流れる最小単位
• バイナリデータ送受でテキストより効率が良い
バイナリフレーム – HTTP/2の仕様
フレームヘッダは 9Bytes
フレームの構造
© SEGA
• HTTP/1.1 の場合
• テキストベースのプロトコル
• 解釈の処理で負荷が高め
ゲームとの関連 – HPACK/バイナリフレーム
HTTP/1.1 200 OK
Date: Wed, 30 Jun 2021 02:19:48 GMT
Content-Type:image/jpeg
Transfer-Encoding: chunked
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
456
Chunk1のデータ ....
0
: の後に空白を許可
ヘッダ領域との区切り
ヘッダ名は
大文字小文字区別なし
Chunk終了の CRLF
データサイズはまだ不明
© SEGA
• HPACK, バイナリフレーム
 API 通信のデータ削減・処理負荷軽減
ゲームとの関連 – HPACK/バイナリフレーム
HTTP/1.1 200 OK
Date: Wed, 30 Jun 2021 02:19:48 GMT
Content-Type:image/jpeg
Transfer-Encoding: chunked
Trailer: Expires
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
456
Chunk1のデータ ....
0
データサイズは先頭
HPACKで圧縮
データサイズは先頭
© SEGA
• TCP, RUDP を使えば?
– HTTP/2をトランスポートレイヤーに持つ
gRPC や WebSocket
– サーバ設定や導入コストの圧縮が見込める
– 対応したサーバレスコンテナの登場
• Cloud Run (Google)
閑話 : API 通信に HTTP を用いるメリット
© SEGA
HTTP/2 を使う実装
Client
Server
クライアント
サーバ
© SEGA
• 自力で全て実装は現実的ではない
• ゲームエンジンが内蔵しているもの
&オープンソースの利用
HTTP/2 を使う実装 Client
© SEGA
• C/C++による
自社製ゲームエンジンやミドルウェアを利用
 C/C++製の OSS は選択肢が豊富
 中でも libcurl, nghttp2 がお勧め
ケース1 - HTTP/2 を使う実装 Client
© SEGA
• Unity を使用している場合
 Unityが採用している C#ランタイム/クラスライブラ
リでは HTTP/2 が利用できない
 前述のC/C++製OSSを用いた
ネイティブプラグインを実装
ケース2 - HTTP/2 を使う実装 Client
© SEGA
• Unreal Engine4 を使用している場合
 Windows で WinHttp 使用時のみ HTTP/2 対応
 C/C++製OSSを用いて対処を考える
ケース3 - HTTP/2 を使う実装 Client
© SEGA
• C#による
自社ゲームエンジンやミドルウェアを利用
 C# 標準 API (HttpClient) が HTTP/2 対応
• .NET Framework 4.6
• .NET Core は注意. .NET Core 3.0 で対応(*1)
 但し、パフォーマンスに懸念
ケース4 - HTTP/2 を使う実装 Client
*1 : https://docs.microsoft.com/ja-jp/dotnet/core/whats-new/dotnet-core-3-0#http2-support
© SEGA
• CDN の選定
• サーバソフトウェアの選定
HTTP/2 を使う実装 Server
© SEGA
• 主要なCDNは全て HTTP/2 対応済み!
 CloudFront (Amazon)
 Cloud CDN (Google)
 Azure CDN (Microsoft Azure)
 Fastly (Fastly)
 Akamai CDN (Akamai)
 CloudFlare (CloudFlare)
CDNの選定 - HTTP/2 を使う実装 Server
© SEGA
• サーバソフトウェアの選定
– 主要なサーバプログラムは全て HTTP/2 対応済み!
• IIS, nginx, apache など
– 前段にあるロードバランサに注意 (ADC含む)
• HTTP/2を終端する可能性
ソフトウェア選定 - HTTP/2 を使う実装 Server
© SEGA
HTTP/2 導入時の勘所
© SEGA
• ダウンロードするデータサイズや順序によっては
期待した結果が出ない
 ファイルサイズが大きいものが支配的な場合
 ファイルサイズでソートされている場合
パフォーマンスが出ない① Problem!
© SEGA
• プロジェクトに有効かをまず判断!
 ファイルサイズのヒストグラム
• ダウンロードリストの作り方に工夫が必要
パフォーマンスが出ない① Solution!
私たちが遭遇したので、
後で詳しく説明します
© SEGA
• コネクション数に応じて、
逐次的にリクエスト発行をしている場合
– HTTP/1.1 を意識した実装の場合、
3~6程度でリクエストを送信となることが多い
パフォーマンスが出ない② Problem!
© SEGA
• リクエストを束で受け取る設計
– 多くのリクエストを同時に発行する
– ライブラリを作るときに意識する
パフォーマンスが出ない② Solution!
© SEGA
• リクエスト数が数万になることも!
– ファイル保存時、ファイル I/O のコスト
– メモリに展開時、メモリ使用量が爆発
大量リクエストを捌くために Problem!
© SEGA
 ファイル保存時、分散書込みなど、負荷軽減策が必要
 メモリに展開時、一旦ファイルに保存
 実装によっては、思わぬボトルネックを生むので注意
大量リクエストを捌くために Solution!
私たちが遭遇したので、
後で詳しく説明します
© SEGA
• HTTP/1.1 時
「コネクションエラー=通信エラー」だったが、
考え方を改める必要あり
エラーへの考え方 Problem!
© SEGA
• HTTP/2 ストリーム単位でのエラーは
復帰できる可能性がある
 即、通信エラーにしてはいけない
エラーへの考え方をアップデート Solution!
APP SRV
Connection
正常なストリームは通信中
© SEGA
• 1 Connection内に複数ストリームで通信
– 高パケロス環境では
複数Connection HTTP/1.1 より速度が劣ることも
パケットロス率に注意 Problem!
APP SRV
他のストリームも
再送の影響を受ける
パケットロスで
通信エラーが発生
© SEGA
• HTTP/2 を悪環境で利用時
 一定のパケットロス環境では
HTTP/1.1 にフォールバックする対策
 フォールバックする場合の割合は、
各プロジェクトで計測して判断が必要
パケットロス率に注意 Solution!
© SEGA
• 本番・テストのサーバは対応しているか?
• サーバ側の HTTP/2 機能を有効にし忘れていないか?
• このような事態が発生すると、
HTTP/2 使っても速くない、と誤解される恐れがある
サーバの対応を確認 Problem!
© SEGA
• HTTP/2 の誤った認識をさせないため
 HTTP/2 通信できているかの
チェックツールを用意しておくのも良い
サーバの対応を確認 Solution!
© SEGA
• 優先度(プライオリティ)の仕様がある
• 各ストリームに重みづけや依存関係を設定し、
先に欲しいリソースをサーバに通知する仕組み
HTTP/2 の優先度設定
© SEGA
• ダウンロードの順序制御に
HTTP/2 の優先度制御を使うことはできない
– CDN 実装の問題で事実上使えない
– HTTP として優先度オプションの協議
– 現状 RFC 策定されていない
優先度制御の課題 Problem!
© SEGA
• リクエスト順を制御したい場合には、
自前で実装するのが無難
優先度制御 Solution!
© SEGA
• TLS 1.2 以上が必要 (サーバ)
– 仕様上 HTTP/2では TLS1.2
• AWS ロードバランサ
– ALB の https 通信で HTTP/2 が使用可能
その他
© SEGA
HTTP/2 トラブル集
C
S
クライアント事例
サーバ事例
© SEGA
ダウンロード速度が出ない①
C
S
クライアント事例
サーバ事例
© SEGA
• 通信速度が一定を超えるとそれ以上のダウン
ロード速度にならない問題が発生
ダウンロード速度が出ない① Problem!
C
© SEGA
• 受信バッファが満タンになった際に待ちが発生
 送受信処理をメインループに同期させていた為
ダウンロード速度が出ない① Cause
C
HTTP/2ライブラリ
受信処理
ゲームメインループ
同期 同期
受信バッファ満タン
パケット
受け取れないので待つ
© SEGA
• 受信を別スレッドに分離し、取りこぼしを抑制
ダウンロード速度が出ない① Solution!
C
HTTP/2ライブラリ
受信処理
ゲームメインループ
取得
パケット
受信バッファ
保存
© SEGA
ダウンロード速度が出ない②
C
S
クライアント事例
サーバ事例
© SEGA
• 前項の「通信速度が一定を超えるとそれ以上の
ダウンロード以上にならない問題」が特定の端
末でのみ再発
ダウンロード速度が出ない② Problem!
C
© SEGA
• 下位グレードの端末で以下の逆転現象が発生
 通信速度 > ファイルI/O速度
• 特にファイル I/O の回数がボトルネックに
ダウンロード速度が出ない② C Cause
© SEGA
• メモリマネージャの実装により解消
 一定のサイズまではメモリに書き溜めておく
 上記サイズを上回った段階でファイルに書き込む
• 一定のサイズの設定値には注意が必要
 大き過ぎるとこれまたボトルネックに
ダウンロード速度が出ない② Solution!
C
© SEGA
ダウンロード速度が出ない③
C
S
クライアント事例
サーバ事例
© SEGA
• 特定のタイトルでダウンロード速度が安定しな
い問題が発生
ダウンロード速度が出ない③ Problem!
C S
© SEGA
• 帯域を使い切ることができないケースがある
 リスト上に小さいファイルが固まっている時
ダウンロード速度が出ない③ C Cause
使用可能な回線帯域
ここが使えていない!
© SEGA
• ダウンロードリストの作り方を工夫する
 ランダムに入れ替えるだけでも効果あり
ダウンロード速度が出ない③
ここの部分を使えるようになった
Solution!
C
© SEGA
• ソートしてもダメなケース
ダウンロード速度が出ない③ C Cause
使用可能な回線帯域
(高速)
帯域次第で使い切れないケースが発生
© SEGA
• ファイルの同時ダウンロード数はサーバ固有
 HTTP/2的にはストリーム最大数と表現
 RFC的にはMAX_CONCURRENT_STREAMS
• クライアントとサーバで別
 お互い自分の受付可能なストリーム最大数を送り合う
ダウンロード速度が出ない③ C S Cause
© SEGA
• コネクション数を増やすことにより解決
 使用していたCDNのストリーム最大数が変更不可
• 最大3コネクションまで張る仕様とした
 300~400ストリームで安定感のある速度になった
 例 : 200Mbps ÷ 384 (stream) → 65kb (1filesize)
ダウンロード速度が出ない③ Solution!
C
© SEGA
主要なCDNのストリーム最大数
ダウンロード速度が出ない③ Appendix
S
Amazon CloudFront 128
Azure CDN 100
Google Cloud CDN 100
akamai 128
Fastly 100
Cloudflare 256
実測値 + 一部 https://netsec.ccert.edu.cn/files/papers/ndss-2020-cdn-judo.pdf を参考
© SEGA
• .Net 6のHTTP/2の機能でも同様の議論有り
 ストリームが上限に達したらコネクションを追加する
 https://github.com/dotnet/runtime/issues/35088.Net
ダウンロード速度が出ない③ Appendix
C
© SEGA
ダウンロード速度が出ない④
C
S
クライアント事例
サーバ事例
© SEGA
• 特定のタイトルでのみダウンロード速度が極端
に低下する問題が発生
ダウンロード速度が出ない④ Problem!
C
© SEGA
• ファイル処理負荷が高い構成だった
 1ディレクトリ下に大量のファイルを保存
 ハッシュ化した長めのファイル名を使用
ダウンロード速度が出ない④ C Cause
© SEGA
• 一時ファイルの処理を変更して回避
 専用のディレクトリを用意
 短いファイル名(内部的なリクエスト番号)
ダウンロード速度が出ない④ Solution!
C
© SEGA
速度出ない問題との闘いに終止符
© SEGA
ダウンロード速度が出すぎた
C
S
クライアント事例
サーバ事例
© SEGA
• とあるタイトルの大型アップデート時に、CDN
のデータ転送レート設定上限値を超える通信量
が発生することが判明した
ダウンロード速度が出すぎた Problem!
C S
© SEGA
• CDNによってはデータ転送レートに制限が掛
かっていることがある
• Amazon CloudFrontの旧制限は40Gbps (※)
 200Mbps出る端末の同時ダウンロード可能数
 40Gbps ÷ 200Mbps = 200 (端末)
ダウンロード速度が出すぎた S Cause
※2020/5/20に150Gbpsに更新された
© SEGA
• 混雑時間帯のみHTTP/1.1へダウングレード
• お金で解決するのも手
 制限があるCDNも転送レート上限の引き上げが可能
な所がほとんど
• CDN選定条件にデータ転送レートも考慮しよう
ダウンロード速度が出すぎた Solution!
C
© SEGA
ファイルオープンエラー発生
C
S
クライアント事例
サーバ事例
© SEGA
• タイトル側でファイル上限エラーが発生
• HTTP/2ライブラリは以下の80%を上限に使用
 Windows (VCRUNTIME) : _getmaxstdio
 Android/iOS : /proc/self/limits
ファイルオープンエラー発生 Problem!
C
© SEGA
• iOS11でファイルオープン上限数が256に
• 結果、タイトル側でファイルリソースが枯渇
 256 * 0.2 = 51 ファイル
ファイルオープンエラー発生 C Cause
© SEGA
• 上限数の変更を行う実装に修正
 setrlimit/getrlimitを使用
• タイトルのファイル使用上限を受け取るように
 setrlimit/getrlimitが効かない端末対策
• ファイルオープン数の削減
 オープンタイミングの見直し
ファイルオープンエラー発生 Solution!
C
© SEGA
ファイルのrenameに失敗
C
S
クライアント事例
サーバ事例
© SEGA
• 特定の端末でのみダウンロード完了後のファイ
ルのrenameに失敗する問題が発生
ファイルのrenameに失敗 Problem!
C
© SEGA
• Android11からExternalStorage境界をまたぐ
rename(POSIX)呼び出しが禁止
 Javaはコピー&削除にフォールバックされる
• 以下の境界をまたぐとNG
 PublicDirectory(Download), Cache, Files,
Files(Download), Media
ファイルのrenameに失敗 C Cause
© SEGA
• Android11でも必ず再現する訳ではない
• sdcardfs採用のカーネルでは発生しない
 cat /proc/filesystems の結果にsdcardfsがあれば発
生しない
ファイルのrenameに失敗 C Cause
© SEGA
• ファイルのrenameが失敗する端末ではコピー&
削除にフォールバック
• renameに比べパフォーマンスペナルティあり
 ExternalStorageの境界を跨がない設計をお勧め
ファイルのrenameに失敗 Solution!
C S
© SEGA
タイムアウトしない
C
S
クライアント事例
サーバ事例
© SEGA
• データを全くダウンロードできないにも関わら
ず、タイムアウトが発生しない問題が発生
タイムアウトしない Problem!
C S
© SEGA
• HTTP/2特有のコネクションクローズ問題
 コネクション切断時に送信されるGOAWAYフレーム
がロストしたことが原因と推測
• 複数のストリームが非同期に絡むのでHTTP/2の
コネクションクローズの実装は複雑となりがち
タイムアウトしない C S Cause
© SEGA
• 独自のタイムアウト処理を追加した
 タイムアウト判定時にはハンドシェイクからやり直し
• graceful shutdownに対応したサーバやライブ
ラリを使っていれば不要
 サーバ側が担保できなかったので独自に実装
タイムアウトしない Solution!
C S
© SEGA
iPhoneで通信中に不正終了
C
S
クライアント事例
サーバ事例
© SEGA
• ダウンロード中に極稀に不正終了が発生
 検証環境では7万回に一回程度発生
iPhoneで通信中に不正終了 Problem!
C
© SEGA
• 利用しているOSSの不具合だった
 HTTP/2のconnection reuse発生時に加えていくつか
の条件を満たした時のみ発生
 数千~数万ファイルを一気にダウンロードするのは
ゲームくらいなのでレアなものを踏む
iPhoneで通信中に不正終了 C Cause
© SEGA
• その後OSSの更新で無事に修正された
• HTTP/2のゲーム活用も枯れてきている
 他社の大型タイトルでも採用が増えてきた
iPhoneで通信中に不正終了 Solution!
C
© SEGA
HTTP/2独自の設定をしたい
C
S
クライアント事例
サーバ事例