システム設計の基礎 (System Design Fundamentals)
はじめに
システム設計とは、要件を満たすソフトウェアシステムのアーキテクチャを決定するプロセスだ。単一のサーバーで動くアプリケーションから、数百万ユーザーをさばく分散システムまで、規模は様々だが考え方の基本は共通している。
医療 SaaS では、データの正確性・可用性・セキュリティが特に重要になる。
基本概念
スケーラビリティ (Scalability)
負荷の増加に対してシステムが対応できる能力。
垂直スケーリング (Scale Up): サーバーのスペックを上げる (CPU, メモリ増強)
- メリット: シンプル、アプリケーション変更不要
- デメリット: 物理的な上限がある、単一障害点
水平スケーリング (Scale Out): サーバーの台数を増やす
- メリット: 理論上は無限にスケール可能
- デメリット: データの一貫性、セッション管理が複雑に
垂直スケーリング: 水平スケーリング:
┌──────────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ │ │Server│ │Server│ │Server│
│ 大きな │ │ 1 │ │ 2 │ │ 3 │
│ サーバー │ └──┬───┘ └──┬───┘ └──┬───┘
│ │ │ │ │
└──────────┘ ┌──┴────────┴────────┴──┐
│ Load Balancer │
└───────────────────────┘
可用性 (Availability)
システムが正常に稼働している時間の割合。
| 可用性 | 年間ダウンタイム | 呼び方 |
|---|---|---|
| 99% | 3.65 日 | Two nines |
| 99.9% | 8.77 時間 | Three nines |
| 99.99% | 52.6 分 | Four nines |
| 99.999% | 5.26 分 | Five nines |
医療 SaaS での考慮: 診療時間中のダウンタイムは直接的に医療行為に影響する。可用性目標は慎重に設定し、それに見合った冗長化を行う。
CAP 定理 (CAP Theorem)
分散システムでは、以下の3つを同時に完全に満たすことはできない:
- Consistency (一貫性): すべてのノードが同じデータを返す
- Availability (可用性): すべてのリクエストにレスポンスを返す
- Partition Tolerance (分断耐性): ネットワーク分断が起きてもシステムが動作する
分散システムではネットワーク分断は不可避なので、実質的には CP (一貫性優先) か AP (可用性優先) の選択になる。
医療データの場合: 患者データの一貫性は極めて重要。誤ったデータを返すより、エラーを返す方が安全 → CP 寄りの設計が基本。
主要コンポーネント
ロードバランサー (Load Balancer)
トラフィックを複数のサーバーに分散させる。
主な分散アルゴリズム:
- ラウンドロビン: 順番に振り分け。シンプルだが均等性の保証はない
- 最小接続数: 接続数が最も少ないサーバーへ
- IP ハッシュ: 同一クライアントを同一サーバーへ (セッション維持)
実務での選択: AWS ALB (Application Load Balancer) を使うケースが多い。パスベースのルーティングや、ヘルスチェックによる異常サーバーの自動除外が可能。
キャッシュ (Cache)
頻繁にアクセスされるデータを高速な場所に保持する。
キャッシュの階層:
クライアント (ブラウザキャッシュ)
↓
CDN (静的アセット)
↓
アプリケーション (Redis/Memcached)
↓
データベース (クエリキャッシュ)
キャッシュ戦略:
- Cache-Aside: アプリがキャッシュを確認し、なければ DB から取得してキャッシュに保存
- Write-Through: 書き込み時にキャッシュと DB を同時更新
- Write-Behind: キャッシュに書き込み、非同期で DB に反映
キャッシュの難しさ: キャッシュの無効化 (invalidation) はコンピュータサイエンスで最も難しい問題の一つ。医療データではキャッシュの整合性に特に注意が必要。
メッセージキュー (Message Queue)
非同期処理を実現するためのコンポーネント。送信者と受信者を疎結合にする。
Producer → [Message Queue] → Consumer
(SQS, etc.)
使いどころ:
- メール/通知の送信
- レポート生成
- 外部システムとの連携
- 時間のかかる処理のバックグラウンド実行
医療 SaaS での例: 検査結果の通知、予約リマインダー、診療レポートの PDF 生成など。
データベースの設計パターン
レプリケーション (Replication):
- Primary-Replica 構成: 書き込みは Primary、読み取りは Replica に分散
- 読み取りが多いワークロード (典型的な Web アプリ) に有効
シャーディング (Sharding):
- データを複数のデータベースに分割して格納
- 分割キーの選択が重要 (例: テナント ID、地域)
シャーディングの例 (テナント ID で分割):
テナント A, B → DB Shard 1
テナント C, D → DB Shard 2
テナント E, F → DB Shard 3
アーキテクチャパターン
モノリス vs マイクロサービス
| 観点 | モノリス | マイクロサービス |
|---|---|---|
| デプロイ | 全体を一括 | サービスごとに独立 |
| 複雑さ | アプリ内は単純、規模拡大で複雑化 | 分散システムの複雑さ |
| チーム | 小〜中規模チーム向き | 大規模組織向き |
| データ一貫性 | トランザクションで容易 | Saga パターン等が必要 |
| 初期コスト | 低い | 高い |
現実的な判断: 多くのスタートアップ・中規模企業では、モジュラーモノリス (モノリスだが内部的にモジュール分割されている) が良い出発点。必要に応じてマイクロサービスに分離する。
API ゲートウェイ
クライアントとバックエンドサービスの間に位置し、以下を担当:
- ルーティング
- 認証・認可
- レート制限
- リクエスト/レスポンスの変換
イベント駆動アーキテクチャ
コンポーネント間をイベント (出来事) でつなぐ。
予約サービス --[予約作成イベント]--> 通知サービス
--> カレンダーサービス
--> 課金サービス
メリット: サービス間の疎結合、拡張性の高さ デメリット: デバッグが難しい、イベントの順序保証に注意が必要
医療 SaaS のシステム設計で考慮すべきこと
データの取り扱い
- 監査ログ: 誰がいつ何のデータにアクセス・変更したかを記録
- 論理削除: 医療データは物理削除せず、論理削除 (soft delete) を基本とする
- データの暗号化: 保存時 (at rest) と通信時 (in transit) の両方
マルチテナンシー
複数の医療機関が同一システムを利用する場合の設計:
- データ分離: テナント間でデータが漏洩しないことの保証
- パフォーマンス分離: 一つのテナントの負荷が他に影響しない設計
- カスタマイズ性: テナントごとの設定・ワークフローの違いへの対応
障害への備え
- サーキットブレーカー: 外部サービスの障害が連鎖しないよう遮断
- リトライとバックオフ: 一時的な障害に対する自動復旧
- グレースフルデグラデーション: 一部機能が使えなくても中核機能は維持
Agent-first 開発においてこれが重要な理由
システム設計は、AI コーディングエージェントが最も支援を必要とする領域の一つだ。
- 全体のアーキテクチャは人間が決める: エージェントはコンポーネントの実装は得意だが、「このシステムをどう分割するか」の判断は人間がすべき
- 非機能要件を明示できる: 「可用性 99.9% を目標に」「読み取り:書き込み = 100:1 の比率を想定」といった制約をエージェントに伝えられる
- トレードオフを言語化できる: 「ここはキャッシュを入れてレイテンシを下げたいが、一貫性のリスクを許容する」のような判断を伝えられる
- レビューの質が上がる: エージェントの提案するアーキテクチャが適切かどうかを評価できる
Further Reading
- System Design Primer - 網羅的なシステム設計ガイド
- Designing Data-Intensive Applications (書籍) - Martin Kleppmann による名著
- AWS Well-Architected Framework - AWS のベストプラクティス
- ByteByteGo - システム設計の図解
- The Twelve-Factor App - モダンな Web アプリの設計原則 (日本語訳あり)