首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP Session 併發阻塞問題與 session_write_close() 解決方案實測

     編輯:PHP 相關知識

PHP 預設的 Session 機制為同一客戶端同一時間只能有一個請求持有 Session 鎖。當多個 AJAX 請求並發訪問同一 Session 時,後續請求會阻塞等待前一請求釋放鎖(預設在腳本結束或顯式調用 session_write_close() 時釋放)。本文通過實測代碼演示阻塞現象,並給出生產環境可用的優化模式。

問題複現:10 秒 vs 2 秒

客戶端代碼(發起 5 條並發 AJAX)

<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
<script>
$(function() {
    for (var i = 1; i <= 5; i++) {
        $.ajax({
            url: 'rest.php?call=' + i,
            success: function(data) {
                $('body').append('<p>Call complete ' + data + '</p>');
            }
        });
    }
});
</script>

服務端 rest.php(未優化)

<?php
session_start();
sleep(2);  // 模擬業務邏輯耗時
echo '{json:"response ' . $_GET["call"] . '"}';
?>

結果:5 請求串行執行,總耗時 ≈ 10 秒(5 × 2s)。瀏覽器 Network 面板顯示請求依次完成,而非並行。

解決方案:盡早釋放 Session 鎖

優化後 rest.php

<?php
session_start();
// 讀取/寫入 Session 相關操作完成後,立即釋放鎖
session_write_close();

sleep(2);  // 耗時業務邏輯,此時其他請求可並行進入
echo '{json:"response ' . $_GET["call"] . '"}';
?>

結果:總耗時 ≈ 2 秒(並發執行)。Session 數據在 session_write_close() 時寫入存儲引擎(files/redis/memcached),後續代碼不再持有鎖。

最佳實踐模式

<?php
// 1. 啟動 Session
session_start();

// 2. 讀取必要的 Session 數據到局部變量
$userId = $_SESSION['user_id'] ?? null;
$permissions = $_SESSION['perms'] ?? [];

// 3. 【關鍵】業務邏輯無需再寫入 Session 時,立即釋放鎖
session_write_close();

// 4. 執行耗時操作:DB 查詢、外部 API 呼叫、大量計算、sleep 等
//    此期間同用戶其他請求可並行處理
$result = heavyOperation($userId);

// 5. 若後續仍需寫入 Session(如更新最後活動時間),可重新啟動
// session_start();
// $_SESSION['last_active'] = time();
// session_write_close(); // 再次釋放

echo json_encode(['data' => $result]);
?>

適用場景與注意事項

場景建議
純讀取 Session / 只在開頭寫入啟動 → 讀/寫 → session_write_close() → 其餘邏輯
中間需多次讀寫 Session分段:session_start() → 操作 → session_write_close() → 耗時邏輯 → 再次 session_start() …
使用 Redis/Memcached 存儲 Session鎖粒度通常較細(按 Key),但同 Key 仍會阻塞,同樣建議盡早釋放
長輪詢 / SSE / WebSocket握手階段驗證 Session 後立即 session_write_close(),長連接期間不持有鎖

進階:自定義 Session Handler 實現無鎖讀取

若業務極度敏感於延遲,可實作 SessionHandlerInterface,在 read() 返回數據後不加鎖、write() 僅追加寫入(如 Redis Lua 腳本原子操作),但需自行處理並發一致性(樂觀鎖/版本號)。

總結

Session 鎖是 PHP 併發性能的隱形殺手。遵循「用完即關」原則:session_start() → 讀寫 Session → session_write_close() → 執行耗時邏輯,能將串行阻塞轉為真正並行,顯著提升高併發場景下的響應速度與吞吐量。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved