結論
速度・省リソースの観点ではこれが良い。
背景
10年もののシステムを運用しています。
画像を扱うサービスなのですが、画像ファイルが相当数になって、ファイルサイズの合計が peta byte にとどこうとしています。
ここまでくると、Storageの費用がかなり目立ちます。
画像の表示速度が遅くなることはビジネス要件として許容しにくく、ストレージを低速なものに変えにくいです。
一番量が多い画像の種別は大きさ違いで同じものを扱っている画像でした。
(メインのドメインの画像を大きさごとに物理的に3種類)
なので、
その種別の画像は1枚のみ管理して他の大きさの画像を削除して1種類のみ管理することで、ストレージのディスクサイズを減らすことで費用削減効果が期待できました。
(細かい話は割愛)
1種類のみ管理するために他の大きさの画像は動的に生成することでそれが実現できます。
(他にも色々対策ありそうですが、細かい話は割愛)
つまり、
画像の大きさを動的に生成する必要がありました。
動的リサイズ: https://engineering.mercari.com/blog/entry/2018-01-30-161001/
上記の内容に近いです。
ヘイシャにもwebp変換のニーズがありましたが、一旦スコープアウトとなりました(それを見据えた設計にする)
これや、他のサービスも検討候補に上がりましたが、
弊社の事情があって、自前で用意した方が安くなりそうだったので、自前で用意してみることになりました。
画像リサイズのライブラリ比較検証
有名なのは ImageMagick, OpenCVです。
処理速度・省リソースを考慮して検証した結果、libvipsが良さそうです。
https://www.libvips.org/
検討した技術
- Go
- Go標準ライブラリ
- GoCV(OpenCVのラッパー)
- gopkg.in/gographics/imagick.v3/imagick(ImageMagicのラッパー)
- bimg(vipsのラッパー)
- govips(vipsのラッパー)
- JavaScript
- Sharp(vipsのラッパー)
- Python
- Pillow
- OpenCV
- pyvips(vipsのラッパー)
- Java
- thumbnailator
当初、AWS Lambdaにのせることを検討していたので、
Lambdaで実装して、処理速度と画質を比較検証しました。
どのライブラリもコード(+Doc)が読みやすいので、実装しやすいです。
色々細かい調整をしてみたのですが、
省メモリ環境を考慮していたので、bimgが最も性能良い(最も早く、画質も圧縮もいい感じ)という結論になりました。
一応、サービスインできそうな形にはできたものの、
AWSLambdaの最低メモリ割り当て数 128MB では、サービス運用に支障が出そうでした。
メモリ割り当てを調整した結果、1500MB くらい割り当てすることが好ましいという結果になりました。
アーキテクチャ検討
当初、AWSのCloudFront+S3ObjectLambdaの利用が候補に上がっていました。
しかし、ヘイシャではKubernetesでサービスを運用していて、コンピュートリソースが余っていたので、
コンテナ上で動的リサイズするとどうなるのか、という検証を行うことになりました。
サーバ立てて動的リサイズを行う方法で以下を検証しました
- Nginxでリサイズ(image filter module)
- imgproxy (vipsを利用してhttpで画像をリサイズするアプリケーション)
どちらもドキュメントが充実していてシンプルなので実装しやすいです。
コンピュートリソースを潤沢に使えるのであれば、
imgproxy を利用するのが、楽で、処理速度も早く、色々な処理ができます。
結果的には以下のアーキテクチャが良さそうという結論になりました
CDN -> AppServer(Kubernetes上でimgproxyのコンテナ)
画像周りのリクエストはかなり多くなると思われるので、
LB分けておいた方が被害少なくなる+監視しやすくなるでしょう。
切り替えはDNSの重みづけで徐々に流していくことができますし、
やっぱり自前で立てておくほうが良いなーと思ってます。
サービスインはこれから。
一旦覚えているうちにアウトプット。
技術検証させてくれるチームと会社に感謝