首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL 「Resource temporarily unavailable」排查實錄:線程數限制與 ulimit 陷阱

     編輯:MySQL 綜合教學

線上環境執行 `su - mysql` 突然報錯 `su: cannot set user id: Resource temporarily unavailable`。這不是 MySQL 本身的錯誤,而是 **作業系統層面的資源限制** 導致無法創建新進程/線程。本文還原完整排查過程,揭示 MySQL 線程模型與 Linux `nproc` 限制的隱性關係。

現場還原

[root@dbmain ~]# su - mysql
su: cannot set user id: Resource temporarily unavailable

排查步驟與證據鏈

1. 檢查用戶級資源限制 (`ulimit -a`)

[root@dbmain ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
...
max user processes      (-u) 25600
open files              (-n) 1024
...

全域 `nproc=25600` 看似充足,但這是 **root 用戶** 的限制,非 `mysql` 用戶。

2. 檢查 `/etc/security/limits.conf` (關鍵突破口)

oracle soft nproc 2047
oracle hard nproc 16384
...
mysql soft nproc 500      <-- 核心發現:mysql 用戶硬限制僅 500
mysql hard nproc 500
mysql soft nofile 1024
mysql hard nofile 65536

**`mysql` 用戶 `nproc` (max user processes) 被硬限制在 500**。

3. 驗證當前 mysql 進程/線程數

[root@dbmain ~]# ps -ef | grep mysql
root      4733     1  0 10:30 ?        00:00:00 /bin/sh /usr/bin/mysqld_safe ...
mysql     4788  4733  0 10:30 ?        00:00:04 /usr/sbin/mysqld ...
root     15171 17507  0 13:26 pts/2    00:00:00 mysql -uroot -p
root     20792 17163  0 15:30 pts/1    00:00:00 grep mysql

僅見 1 個 `mysqld` 主進程 (PID 4788) 和幾個 client 連線,**進程數遠低於 500**,為何仍報錯?

4. 深入:MySQL 線程 = Linux 任務 = 佔用 nproc

[root@dbmain ~]# ls -l /proc/4788/task/ | wc -l
# 假設輸出 450+ (含主線程、IO 線程、Worker 線程、連線線程等)

[root@dbmain ~]# cat /proc/4788/status | grep Threads
Threads: 480

**MySQL 使用 `pthread` 實現多線程,每條連線、每個後台任務 (purge、page cleaner、redo log writer 等) 都是一個 Linux 任務 (LWP),全部計入用戶的 `nproc` 計數器。**

5. 計算:連線數 + 內部線程 = 總任務數

  • MySQL 內部固定線程:~10-20 條 (主線程、IO、redo log、purge、page cleaner、shutdown、監控等)
  • 每個用戶連線:1 條線程 (`thread_per_connection`)
  • 若 `max_connections=500`,滿載時需 **520+ 任務槽位**
  • 但 `limits.conf` 限制 `mysql hard nproc 500` → **槽位不足,無法創建新線程/進程**

6. 修復驗證

# 1. 調大 limits.conf
vim /etc/security/limits.conf
mysql soft nproc 10000
mysql hard nproc 10000

# 2. 重新登入生效 (或重啟 mysqld 服務)
su - mysql  # 成功!

# 3. 同步調整 MySQL 參數 (防止配置超過 OS 限制)
# my.cnf
max_connections = 5000
thread_cache_size = 100

# 4. 系統級也要跟上
echo "* soft nproc 10000" >> /etc/security/limits.conf
echo "* hard nproc 10000" >> /etc/security/limits.conf
# /etc/systemd/system/mysql.service.d/override.conf
[Service]
LimitNPROC=10000
LimitNOFILE=65536

核心認知總結

認知點說明
MySQL 線程 = Linux 任務 (LWP)每條連線、每個後台線程都佔用一個 `nproc` 槽位
`max_connections` ≠ 實際最大並發受限於 OS `nproc`、`nofile`、記憶體、CPU
`limits.conf` 對特定用戶生效`mysql` 用戶需單獨配置,不能只依賴 `*` 通配
systemd 服務有獨立 Limit`LimitNPROC`/`LimitNOFILE` 在 unit 中覆蓋 PAM 限制
排查命令`cat /proc//status | grep Threads`、`ls /proc//task/`、`ulimit -u` (以目標用戶身份)

生產環境配置清單

# 1. /etc/security/limits.conf
mysql soft nofile 65536
mysql hard nofile 65536
mysql soft nproc 10000
mysql hard nproc 10000

# 2. /etc/systemd/system/mysqld.service.d/override.conf (或 mysql.service)
[Service]
LimitNOFILE=65536
LimitNPROC=10000
LimitMEMLOCK=infinity

# 3. my.cnf
[mysqld]
max_connections = 5000
thread_cache_size = 200
open_files_limit = 65536  # 需 ≤ OS nofile hard limit
table_open_cache = 4000

# 4. 內核參數 /etc/sysctl.conf
fs.file-max = 1000000
fs.nr_open = 1000000
vm.max_map_count = 262144

# 5. 重啟驗證
systemctl daemon-reload
systemctl restart mysqld
su - mysql -c "ulimit -a"  # 確認 nproc/nofile 生效
mysql -e "SHOW VARIABLES LIKE 'max_connections'; SHOW GLOBAL STATUS LIKE 'Threads_connected';"

延伸:容器化環境 (Docker/K8s) 的同類坑

  • 容器預設 `--ulimit nproc=1024:1024`、`nofile=1024:1024`,極易觸發。
  • K8s `securityContext.runAsUser=999` (mysql uid) 需配合 `ulimit` 設定或 Pod `resources.limits` 間接控制。
  • 建議:K8s 部署 MySQL 使用 Operator (Oracle MySQL Operator、Percona Operator、Vitess),由 Operator 管理資源限制與調優。

**「Resource temporarily unavailable」看似神秘,實則是「MySQL 線程模型 + Linux nproc 限制」的必然碰撞。** 將 OS 級資源限制納入 MySQL 容量規劃與部署標準化清單,才能徹底根治此類隱性故障。

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