学習コンテンツテック企業求人ブログ面接対策サポート

SystemDesign InterviewCat

トップ

01 SystemDesign InterviewCat

はじめに

02 イントロダクション03 SystemDesign InterviewCat対象読者04 システムデザイン面接のコンプリートガイド

Discordサポートについて(購入者特典)

05 Discordサポート(購入者特典)

基礎 - コミュニケーション

06 リクエストを送信(HTTP)07 サーバー側の更新をリアルタイムに受け取る(Polling / Long Polling / SSE)08 リアルタイム双方向通信(WebSocket)09 サービス間通信の設計10 Pub/Subで複数のサービスにメッセージ配信

基礎 - スケーラビリティ

11 垂直スケーリングと水平スケーリング12 オートスケール13 ロードバランサーでリクエストを負荷分散14 データベースレプリケーションによるクエリの分散15 パーティショニングによるスケーラビリティの向上16 Consistent Hashing(コンシステントハッシュ法)17 メッセージキューによるスケーラビリティの向上18 ステートフル接続に対してスケーラブルな設計を行う

基礎 - パフォーマンス

19 ネットワークレイテンシを改善する20 キャッシュを使ったパフォーマンスを向上21 CDNによる静的コンテンツのキャッシュ22 CDNによる動的コンテンツのキャッシュ23 インメモリデータベースを使ったキャッシュ24 並列分散処理によるパフォーマンス向上25 データベースインデックス26 スロークエリ分析と最適化

基礎 - 可用性、耐障害性、信頼性

27 冗長化とフェイルオーバーによるシステムを切り替え28 レプリケーションによる耐障害性、可用性の向上30 オブジェクトストレージによる非構造化データの耐久性の向上

基礎 - 可用性、耐障害性、信頼性

29 ログによるデータベースの耐障害性の向上31 リクエストのリトライ設計について32 サーキットブレーカーでリトライによる過負荷を防ぐ33 メッセージキューによる信頼性向上34 大量のリクエストを制限する

基礎 - トランザクション、分散システム

35 データベーストランザクション36 データベースロックを使って排他制御を行う37 長時間のトランザクションへ分散共有ロックを活用する38 CAP定理と整合性モデル39 マイクロサービス間のトランザクションの整合性を維持する40 メッセージキューとデータベースの書き込みを同一のトランザクション内で実行する41 API Gatewayでマイクロサービスの入口を作る42 コーディネーションサービスを活用した分散システムの管理43 分散システムでユニークIDを設計する44 ファイルをオブジェクトストレージにアップロードする

基礎 - アプリケーション設計パターン

45 遅延キューを使って処理を遅らせる46 ページネーションを設計する47 全文検索を導入する48 ユーザーを認証・認可する49 SaaSのマルチテナントを設計する

基礎 - ビックデータ処理

50 大量のイベントデータをバッチ処理する51 大量のイベントデータをストリーム処理する52 アナリティクス用のデータベースを活用する

応用問題

53 画像アップロードサービスの設計54 LINE(リアルタイムチャット)の設計55 YouTube Liveコメントサービスの設計56 チケット予約サービスの設計57 X/Twitterの設計58 X/Twitterリアルタイム検索の設計59 Dropboxの設計60 AtCoderコンテストの設計61 LinkedIn求人アラートサービスの設計62 Googleアナリティクスの設計

Appendix

63 アプリケーション監視について考える
© 2026 InterviewCat. All rights reserved.
プライバシーポリシー利用規約特定商取引法に基づく表記運営お問い合わせフォーム
  1. 学習コンテンツ
  2. SystemDesign InterviewCat
  3. 画像アップロードサービスの設計

画像アップロードサービスの設計

要件

機能要件

  • ユーザーはブラウザ/モバイルアプリから画像ファイルをアップロードできる
  • アップロードした画像は多様なサイズにリサイズされ変換される
  • 元画像と変換された画像のURLは画像のIDを用いて取得できる
  • 取得したURLから画像を高速に配信できる

非機能要件

  • 高スケーラビリティ、特に画像変換
  • 高信頼なサービス、画像データは失われてはいけない
  • 画像配信は低レイテンシ、全世界のユーザーから利用される
  • 高可用なサービス

想定質問

❓️画像のファイル形式は?
→ 基本的にjpegとpngを想定すればいい
❓️多様なサイズとはどのくらいバリエーションがある?
→ 3種類
❓️アップロードする画像の上限のサイズなどはある?
→ サイズの上限は5MB
❓️画像アップロードリクエストのリクエスト数はどのくらいを想定すればよい?
→ ピーク時には毎秒100件程度だが、普段はそこまでのリクエストは来ない

データモデル

Users
  • id: ユニークID
  • name: ユーザー名
💡
ユーザーに関する要件はあまりないのでシンプルな構造にしておきます。
Images
  • id: ユニークID
  • userId: ユーザーID
  • imagePath: 画像のパス
  • width: 画像の横の長さ
  • height: 画像の縦の長さ
  • status: ドラフト、処理中、完了、失敗
💡
画像データで最も大事なのは画像のパスの情報です、imagePathはストレージへのパスのデータを保持しておきます。S3などのオブジェクトストレージに保存している場合、キーの名前が入ります。サイズ(width、height)は画像のメタデータから取得も可能ですが、クライアント表示時に必要なデータなのでデータとして保持しておきます。
ImageVariants
  • id: ユニークID
  • originalImageId: 元画像のID
  • imagePath: 画像のパス
  • width: 画像の横の長さ
  • height: 画像の縦の長さ
  • status: ドラフト、処理中、完了、失敗
💡
派生画像(サムネイルやリサイズ済み画像)専用のスキーマ。originalImageId で元画像にひもづけることで、1 枚のオリジナルに対して複数サイズを柔軟に管理できます。statusは画像処理の状態を保持しておきます。imagePath 、width、height

API

画像をアップロードする

アプリケーションサーバーがmultipart/form-dataを受け取り、オブジェクトストレージへ転送する。完了後に画像メタデータを登録し、レスポンスを返す。
POST /images Content-Type: multipart/form-data
リクエストパラメータ
  • file: 画像バイナリ
  • fileName: 元ファイル名(任意)
💡
Pre-Signed URLを使う手法もあります。今回はアプリケーションサーバー経由で画像を転送しましたが、Pre-Signed URLを用いるとクライアント側から直接ファイルをオブジェクトストレージに転送できます。
関連 -
📗
ファイルをオブジェクトストレージにアップロードする

画像メタデータと派生画像を取得する

指定した imageId に対するオリジナル画像と派生画像(ImageVariants)の URL を返します。
GET /images/{imageId}
リクエストパラメータ
  • imageId: 画像のID
レスポンス
{ "id": "uuid-1234", "userId": "user_f7b3c4", "url": "https://interviewcat.com/uuid-1234/img_s2ds.jpg", "width": 4000, "height": 3000, "variants": [ { "id": "uuid-sus1", "url": "https://interviewcat.com/uuid-sus1/img_200x150_d8f1.jpg", "width": 200, "height": 150 }, { "id": "uuid-1f3i", "url": "https://interviewcat.com/uuid-1f3i/img_800x600_5e91.jpg", "width": 800, "height": 600 }, { "id": "uuid-9ks7", "url": "https://interviewcat.com/uuid-9ks7/img_1920x1080_s892.jpg", "width": 1920, "height": 1080 } ] }

アーキテクチャ図

  1. クライアントはUpload Serviceへmultipartで画像を送信
  1. ロードバランサーはリクエストをアプリケーションサーバーへ振り分ける
  1. Upload Serviceはmultipartのデータ(オリジナル画像)をそのままオブジェクトストレージへ転送し、メタデータ(Images)をDBに保存
  1. 同時に「画像変換リクエスト」をWorkerへ転送
  1. 画像変換Workerが各種サイズに変換しストレージへ保存、ImageVariantsもDBに保存
  1. クライアントはImage Metadata Serviceで画像のメタデータ(Images & ImageVariants)を取得し、CDN経由で画像をダウンロードする
  1. CDNはストレージをオリジンとしてキャッシュし、世界中へ低レイテンシ配信
notion image

設計の深堀りについて

1. 画像変換のスケーラビリティと非同期処理について

非機能要件には画像変換処理のスケーラビリティについて書かれています。画像変換はCPUやメモリを多く消費する計算負荷の高いジョブであり、画像をアップロードを受け付けるアプリケーションと同じサーバーで処理を行うとリソースが大きく消費され、結果的にシステム全体の可用性やスケーラビリティに影響を与えます。そこで画像変換処理を分離し、別サーバーで非同期処理を行う仕組みが必須でしょう。
非同期化により、Webアプリケーションは一旦202 Acceptedを即座に返し、ユーザー側はポーリングやSSEなどで進捗を取得できます。
関連
  • 📗
    サーバー側の更新をリアルタイムに受け取る(Polling / Long Polling / SSE)
別サーバーでスケーラブルな画像変換処理を行うにはどのようにすればよいでしょうか?

ジョブスケジューラによるオンラインバッチ

メッセージキューを導入せず、アプリケーションやDBだけでオンラインバッチを組むことを考えてみましょう。この方法では、画像アップロードがされた時に画像変換ジョブをDBに保存します。
その後、一定時間ごとにテーブルをスキャンしてジョブを処理する仕組みを構築します。決められた間隔で起動するワーカーが未処理レコードを探して変換を実行し、完了後に状態を更新することで、メッセージキューなしでの非同期処理を実現できます。

課題

しかしこれはスケーラビリティの観点で大きな課題が残ります。スキャン方式では複数のワーカーがDBからジョブのレコードを取得する際に競合に気をつけることもしくは複数のワーカーが互いに独立したジョブにアクセスできるようにしなければなりません。このような実装もコーディネーションサービスを利用することで担当ジョブをワーカーごとに分けることが可能ですが仕組みが複雑化することは避けられません。
関連
  • 📗
    コーディネーションサービスを活用した分散システムの管理

メッセージキューとワーカーにより非同期処理(オススメ)

画像変換リクエストをメッセージとしてキューに投入し、ワーカープールが取り出して実行するパターンはどうでしょうか?メッセージの単位はVariantごとに用意しましょう。
この方法ではスケーラビリティが大きな利点となります。ワーカーはメッセージキュー内のメッセージの数のメトリクスをに対してコンテナもしくはVMをオートスケールで増減でき、スループットを動的に確保できます。また、メッセージキューがバッファとして機能するため、アップロードピーク時にメッセージがたまってもアプリケーションサイドは影響を受けません。これにより、ピーク時にリクエストが増えても対処可能です。
関連
  • 📗
    メッセージキューによるスケーラビリティの向上
notion image
メッセージキューを使った後のデザインはこのようになります。
notion image

2. オブジェクトストレージによる画像データの信頼性について

オブジェクトストレージに保存されている画像を冗長化やデータ破損の検知を自動化させることで、画像データ損失を防ぐ高信頼なサービスを実現することができます。

ジオレプリケーション

ジオレプリケーションでは、ファイルデータを地理的に離れた複数のデータセンターに複製保存します。例えば、東京、シンガポール、オレゴンの三拠点に同じファイルを保存することで、自然災害や大規模障害による単一拠点の損失に対応できます。非同期レプリケーションを採用することで、書き込み性能への影響を最小限に抑えつつ、結果整合性を保証します。

Erasure Coding

Erasure Codingは、数学的アルゴリズムによる高効率な冗長化技術です。ファイルを複数のデータブロックとパリティブロックに分割し各サーバーで保管、一部のブロックが損失しても元データを完全復元できます。従来の単純なレプリケーションと比較して、約50%のストレージオーバーヘッドで同等以上の耐久性を実現し、運用コストを大幅に削減できます。

