PHP 作為 Apache 模組運行時,長連接能否生效取決於 Apache 的 Keep-Alive 設定。
KeepAlive On MaxKeepAliveRequests 0 # 不限制單連線請求數 KeepAliveTimeout 15 # 保持連線秒數,關鍵參數
<?php echo "Apache 進程 PID: " . getmypid(); // 15 秒內重整頁面觀察 PID 是否變化 ?>
mysql_pconnect 根據 Apache 進程 ID 生成 Hash Key,在進程級別的 persistent_list 中查找/儲存連線資源。
// 簡化版核心邏輯 (PHP 源碼 ext/mysql/php_mysql.c)
$user = php_get_current_user(); // 取得進程唯一標識
$hashed_details = "MySQL__${user}_";
// 在 persistent_list 中查找
if (zend_hash_find(&EG(persistent_list), $hashed_details, ...) == FAILURE) {
// 不存在:建立新連線並存入 hash 表
zend_hash_update(&EG(persistent_list), $hashed_details, ..., $new_le);
} else {
// 存在:直接復用連線資源
$mysql = $le->ptr;
}
兩者預設均為 8 小時 (28800 秒),極易導致連線堆積。
<?php
$conn = mysql_pconnect("localhost", "root", "123456");
echo "MySQL Thread ID: " . mysql_thread_id($conn) . "<br>";
echo "Apache PID: " . getmypid();
?>
對照 MySQL SHOW PROCESSLIST 觀察 Command=Sleep、Time 遞增。
[mysqld] wait_timeout = 30 # 非互動式連線閒置超時 interactive_timeout = 60 # 互動式連線閒置超時
mysql_pconnect → 非互動式 → 受 wait_timeout 控制mysql_pconnect(..., MYSQL_CLIENT_INTERACTIVE) → 互動式 → 受 interactive_timeout 控制Apache KeepAliveTimeout ≥ MySQL wait_timeout
確保 Apache 釋放連線前,MySQL 已主動清理閒置連線,避免「僵屍連線」佔用 max_connections。
| 層面 | 建議值 | 說明 |
|---|---|---|
| Apache KeepAliveTimeout | 15-30 秒 | 視網站流量調整,過長浪費進程槽 |
| MySQL wait_timeout | 10-30 秒 | 略小於 KeepAliveTimeout |
| MySQL max_connections | 500-2000 | 配合伺服器記憶體設定 |
| PHP mysql_pconnect | 謹慎使用 | 高併發下易爆連線數,建議改用連線池 |
mysql_pconnect 看似美好,實則是「雙邊協作」的脆弱平衡。現代高併發架構建議:放棄長連接,採用短連接 + 連線池中介 + 資料庫參數調優,更穩定可控。