「HOT PEPPER Beauty」美容クリニックにおける画像アップロードシステム
川村 一斗
HOT PEPPER Beauty の美容クリニックのカウンセリング予約ができるサービス(以降 美容クリニック)にて SRE を担当している川村です。 もともとは美容クリニックにおいてバックエンドを担当していたのですが、2020年4月から SRE を担当しています。
本記事では美容クリニックにてクリニック情報を入稿するための社内システムにおいて利用している画像アップロードのシステム設計について紹介します。 画像アップロードは一般的な Web サービスにおいて当たり前の機能の一つではありますが、美容クリニックでは画像アップロード要件などの兼ね合いから少し複雑なシステム設計を行っております。 美容クリニックにおける画像アップロード要件と併せて、画像アップロードシステムの設計意図をお伝えできればいいなと思います。
美容クリニックのシステム概要と画像アップロード要件
本題に入る前に、美容クリニックの Web アプリケーションのアーキテクチャをおさらいしましょう。 こちらの記事 にもあるように、美容クリニックの Web アプリケーションはフロントアプリケーションと API アプリケーションに分かれており、それぞれが責務を分担していました。 さらに、クラウドサービスとして AWS を採用しています。
本記事で紹介する画像アップロードシステムは、以下のようなクリニックページに表示されている画像を登録する際に利用されています。
上記のクリニックページはクリニック情報を入稿する社内システムを利用して入稿されたデータによって構築されています。 この社内入稿システムの機能の一つに本記事で紹介する画像アップロードが存在しています(下記イメージ参照)。
では、社内入稿システムにおいて以下の画像アップロード要件を実現することを考えてみましょう。
画像アップロード要件
入力画面でアップロード画像を選択 → 画像をサムネイル表示 → 登録の 3 ステップ構成で画像をアップロード(下記イメージを参照)
入力画面にてアップロード画像を選択するのと同期的に画像に対するバリデーションを実施(ex. 画像の拡張子、サイズ、etc.)
バリデーションが OK だった画像のみ、入力画面にてサムネイル表示。 サムネイル表示する画像は EXIF 情報の削除、カラープロファイルの保持や回転処理等の画像加工処理を実施済みであること。
画面に関しては、よくある画像アップロード機能が埋め込まれたフォーム画面をイメージしていただけるとわかりやすいかと思います。
上述の画像アップロード要件によって以下のような懸念点が考えられます。
- 画像アップロード要件の 2 と 3 は同期的に画像バリデーションと画像加工処理を実施する必要がある(画像に対する非同期処理が採用できない)ため、結果としてレスポンスタイムが悪化する
- 画像処理により、サーバの負荷が高騰する(既存の別プロダクトにおける画像アップロードシステム内でサーバの負荷高騰が発生していた)
このような懸念点も考慮しながら画像アップロードシステムを何度も設計&レビューし、結果として以降で説明していく設計を採用しました。
画像アップロードシステム設計
前節の画像アップロード要件をどのように実現しているのか、要件 1 に記載の 3 ステップに沿って画像アップロードシステムを紹介していきます。
入力画面でアップロード画像を選択 → 画像をサムネイル表示
早速ですが、入力画面でアップロード画像を選択 → 画像をサムネイル表示
のステップにおける画像アップロードシステムの利用イメージ図を以下に示します。
上図に示した各処理ステップと画像アップロードシステムにおいて登場する各種コンポーネントの役割を以下にまとめていきます。
① 入力画面にてアップロード画像を選択 / ② 1次 S3 に画像をアップロード
ブラウザから画像データを POST
し、フロントアプリケーションがリクエストを受け取ります。
その後フロントアプリケーションは AWS SDK for Java を利用し、1次画像保存用の S3 に画像を格納します。
1次画像保存用の S3 にはライフサイクルポリシーを設定し、定期的に画像のパージ処理を実施しています。
フロントアプリケーションの代わりに AWS API Gateway を利用することも考えられますが、ペイロードサイズの制限を考慮してフロントアプリケーションを利用することにしています。
③ 画像バリデーションと画像加工を並列処理
1次画像保存用の S3 に画像を格納した後、フロントアプリケーションは2つの AWS Lambda 関数(以降 Lambda 関数)を並列に呼び出します。 一つは1次画像保存用 S3 に格納した画像に対して画像バリデーションを実施、もう一つは1次画像保存用S3に格納した画像に対して EXIF 情報の削除等の画像加工を実施します。 この2つの Lambda 関数によって上述した画像アップロード要件の 2 と 3 を実現しています。 また、1次画像保存用 S3 を用いることで並列処理を実現し、懸念点の1つにあった画像に対する同期処理によるレスポンスタイムの悪化を解消しています。
それぞれの Lambda 関数のランタイムは Ruby、画像処理には ImageMagick の wrapper である Mini Magick を採用しています。 画像バリデーションと画像加工処理を AWS Lambda というサーバレスアーキテクチャに寄せてフロントアプリケーションと切り離すことで、もう1つの懸念点であるサーバの負荷高騰を解消することを狙って設計しました。
画像加工を実施する Lambda 関数では、加工処理完了後に処理済みの画像を2次画像保存用 S3 に格納します。 2次画像保存用 S3 に格納された画像は、入力画面でアップロード画像を選択した後に画像のサムネイル表示をするために利用されます。 1次画像保存用 S3 と同様に、2次画像保存用 S3 においてもライフサイクルポリシーを設定し、定期的に画像のパージ処理を実施しています。 1, 2次画像保存用 S3 に格納されている画像は永続化前の画像と見なし、定期的なゴミ掃除を実施しているイメージです。
④ 2次 S3 にアップロードされた画像をサムネイル表示
2つの Lambda 関数の処理完了後、フロントアプリケーションは2次画像保存用 S3 に格納された加工処理済み画像の URL をブラウザに返却します。 ブラウザは返却された URL を利用してサムネイル画像を表示します。
入力画面でアップロード画像を選択 → 画像をサムネイル表示のまとめ
以上が 入力画面でアップロード画像を選択 → 画像をサムネイル表示
における各処理ステップと画像アップロードシステムにおいて登場する各種コンポーネントの役割です。
各種コンポーネントの役割を簡単にまとめると以下の表のとおりです。
コンポーネント | 技術スタック | 役割 |
---|---|---|
フロントアプリケーション | Spring Boot on Fargate | 画像アップロードリクエストを受け取り、S3 と Lambda 関数を用いてサムネイル表示用の加工処理済み画像の URL をブラウザに返却する。 |
1次画像保存用 S3 | Amazon S3 | 後述の2つの Lambda 関数が並列処理できるようにフロントアプリケーションが受け取った画像を格納する。 |
2次画像保存用 S3 | Amazon S3 | 加工処理済みの画像を格納する S3。この S3 に格納された画像を画像アップロード時のサムネイル表示に利用する。 |
画像バリデーション用 Lambda 関数 | AWS Lambda, Ruby, ImageMagick | 画像アップロード要件 2 にあるバリデーション処理を実施する。 |
画像加工処理用 Lambda 関数 | AWS Lambda, Ruby, ImageMagick | 画像アップロード要件 3 にある EXIF 情報を削除等の加工処理を実施する。 加工処理完了後に2次画像保存用 S3 に加工処理済み画像を格納する。 |
画像をサムネイル表示 → 登録
続いて、画像をサムネイル表示 → 登録
のステップにおける画像アップロードシステムの利用イメージ図を以下に示します。
上図に示した各処理ステップと画像アップロードシステムにおいて登場する各種コンポーネントの役割を以下にまとめていきます。
⑥ 2次 S3 の画像を公開用 S3 にアップロード
入力画面にて登録ボタンを押下後、フロントアプリケーションがブラウザから POST
されたリクエストを受け取ります。
フロントアプリケーションは先述した2次画像保存用 S3 に格納されている加工済み画像を公開画像保存用 S3 にアップロードし直します。
公開画像保存用 S3 に格納された画像は社内入稿システムだけではなく、一般のユーザが利用する美容クリニックにおいて公開されます。
1, 2次画像保存用 S3 とは違い、公開画像保存用 S3 ではライフサイクルポリシーを設定せず、別途画像のパージ処理を実施するようにしています。
まとめ
以上が美容クリニックにおける画像アップロードシステムの概要になります。 筆者がクラウドサービスへの馴染みが少なかったこともあり、かなりピタゴラスイッチ的なシステム設計になってしまったかもしれません。 しかし、当初の2つの懸念点については
- 画像アップロード要件の 2 と 3 は同期的に画像バリデーションと画像加工処理を実施する必要がある(画像に対する非同期処理が採用できない)ため、結果としてレスポンスタイムが悪化する
→ 1次画像保存用 S3 を用いることで並列処理を実現し、画像に対する同期処理によるレスポンスタイムの悪化を解消
- 画像処理により、サーバの負荷が高騰する(既存の別プロダクトにおける画像アップロードシステム内でサーバの負荷高騰が発生していた)
→ 画像バリデーションと画像加工処理を AWS Lambda というサーバレスアーキテクチャに寄せてフロントアプリケーションと切り離すことでサーバの負荷高騰を解消
といったようにそれぞれ対応することができました。
それ以外にも S3 のライフサイクルポリシーを利用してゴミ画像のパージ処理を簡素化できたことにもメリットを感じています。
さいごに
本記事では美容クリニックにおける画像アップロードシステムを紹介いたしました。 画像アップロードシステムは多種多様な設計が考えられますが、要件を満たすために最適なシステム設計を泥臭く考え抜くことが一番大切なポイントだと思っています。
美容クリニックでは、このようなクラウドサービスを利用したシステム設計や自分も担当している SRE としてサービスに関われる環境が揃っています。 興味がある方がいらっしゃいましたら、ぜひ採用ページを御覧ください。
引用
- "オブジェクトのライフサイクル管理",https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/object-lifecycle-mgmt.html,(参照 2020-06-22)
- “Amazon API Gateway のクォータと重要な注意点”,https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/limits.html,(参照 2020-06-22)
- “ImageMagick - Convert, Edit, or Compose Bitmap Images”,https://imagemagick.org/,(参照 2020-06-22)
- “GitHub - minimagick/minimagick: mini replacement for RMagick”,https://github.com/minimagick/minimagick,(参照 2020-06-22)