PHP mysqli/pdo_mysql 預設僅支援連線超時 (MYSQLI_OPT_CONNECT_TIMEOUT),缺乏查詢執行階段的讀/寫超時控制。高負載下慢查詢會阻塞 PHP 進程,導致 FPM 池耗盡、整站雪崩。
$mysqli = mysqli_init();
$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 5); // 秒
$mysqli->real_connect('localhost', 'user', 'pass', 'db');
libmysqlclient 的 mysql_options()。MYSQL_OPT_READ_TIMEOUT (11) 與 MYSQL_OPT_WRITE_TIMEOUT (12)。<?php
// 定義 libmysqlclient 常數
if (!defined('MYSQL_OPT_READ_TIMEOUT')) define('MYSQL_OPT_READ_TIMEOUT', 11);
if (!defined('MYSQL_OPT_WRITE_TIMEOUT')) define('MYSQL_OPT_WRITE_TIMEOUT', 12);
$mysqli = mysqli_init();
// 設定讀寫超時 3 秒 (實際約 9 秒)
$mysqli->options(MYSQL_OPT_READ_TIMEOUT, 3);
$mysqli->options(MYSQL_OPT_WRITE_TIMEOUT, 1);
$mysqli->real_connect('localhost', 'root', 'root', 'test');
// 測試:sleep(1) 成功,sleep(9) 超時斷開
$mysqli->query('SELECT SLEEP(1)'); // 成功
$mysqli->query('SELECT SLEEP(9)'); // 失敗:MySQL server has gone away
libmysqlclient 僅支援秒級。若需毫秒級,需修改:
pcntl_alarm 或非阻塞 IO + stream_select)。vio 層 poll() / setsockopt(SO_RCVTIMEO/SO_SNDTIMEO) 邏輯,重新編譯 libmysqlclient。$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass', [
PDO::ATTR_TIMEOUT => 5, // 連線超時
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET SESSION MAX_EXECUTION_TIME=3000' -- MySQL 5.7.8+
]);
// MAX_EXECUTION_TIME 單位毫秒,僅對 SELECT 生效
MAX_EXECUTION_TIME、long_query_time、EXPLAIN 監控慢查詢。request_terminate_timeout、Nginx proxy_read_timeout 同步設定,防止層層疊加。