Serverless IIIF で1Gピクセル級の高精細画像を配信するときに行った最適化のノート
1Gピクセル級の高精細画像(PTIF 約450MB)を AWS Lambda 上の Serverless IIIF で配信するにあたり、エンコード、Lambda、CloudFront、S3 メタデータの観点で行った調整の記録です。
iiifserverless-iiifaws-lambdacloudfrontptiflibvipss3
台本(フルテキスト)
動画の掛け合いを書き起こしたものです。音声を再生しづらい場合はこちらをお読みください。
オープニング
- Serverless IIIF で大判高精細画像を配信
- エンコード・Lambda・CloudFront・S3 メタデータの調整記録
- めたん
- こんにちは。今日は Serverless IIIF で大きな高精細画像を配信したときの最適化の記録を紹介しますね。
- ずんだもん
- サーバレス IIIF って何なのだ?
- めたん
- IIIF は画像を相互運用するための規格で、Serverless IIIF はそれを AWS Lambda の上で動かす実装よ。
- ずんだもん
- なるほど。それで何が困ったのだ?
- めたん
- 扱う画像が 4万9千かける2万8千ピクセルと大きくて、レンダリングのタイムアウトや 429 エラーが出たの。
- ずんだもん
- それは大変なのだ。どう直したのか知りたいのだ。
PTIF が縮まない問題
- JPEG から作った PTIF がほぼ縮まない
- Q 値 90 以上だと RGB 保存になる libvips の挙動
- めたん
- まず画像形式の PTIF、ピラミッド TIFF を作ったんだけど、元の JPEG とほぼ同じサイズにしかならなかったの。
- ずんだもん
- 圧縮したのに縮まないのは変なのだ。
- めたん
- 原因は色の保存方式。tiffinfo で見たら、速いファイルは YCbCr、遅いファイルは RGB で保存されていたの。
- ずんだもん
- その違いでそんなに変わるのだ?
- めたん
- YCbCr なら色差を四分の一に圧縮できるの。犯人は vips の挙動で、Q 値が 90 以上だとサブサンプリングをやめて RGB になるのよ。
- ずんだもん
- じゃあ Q 値を下げればいいのだ?
- めたん
- そう。Q を 85 にして、タイルを 512 にしたら、3 ファイル合計が 4232 メガから 1158 メガまで縮んだわ。
Lambda のタイムアウト
- デフォルト 10 秒では初回レンダリングが間に合わない
- Timeout を 30 秒に変更
- ずんだもん
- ファイルを小さくしたら速くなったのだ?
- めたん
- それでもレンダリングが時間内に終わらなくて、タイムアウトのエラーが返ってきたの。
- ずんだもん
- どれくらいで切られていたのだ?
- めたん
- Lambda のタイムアウトはデフォルトが 10 秒なの。初回の大きなレンダリングはこれを超えてしまうのよ。
- ずんだもん
- じゃあ伸ばせばいいのだ。
- めたん
- ええ。30 秒に変更したわ。CloudFront がエラーレスポンスをキャッシュしてしまう問題もあったから、これは大事ね。
S3 メタデータで寸法を渡す
- 毎リクエストで IFD を二重パースしていた
- S3 メタデータに width / height を入れると info.json が 86 倍速く
- めたん
- 次にログを見たら、毎回 sharp.metadata にフォールバックする警告が出ていたの。
- ずんだもん
- フォールバックって、何が起きているのだ?
- めたん
- Lambda が画像の寸法を知るために、毎回 PTIF の目次、IFD を S3 から読み直していたの。これに 5 秒近くかかるのよ。
- ずんだもん
- 5 秒は長いのだ。どうにかならないのだ?
- めたん
- Lambda のコードを読んだら、S3 オブジェクトのメタデータに幅と高さがあれば、それを即座に使う仕組みがあったの。
- ずんだもん
- じゃあメタデータを入れればいいのだ。効果はあったのだ?
- めたん
- info.json は 4.3 秒から 0.05 秒になったわ。86 倍ね。レンダリングも 2 秒から 3 秒短くなったの。
メモリは 10GB も要らない
- メモリを増やしても速くならない
- ボトルネックは CPU ではなく S3 の入出力
- ずんだもん
- 速くしたいならメモリをたくさん積めばいいのだ?
- めたん
- それを期待して 10 ギガバイトにしてみたんだけど、ほとんど変わらなかったの。
- ずんだもん
- えっ、メモリは効かなかったのだ?
- めたん
- ええ。2 ギガバイトに下げても所要時間はほぼ同じ。実際のメモリ使用量は 600 メガ程度だったわ。
- ずんだもん
- どうして増やしても速くならないのだ?
- めたん
- ボトルネックが CPU ではなく、S3 からデータを取ってくる入出力だったからよ。だから 2 ギガで十分なの。
429 エラーと同時実行制限
- x-amzn-errortype は Lambda の同時実行制限超過
- Reserved Concurrency を 50 から 200 へ
- ずんだもん
- さっき言っていた 429 エラーは何だったのだ?
- めたん
- レスポンスヘッダに TooManyRequests と出ていて、これは Lambda の同時実行制限に達したサインなの。
- ずんだもん
- 同時実行制限はいくつだったのだ?
- めたん
- 50 だったの。1 リクエストが 5 秒から 7 秒かかるから、1 秒あたり 10 件くらいしか捌けない計算ね。
- ずんだもん
- ビューアがタイルをたくさん要求したら足りないのだ。
- めたん
- そう。だから同時実行数を 200 に増やしたの。これで 100 を超えてもエラーは出なくなったわ。
CloudFront キャッシュと所要時間の傾向
- タイルは不変なのでキャッシュ TTL を 1 年に
- レンダリング時間はファイルサイズに比例
- めたん
- あとは CloudFront のキャッシュね。タイル画像は内容が変わらないから、TTL を 1 年まで伸ばしたの。
- ずんだもん
- 1 年もキャッシュして大丈夫なのだ?
- めたん
- ええ。一度生成したタイルは 50 ミリ秒くらいで返るし、Lambda も呼ばれないからコストも下がるの。
- ずんだもん
- 初回のレンダリングはどれくらいかかるのだ?
- めたん
- 計測したら、レンダリング時間はピクセル数よりファイルサイズに比例していたの。200 メガ未満なら 2 秒から 3 秒ね。
- ずんだもん
- 大きいファイルはやっぱり遅いのだ?
- めたん
- 400 メガを超えると 5 秒から 7 秒かかるわ。ここは sharp が目次を読む時間で、Lambda の構成では削りにくいの。
まとめ
- PTIF は Q89 以下・YCbCr・512 タイル
- Lambda は Timeout 30 秒・メモリ 2GB・同時実行 200
- ずんだもん
- 今日のポイントを整理してほしいのだ。
- めたん
- PTIF は Q を 89 以下にして YCbCr で保存、タイルは 512。S3 にはメタデータで幅と高さを入れる。
- めたん
- Lambda はタイムアウト 30 秒、メモリは 2 ギガで十分、同時実行はビューアに合わせて見直す。
- ずんだもん
- CloudFront のキャッシュも長めにするのだったのだ。
- めたん
- そうね。さらに速くしたいなら、Cantaloupe を常駐サーバとして動かす構成も選択肢になるわ。
- ずんだもん
- よく分かったのだ。ありがとうなのだ!