ERROR 2006 (HY000): MySQL server has gone away 或 ERROR 2013 (HY000): Lost connection to MySQL server during query 表示客戶端與服務器連接意外中斷。核心原因三類:
wait_timeout/interactive_timeoutmax_allowed_packet典型場景:PHP/Python/Java 長時間運行腳本、ETL 作業、數據遷移,中間間隔超過 8 小時 (默認 wait_timeout=28800) 無交互。
-- 1. 服務端調大超時 (持久化生效,需重啟)
# /etc/my.cnf
[mysqld]
wait_timeout = 86400 # 24 小時
interactive_timeout = 86400 # 交互式客戶端
-- 2. 客戶端連接時指定 CLIENT_INTERACTIVE (臨時生效)
# PHP PDO
$pdo = new PDO("mysql:host=127.0.0.1;dbname=test", "user", "pass", [
PDO::MYSQL_ATTR_INIT_COMMAND => "SET SESSION wait_timeout=86400",
PDO::ATTR_PERSISTENT => true # 或用持久連接
]);
# Python MySQLdb
conn = MySQLdb.connect(host='127.0.0.1', user='user', passwd='pass', db='test',
connect_timeout=10, read_timeout=86400, write_timeout=86400,
client_flag=MySQLdb.constants.CLIENT.INTERACTIVE)
# Java HikariCP
dataSource.setConnectionInitSql("SET SESSION wait_timeout=86400");
dataSource.setMaximumPoolSize(20);
dataSource.setMinimumIdle(5);
dataSource.setIdleTimeout(600000); # 10 分鐘空閒回收,避免撞服務端超時
testOnBorrow / validationQuery: SELECT 1,借連接前心跳檢測maxLifetime < 服務端 wait_timeout,主動回收老連接autoReconnect=true (JDBC 老版本),改用連接池自帶重試邏輯典型場景:批量 INSERT 巨大 SQL、存儲 Base64 圖片/文件、mysqldump 導出含大字段、LOAD DATA 導入大行。
-- 1. 服務端調大 (持久化,需重啟)
# /etc/my.cnf
[mysqld]
max_allowed_packet = 256M # 視業務最大 Blob 大小而定,建議 64M-1G
[client]
max_allowed_packet = 256M # mysqldump/mysql 客戶端也要跟著調大
-- 2. 會話級臨時調大 (無需重啟,僅當前連接)
SET SESSION max_allowed_packet = 256M;
-- 3. 應用層拆分大 SQL
# 批量 INSERT 分批,每批 1000-5000 行
# 大 Blob 分塊寫入或存對象存儲 (S3/OSS) 只存 URL
# 導出:避免 --opt 產生超大 INSERT (默認開啟 --extended-insert)
mysqldump -uroot -p --single-transaction --quick --max_allowed_packet=256M \
--net_buffer_length=16384 db_name > dump.sql
# 導入:調大客戶端 packet
mysql -uroot -p --max_allowed_packet=256M db_name < dump.sql
# 或分批導入
split -l 10000 dump.sql chunk_
for f in chunk_*; do mysql -uroot -p db_name < $f; done
grep -i -e "killed" -e "out of memory" -e "assertion" -e "signal" /var/log/mysql/error.logdmesg -T | grep -i -e mysql -e oom -e kill 看是否被 OOM Killer 殺死pt-query-digest slow.log、SHOW ENGINE INNODB STATUSSHOW GLOBAL STATUS LIKE 'Threads_connected'; SHOW PROCESSLIST;| 故障類型 | 表徵 | 解決方案 |
|---|---|---|
| OOM Killer | dmesg 顯示 Out of memory: Kill process mysqld | 降低 innodb_buffer_pool_size、增加 Swap、限制 max_connections、升級內存 |
| InnoDB Assertion/Crash | error.log 有 assertion failure / segmentation fault | 升級 MySQL 版本、檢查硬件 (ECC 內存)、innodb_force_recovery 恢復數據 |
| 主動 KILL | error.log: "Killed by user root" | 審計誰執行了 KILL,限制 SUPER 權限 |
| 網絡中斷 | 防火牆/交換機/負載均衡超時斷開長連接 | |
| 磁盤滿/IO 凍結 | df -h 顯示 100%、iostat %util 100% | 清理 Binlog、擴容磁盤、優化慢查詢減少 IOPS |
# Python 示例:指數退避重試 + 熔斷
import time, random, pymysql
from contextlib import contextmanager
class CircuitBreaker:
def __init__(self, failure_threshold=5, recovery_timeout=30):
self.failures = 0
self.threshold = failure_threshold
self.recovery_timeout = recovery_timeout
self.last_failure = 0
self.open = False
def call(self, func, *args, **kwargs):
if self.open and time.time() - self.last_failure > self.recovery_timeout:
self.open = False
self.failures = 0
if self.open:
raise Exception("Circuit breaker open")
try:
result = func(*args, **kwargs)
self.failures = 0
return result
except (pymysql.err.OperationalError, pymysql.err.InterfaceError) as e:
if e.args[0] in (2006, 2013, 2055): # Gone away / Lost connection
self.failures += 1
self.last_failure = time.time()
if self.failures >= self.threshold:
self.open = True
raise
@contextmanager
def mysql_retry(max_retries=3, base_delay=0.5):
for attempt in range(max_retries):
try:
yield
return
except (pymysql.err.OperationalError, pymysql.err.InterfaceError) as e:
if e.args[0] not in (2006, 2013, 2055) or attempt == max_retries - 1:
raise
delay = base_delay * (2 ** attempt) + random.uniform(0, 0.1)
time.sleep(delay)
# 重新獲取連接 (連接池會自動處理)
raise Exception("Max retries exceeded")
[mysqld]
# 連接管理
wait_timeout = 86400
interactive_timeout = 86400
max_connections = 2000
max_connect_errors = 100000
thread_cache_size = 100
# 數據包
max_allowed_packet = 256M
net_buffer_length = 16384
net_read_timeout = 60
net_write_timeout = 60
# 穩定性
innodb_buffer_pool_size = 70%_RAM
innodb_log_file_size = 2G
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1
innodb_deadlock_detect = ON
# 監控
slow_query_log = 1
long_query_time = 1
log_queries_not_using_indexes = 0
log_error = /var/log/mysql/error.log
log_error_verbosity = 3
核心原則:客戶端主動管理連接生命周期 (連接池 + 心跳 + 重試),服務端配置足夠緩衝 (timeout/packet/buffer),監控覆蓋錯誤日志/系統日志/慢查詢/連接數,做到早發現、快恢復、不丟數據。