PHPの実行モデルと前提
PHPの実行モデルと前提
Section titled “PHPの実行モデルと前提”PHPの実行モデルと、実務で事故を防ぐための前提条件を詳しく解説します。
実行モデルとリソースの物理的制約
Section titled “実行モデルとリソースの物理的制約”コンピュータ資源は有限であり、性能ではなく制約を前提に設計することが基本です。
主な物理的制約
Section titled “主な物理的制約”CPU・メモリよりも先に枯渇するリソース:
-
DB・外部APIのコネクション数
- 接続プールの上限(例: PDOの
max_connections) - 接続リークは数時間後にシステム全体を停止させる
- 接続プールの上限(例: PDOの
-
プロセス/スレッドプール
- PHP-FPMのプロセス数制限(
pm.max_children) - プロセス枯渇により、すべてのリクエストが処理できなくなる
- PHP-FPMのプロセス数制限(
-
ファイル記述子
- OSレベルの制限(通常1024〜65536)
- ファイルやソケットを適切にクローズしないと枯渇
-
メモリリーク
- オブジェクトの参照が保持される
- グローバル変数や静的変数の不適切な使用
実際の事故例:
10:00:00 - アプリケーション起動(接続プール: 10/10)10:00:01 - リクエスト1受信(接続取得: 11/10 → 待機)10:00:02 - リクエスト2受信(接続取得: 12/10 → 待機)...10:30:00 - 接続が解放されず、すべてのリクエストが待機状態10:30:01 - タイムアウトエラーが大量発生10:30:02 - システム全体が応答不能PHPの実行モデル
Section titled “PHPの実行モデル”PHPの実行モデル
Section titled “PHPの実行モデル”実行モデル:
PHPコード (.php) ↓ インタープリタで実行Zend Engine(実行時)重要な特徴:
- 動的型付け: 実行時に型が決定される(PHP 8.0以降は型宣言が強化)
- ガベージコレクション: 自動メモリ管理(ただし、参照が保持されている場合は動作しない)
- リクエストごとの実行: 各リクエストが独立したプロセス/スレッドで実行される
- OPcache: バイトコードキャッシュによる高速化
トランザクション境界
Section titled “トランザクション境界”PHPのトランザクション管理:
// PDOでのトランザクション管理try { $pdo->beginTransaction();
// トランザクション内の処理 $stmt = $pdo->prepare("INSERT INTO orders (user_id, amount) VALUES (?, ?)"); $stmt->execute([$userId, $amount]);
$orderId = $pdo->lastInsertId();
$stmt = $pdo->prepare("UPDATE inventory SET stock = stock - ? WHERE product_id = ?"); foreach ($items as $item) { $stmt->execute([$item['quantity'], $item['product_id']]); }
$pdo->commit();} catch (Exception $e) { $pdo->rollBack(); throw $e;}特徴:
- 明示的なトランザクション境界:
beginTransaction()とcommit()で明示 - 手動ロールバック: エラー時に手動でロールバック
- 例外処理: try-catchブロックでエラーハンドリング
PHPの非同期処理:
// プロセスフォークを使用$pid = pcntl_fork();
if ($pid == -1) { die('Could not fork');} elseif ($pid) { // 親プロセス pcntl_wait($status);} else { // 子プロセス(非同期処理) processOrder($orderId); exit(0);}特徴:
- プロセスフォーク:
pcntl_fork()による非同期処理 - エラーハンドリング: 親プロセスで子プロセスの状態を監視
- 再実行: 手動で再実行を実装
実行環境による特性
Section titled “実行環境による特性”| 環境 | 特徴 | 主なリスク |
|---|---|---|
| Serverless (Lambda/Vercel) | 短寿命・自動スケール | コールドスタート、接続バースト、DBパンク、実行時間制限(Lambda: 15分、Vercel: 300秒) |
| 常駐プロセス (PHP-FPM) | 長寿命・安定動作 | メモリリーク、プール断片化、デッドロック、接続リーク |
Serverless環境での実行
Section titled “Serverless環境での実行”制約:
// ❌ 悪い例: Serverless環境で問題のあるコードfunction createOrder($orderData) { // 問題: 長時間実行される可能性がある // 問題: トランザクションが長時間保持される // 問題: 接続プールが適切に管理されない $pdo = new PDO($dsn, $user, $pass); $stmt = $pdo->prepare("INSERT INTO orders (user_id, amount) VALUES (?, ?)"); $stmt->execute([$orderData['user_id'], $orderData['amount']]); return $pdo->lastInsertId();}問題点:
- 実行時間の制限: Lambdaは最大15分、Vercelは最大300秒
- コールドスタート: PHPの起動に時間がかかる(500ms-2s)
- メモリ制限: メモリ使用量に制限がある(Lambda: 128MB〜10GB)
- 接続バースト: スケールアウト時に接続プールが急増し、DBがパンクする可能性
PHPの実行モデルと前提のポイント:
- リソースの物理的制約: CPU・メモリよりも先に枯渇するのは、DB接続数・プロセスプール・ファイル記述子・メモリリーク
- PHP: 動的型付け、ガベージコレクション、リクエストごとの実行、OPcache
- トランザクション境界:
beginTransaction()とcommit()で明示、手動ロールバック - 非同期処理: プロセスフォークによる制御、エラーハンドリング、手動再実行
- Serverless環境: 実行時間制限、コールドスタート、メモリ制限、接続バースト
- 常駐プロセス環境: 長時間実行可能、接続プール、キャッシュ(メモリリーク・接続リークに注意)
重要な原則: 性能ではなく制約を前提に設計する。リソースの垂れ流しは数時間後にシステム全体を停止させる。