CloudFrontでどんな形式のファイルでもgzip圧縮して配信するトリック / 転送量50%減！

**AWS CloudFront の仕様を突いてあらゆる形式のファイルをgzip圧縮するトリック**

前提として、CloudFront は CDN, gzip 圧縮はコンテンツを圧縮して配信することができる技術です。CloudFront は配信元のサーバーをキャッシュして配信できますが、自動的にコンテンツを gzip 圧縮したうえで配信させることもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/7e01b818-2f8f-4886-d9fd-20bd906a2545.png)

対象となるデータによりますが、通信量も減るし、速度も速くなるのでとても素晴らしい技術なのです。

CloudFrontは特定のファイル形式に対して自動的にgzip圧縮を行いますが、すべての形式に対応しているわけではありません。この記事では、CloudFrontの仕様をうまく利用して、**あらゆる形式のファイルをgzip圧縮し、転送量を劇的に削減するテクニック**を紹介します。

## なぜあらゆるファイル形式をgzip圧縮する必要があったのか？

「なぜそんなことをする必要があるのか？」

昨年、私はブラウザで遊べる「 **ブラウザ版レッドストーン** 」というプロジェクトを開発しました。「REDSTONE」という無料オンラインゲームは、元々は1GB以上のインストーラーをダウンロードし、インストールしないと遊ぶことができないPCゲームです。

**それをほぼすべて JavaScript で書き直し、ブラウザに移植するという挑戦的な試みでした。**

実際にどのようなものを作ったのかは以下の記事を御覧ください。

開発記事

https://note.com/newyorkgal/n/n7ae81b6419f4

プロジェクトのソースコードも全部公開してます

Github: https://github.com/LostMyCode/redstone-js

https://github.com/LostMyCode/redstone-js

[ブラウザ移植版プレイ動画](https://youtu.be/mP9C9k2_3t0)

<iframe width="560" height="375" src="https://www.youtube.com/embed/mP9C9k2_3t0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

しかし、先にも述べたようにこのゲームはもともと１GB以上のインストーラーをPCにダウンロードし、インストールしてはじめて遊ぶことができるゲームです。

#### これをブラウザで完全再現するためには？

そうです！結局ブラウザで表示できるためにはグラフィックを描画するためのキャラクターやゲームマップのテクスチャをすべて取得して読み込む必要があるわけです。

つまり、このゲームをブラウザで表示する裏で大量のファイルをfetchしているわけです。

実際にゲームをロードするときにネットワークタブをみると比較的サイズが大きいテクスチャやマップデータを取得しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/19d2fff3-a6b4-b30b-f1a7-35887a395186.png)

基本的にゲームで使われているテクスチャファイルやその他のデータファイルは独自のバイナリ形式で格納されています。

レッドストーンではキャラクターやアイテムの画像データやアニメーションデータは、独自のバイナリ形式（.sad、.sdなど）で保存されており、CloudFrontの標準的なgzip圧縮対象外でした。

ファイルサイズが大きいため、そのまま配信すると読み込み時間が長くなってしまうという課題がありました。

CloudFront では当然ながらこれらの形式に対応しておらずそのまま配信してもキャッシュされるだけで gzip 圧縮されて配信されることはありません。

### 解決策：すべてのゲームファイルの拡張子を `.txt` にする

そこで私がとった解決策は、**すべてのゲームデータファイルの拡張子を`.txt`に変更すること**でした。

 `.txt` という拡張子を加えてみるとどうでしょう？

 「拡張子を変えるだけで何が変わるの？」と思うかもしれません。

 before:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/105f8586-3d55-bb34-3856-95218b7a94bd.png)


after:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/8ddc643e-c959-09f0-7c5d-e1490f6a4eeb.png)


なんということでしょう。

配信されるファイルの転送サイズが大幅に減っているではありませんか！

そうです、拡張子を変えるだけであらゆる形式のファイルでも gzip 圧縮処理の対象とすることができるのです。

CloudFront で gzip 圧縮対象のファイル形式一覧

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html#compressed-content-cloudfront-file-types

公式ドキュメントに記載されている対応ファイル形式の拡張子に書き換えるだけで gzip 圧縮の対象となります。

「そもそも拡張子を変えることはいかがなものか」という意見もあるでしょうが、今回は独自のゲームファイルであり、バイナリデータを読み取って処理する部分は完全に独自実装なので、ファイル形式がなんであろうが中身さえ同じであれば支障はないのです。

マップデータ、アニメーションデータ、オブジェクトデータなどあらゆるゲームデータファイルの拡張子に `.txt` を加え、gzip 圧縮させてしまうことにしました。

## gzip圧縮の効果：転送量50%減！

このシンプルなテクニックによって、驚くべき効果が得られました。

配信されるファイルサイズのトータルはどうなったでしょうか？

**圧縮せずに配信**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/7002fe40-19bc-0be9-eefd-089bc26cbe1b.png)

転送量: 48.5 MB


**gzip圧縮後**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/9eb8539b-4940-c44c-5dfc-886c5277b507.png)

転送量: 22.9 MB 


48.5 MB から 22.9 MB に削減されたので、削減された転送量は 48.5 MB - 22.9 MB = 25.6 MB です。

```
 (25.6 MB / 48.5 MB) * 100% ≈ 52.8% 
 ```

gzip圧縮によって約 **52.8%** の転送量削減に成功しました。

転送量を50%以上削ることができたのでかなり効果がありますね！

処理時間はあまり参考にならない（before, after それぞれ別サーバーから配信しているため）ですが、大幅に短縮され、ユーザーエクスペリエンスの向上に大きく貢献しました。

ファイル拡張子を `.txt` にするだけでこれだけの効果があったのでかなりデカいです！

**ファイルサイズの変化**

before: (サイズ大きいけど CDN 経由なので謎に爆速ｗ)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/538e8285-4f5e-87fb-7618-59f75b07d568.png)

after: (拡張子を `.txt` に変えて CloudFront による gzip 圧縮で配信)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/d898d2bc-be29-1229-a872-5ac7567ee669.png)

逆に今回これだけ効果が出たのは、レッドストーンのゲームデータ構造があまり最適化されていないからっていうのも判明してしまいましたね笑

実際、ほとんどのファイルはアニメーションや画像データですが、解析をすると画像のビットデータが圧縮されずにそのままほとんど生の状態で格納されています。そりゃ大きいサイズのファイルができちゃいますよね。

この非圧縮状態が大きなファイルサイズの原因となっており、gzip圧縮を適用することで劇的な効果が得られました。

## まとめ：シンプルながらも効果的なテクニック

今回のケースは特殊な例かもしれませんが、「ファイルサイズを小さくしたい」「CloudFrontでgzip圧縮を活用したい」というニーズは少なくないはずです。拡張子`.txt`を利用したgzip圧縮は、シンプルながらも非常に効果的なテクニックです。ぜひあなたのプロジェクトでも試してみてください。

今回紹介したプロジェクト（PCゲームをブラウザ移植する）もお見逃し無く！

https://note.com/newyorkgal/n/n7ae81b6419f4

### 参考記事 & 画像引用元:

- [What is GZIP Compression?](https://bunny.net/academy/http/what-is-gzip-lossless-compression/)
- [【AWS】Amazon CloudFrontの理解〜高速配信機能編](https://qiita.com/kiton/items/6b5294cabe19e13da4d6)
- [レッドストーン ブラウザ移植版](https://github.com/LostMyCode/redstone-js)