チェックサム検証

チェックサム検証では、データ破損の検出と修復を実現します。大規模システムでは、メモリ内でのデータ破損、ネットワーク転送中のビット反転、ストレージデバイスでの部分的エラーなど、「サイレント」な破損が日常的に発生し、検出が困難です。
各チャンクにSHA-256などのハッシュ値を付与し、データ読み取り時に再計算したハッシュ値と比較することで破損を検出します。チェックサム不一致が検出された場合は、Erasure Codingと組み合わせて他の障害ドメインから正常なデータを取得し、自動的に修復してクライアントに返却します。この継続的な検証により、サイレントデータ破損を防止できます。
関連
  • 📗
    オブジェクトストレージによる非構造化データの耐久性の向上

3. CDNによるグローバルでの低レイテンシな画像配信

画像を世界中に低レイテンシで届けるにはCDNを用いてエッジサーバーでキャッシュすることが効果的です。ユーザーは地理的に最も近いエッジロケーションへ接続するためRTTが短縮され、オリジンサーバーの負荷も大きく下がります。
関連
  • 📗
    CDNによる静的コンテンツのキャッシュ

プル型CDNキャッシュ

画像がリクエストされた時点でCDNがオリジンから取得し、TTLが切れるまでエッジに保存します。多くのCDNのサービスはレスポンスのCache-Control ヘッダーをカスタマイズ可能なのでユースケースに応じてどのくらいのTTLに設定するかを見極めましょう。プル型CDNの短所は初回アクセスのキャッシュミスによりレイテンシが伸びる点ですが、アクセス頻度の高い画像が増えるほどヒット率が向上します。

画像のバージョン管理

キャッシュの欠点としてデータの更新をしなければならない点がありますが、URLにサイズ情報やファイルのハッシュ値を含めファイル単位でキャッシュキーを分離すれば、バージョン管理も容易です。何らかの要因で画像を更新しなければならない時も再生成した画像に新たにサイズ情報やファイルのハッシュ値を含めれば違うキャッシュキーとなり新しくアクセスした際にも新規生成された画像を参照することができます。

4. メタデータデータベースの可用性について

画像配信においてはCDNやオブジェクトストレージにより極めて高い可用性が実現できる一方で、メタデータを管理するデータベースは適切な冗長化設計が必要です。メタデータデータベースが単一障害点となることを避け、システム全体の可用性を確保するための設計について検討していきます。
最も一般的で実装が容易なアプローチは、プライマリ・セカンダリ構成によるシングルリーダーレプリケーションです。書き込みはプライマリデータベースでのみ受け付け、読み取りはプライマリまたは複数のレプリカから実行します。
プライマリに障害が発生した場合、フェイルオーバーによりセカンダリがプライマリに昇格します。フェイルオーバー中の短時間(通常30秒から数分)は書き込みが停止しますが、画像変換リクエストはメッセージキューに保持されるため、データベースが復旧すれば再度リトライする事で処理を継続できます。読み取りに関してはレプリカが稼働している限りは中断されることはありません。
例えば、AWSのRDSマルチAZ構成では、プライマリインスタンスに障害が発生すると自動的にセカンダリインスタンスに切り替わります。
関連
  • 📗
    レプリケーションによる耐障害性、可用性の向上
  • 📗
    メッセージキューによる信頼性向上
 
アナリティクス用のデータベースを活用するLINE(リアルタイムチャット)の設計

目次

要件機能要件非機能要件想定質問データモデルAPI画像をアップロードする画像メタデータと派生画像を取得するアーキテクチャ図設計の深堀りについて1. 画像変換のスケーラビリティと非同期処理についてジョブスケジューラによるオンラインバッチメッセージキューとワーカーにより非同期処理(オススメ)2. オブジェクトストレージによる画像データの信頼性についてジオレプリケーションErasure Codingチェックサム検証3. CDNによるグローバルでの低レイテンシな画像配信プル型CDNキャッシュ画像のバージョン管理4. メタデータデータベースの可用性について