Qiitaの記事画像が最適化され、35%転送量が削減されました

## 概要

- 画像用CDNを [imgix](https://www.imgix.com/) にCloudFrontから移行した
- CDNの総転送量を35%削減した
- PageSpeed Insightsで記事ページが15~20点改善した

## 以前までの画像の配信基盤

![qiita-camo](https://www.plantuml.com/plantuml/png/0/PP11ImD138Nl-HMFlU_suAs7Kgm8dWIbNaHAt4cxGtTcQYQBYFZVdMrnhVKIGbxUbqUMsLXj23tUl3UkMmw9Y5jBYYSlxwBKzcbmM8trLbCqsYe7mGFxFkEJ0Dv9DAn6vnVHoOLwSMxvRO_2yKWkDueLrUFLvdfezsBL2QVcjoK1xaAH2p8c4wZVTOOvreS-iHE7rmyCMJIVWUwj4ztSfC0-vWjOrPaTydmsQvgc-YVyp4l-CTmOSaerJVxWYQO5rC-TTqxYYwilbvOINVdkDm00 "qiita-camo")

今まではAmazon CloudFrontをCDNとして画像を配信していました。Rails上ではHTTPS化のためのProxyとして[camo](https://github.com/atmos/camo)を動作させており、camoがURLをハッシュ化してユニークなPathを生成します。

この構成の課題は、「記事中の画像がまったく最適化されていなかった」ことです。記事にもよりますが、数MBの画像が何十枚も使われているケースがあり、特にモバイルユーザーに対しての体験がよくありませんでした。

最適化の手法として「記事中で使用している画像を全てS3に最適化して保存する」といったことも考えましたが、変更に柔軟なシステムではありません。というのも、「画像の品質をより落としたい」となればS3にある画像全てに対して再度最適化を行い、URLの移行作業をする必要があるためです。そこでimgixを最適化のシステムとして採用しました。

## imgixを使った現在の基盤

![qiita-camo](https://www.plantuml.com/plantuml/png/0/SoWkIImgAStDKIZCp2n9r4rEpCtduafCBialKWZBJ2rFBU9ApialJL7mp4tFh8XtTl7ZueA8A-ZQ8Gj2L2c5foOfALHpAIW0JSrC0vgZe9HHKb9GRAMlhwUdfuGX0HElvUA26mOo6MWE5vT3QbuAq6a0 "qiita-camo")

imgixは画像の最適化をURLパラメーターから行えるCDNです。
imgixはオリジン画像のソースとして、S3などの他に「[Web Proxy](https://docs.imgix.com/setup/creating-sources/web-proxy)」を提供しており、camoのような役割も担うことができます。QiitaではWeb Proxyを使い、これまで通りS3や他ドメインのURLをパスとしたものを配信しています。

## Qiitaのimgix料金について

imgixでは、Enterprise向けとして[Volume Pricing](https://www.imgix.com/pricing)を用意しています。QiitaはVolume Pricingとして1年間契約しています。注意点として、imgixでgifを扱うにはVolume Pricingプランである必要があります。

一ヶ月のフリートライアルを用いて見積もりを行いましたが、既存のCloudFrontのインフラ費用との差額を考慮すると、得られるパフォーマンスが期待を上回っていたため、imgixとの契約を行いました。その他の理由は後述します。

### サポートは英語のみ
imgixのサポートは英語のみです。Volume Pricingの交渉なども全て英語で行う必要があります。
またVolume Pricingを契約すると専属のサポートがつくのですが、Volume Pricingの交渉を行う前でも、サポートの対応が非常に早く丁寧です。

## なぜimgixを選んだか
画像の最適化を行えるCDNとして、「[Fastly Image Optimization](https://www.fastly.com/products/web-and-mobile-performance/image-optimization)」や「[Cloudflare Image Resizing](https://blog.cloudflare.com/announcing-cloudflare-image-resizing-simplifying-optimal-image-delivery/)」などがあります。
これらのCDNも、画像のリサイズやWeb対応ブラウザへの自動変換は行えますが、なぜimgixを選んだかは以下のような理由があります。

- 他のCDNに比べて様々なAPIが用意されている
    - [Multi-line Text & Overlays](https://docs.imgix.com/tutorials/multiline-text-overlays-typesetting-endpoint)のように組み合わせることで柔軟に画像加工することが可能
- ドキュメントが豊富でサンプル画像やコードがしっかりと書かれている
    - https://docs.imgix.com/apis/url
- 既存のインフラ費用との差を考えてコストパフォーマンスが十分に高かった
- [一休.com](https://user-first.ikyu.co.jp/entry/2018/07/02/070000)や[日経新聞](https://logmi.jp/tech/articles/282375)での実績があった
- もともと[Qiita Jobsでも利用していた](https://qiita.com/hareku/items/cfa2ccef7ff9a8b9c5d2)

本来はいくつかのCDNで見積もりを取るべきですが、「1年契約である」「他に移行するとしてもimgixが負債にならない」といった点や、現状の開発リソースを踏まえてimgixを選択しました。

## 技術的な対応
### 初回アクセスのキャッシュ対応
imgixへの初回アクセス（キャッシュ未生成時）はやはりレスポンスが遅いです。通常のpngやjpgの場合は2~3秒でレスポンスが返ってきますが、gifなどの場合は10秒以上掛かることがあります。

記事中の画像が10秒以上見れないのは、ユーザーにとって体験が良くありません。そのため記事投稿中のプレビューや、記事投稿直後は、前構成であるCloudFrontを使って配信し、投稿後にimgixのURLへの差し替えをキューで処理します。キュー処理の際にimgixの画像URLへHEADリクエストを送り、キャッシュ生成を行います。

### `?auto=compress`は使わない
https://docs.imgix.com/apis/url/auto/auto#compress

imgixでは`?auto=compress`を付けることによってベストエフォート型の手法を用いて画像を最適化してくれます。しかしこのパラメーターは、Webp未対応ブラウザにはgifをpng8に変換して配信してしまいます。
Qiitaでは、画像に関する記事（png8とpng24を比較するなど）も存在するため、`?auto=compress`は使わずに、`q`（品質）パラメーターを固定設定しています。

## まとめ
`srcset`の使用やgifのmp4変換など、まだまだ最適化できそうな点はありますが、単純に最適化を行うだけで35%もの転送量を削減できました。
また記事によりますが、PageSpeed Insightsでもスコアが15~20点ほど改善しています。

画像最適化にimgixを検討してみてはいかがでしょうか。