關於 SQL 的那些小坑(2):DB Connection 爆掉的 真實原因與處理策略
· 閱讀時間約 3 分鐘
當 MySQL 連線數爆掉時,常見症狀包括 API timeout、網站卡死,以及 Too many connections 錯誤。這通常不是單一 bug,而是系統架構與設定累積的結果。
資訊
在 Threads 上面看到有人聊到資料庫連線爆掉的問題,以前在做後端工程師的時候也會遇到...於是學會了像是使用SHOW PROCESSLIST、或是增加 DBMS 連線數,以下這篇是和 AI 聊天的過程和請 AI 幫忙寫的文章...XD
一、確認目前最高連線數
之前應該就要了解自己系統了
SHOW VARIABLES LIKE 'max_connections'; -- mysql
SHOW max_connections; -- pgsql
二、找出佔用連線的 Query / Client
SHOW FULL PROCESSLIST; --mysql
SELECT * FROM pg_stat_activity; --pgsql
常見問題包含:
- Query 執行超過數十秒
- 狀態卡在
Sending data - Sleep connection 大量累積
三、緊急止血(Production)
KILL <process_id>; -- mysql
SELECT pg_cancel_backend(<pid of the process>) --pgsql
SELECT pg_terminate_backend(<pid of the process>) --pgsql
四、常見根本原因
1. Connection Leak
程式沒有釋放 DB 連線,導致連線逐漸累積。
這個之前有遇過...如果自己寫的程式碼要記得做 db close 呀!
2. 每個 Request 建立新連線
沒有使用 connection pool,每次 request 都建立新 client。
個人認為常常是 php 慢的原因...但我覺得也要檢討為什麼每次 Query 會慢?應該要研究整個查詢的 Bottleneck 進而優化 SQL 查詢...有時候慢的原因常常出自於架構設計問題與撰寫程式碼的問題...總歸都是人自己的問題 XD
3. Worker / PHP-FPM 開太多
Worker 數量 × DB connection = 真實連線需求。
學到了!我覺得最近可能也要好好學習 php-fpm 的功課 要開多少個 Worker 之類的
五、工程級解法
1. 調整 MySQL 連線上限
SET GLOBAL max_connections = 200; --mysql
ALTER SYSTEM SET max_connections TO '200'; --pgsql
注意:需搭配 RAM 評估,不能無限制提高。
2. 建立 Connection Pool(應用程式層)
3. 使用 Proxy Layer
- ProxySQL
- MySQL Router
4. 加 Cache 減少 DB Hit
Cache::remember("user:$id", 60, fn() => User::find($id));
六、小 VPS 建議配置(1GB RAM)
max_connections = 50
innodb_buffer_pool_size = 256M
七、容量計算觀念
實際連線需求約為:
PHP-FPM workers × DB conn per request
+ Queue workers × DB conn
只要需求 > max_connections → MySQL/PostgreSQL 必炸。
結論
MySQL 連線數問題通常不是資料庫本身,而是系統架構設計與容量規劃問題。 能預先設計 connection usage 的工程師,已具備 Senior Backend / SRE 等級的系統思維。
小君曰:真是很懶得寫文章XD