MySQL 資料庫崩潰(crash)的常見原因和解決辦法

姚遠ACE發表於2022-06-13

檢查 MySQL 資料庫的啟動時間

Linux 系統中的 systemd 和 mysqld_safe 會在 mysqld 程式 crash 後自動重新啟動 MySQL 的服務,需要注意的是使用 kill -9 殺死 mysqld 程式系統會自動重新啟動,而只使用 kill 命令則不會重新啟動,因為執行 kill 命令,系統會傳送一個 SIGTERM 訊號給 mysqld,mysql 資料庫會正常關閉,日誌中會出現類似下面的記錄:

2020-10-26T09:06:48.435181Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.19)  MySQL Community Server - GPL.

MySQL 資料庫 crash 後都會重新啟動,因此我們有時可能不知道 MySQL 資料庫已經 crash 過了,但我們可以從mysql資料庫啟動時間上找到線索,下面介紹四種檢查 MySQL 資料庫啟動時間的方法。

檢查 MySQL 服務狀態

scutech@scutech:~$ service mysql status
● mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2020-10-21 05:54:18 NDT; 4 days ago
  Process: 774 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid (code=exited, status=0/SUCCESS)
  Process: 708 ExecStartPre=/usr/share/mysql/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
 Main PID: 791 (mysqld)
    Tasks: 27 (limit: 2328)
   CGroup: /system.slice/mysql.service
           └─791 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid

顯示 MySQL 資料庫已經執行 4 天多。

檢查 MySQL 中的 uptime 狀態

mysql> show global status like 'uptime';
+---------------+--------+
| Variable_name | Value  |
+---------------+--------+
| Uptime        | 428334 |
+---------------+--------+
1 row in set (0.32 sec)

這個值是以秒為單位,下面換算成以天為單位是 4 天多。

mysql> select 428334/60/60/24;
+-----------------+
| 428334/60/60/24 |
+-----------------+
|  4.957569444444 |
+-----------------+
1 row in set (0.01 sec)

 查詢 uptime 狀態的另一種方法是使用 mysqladmin version 或在 mysql 客戶端裡用 “\s” 進行查詢。

使用 ps 檢查程式啟動時間

使用 ps 命令查詢發現 mysqld 啟動了4天23小時3分種54秒


scutech@scutech:~$ ps -eo pid,user,args,etime|grep mysqld
  791 mysql    /usr/sbin/mysqld --daemoniz  4-23:03:54


檢查 MySQL 日誌

找關鍵字 “ready for connections”,可以查到啟動資訊。

2020-10-21T08:24:18.986765Z 0 [Note] /usr/sbin/mysqld: ready for connections.
Version: '5.7.28-log'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)


MySQL 資料庫 crash 的常見原因

MySQL 資料庫 crash 的最常見原因有兩個,一個是 mysql 的 bug , 另一個是 mysql 申請系統資源失敗或記憶體洩漏。

MySQL 的 bug

 MySQL資料庫 crash 的最常見的一個原因當然是 MySQL 的bug。95% 的 bug 都是和具體的 sql 相關,通常是 MySQL  crash 前執行的最後一個 sql 有問題,因此定位 bug 時應開啟  general query log ,根據最後一個 sql 來查詢線索。 

 當你確定了 crash 的原因後,應該檢查一下 MySQL 的 bug 庫(),通常採用 Advanced search,看看有沒有類似的問題。如果你找到了可能與你相關的 bug,確認它是否修復了。如果已經修復了,那麼把 MySQL 升級到 bug 已經修復的版本。


在每個版本的 Release Notes 裡面有一節 Bugs Fixed ,可以查到修復的 bug 。

MySQL 申請系統資源失敗或記憶體洩漏

記憶體不足或 MySQL 申請系統資源失敗外都會造成 MySQL 崩潰,例如磁碟空間滿了,磁碟上的檔案 corrupt 等。此時需要定位 crash 的根本原因有下面幾種方法:

 1. 仔細閱讀 MySQL 的錯誤日誌,這個日誌裡面的一些程式除錯資訊看起來很讓人困惑,但靜下心來仔細看,很多時候會找到線索;  

 2. 開啟 general query log ,找到最後一個 sql 訪問的表或索引,檢查這個表或索引,如果有問題就重建,通常可以解決問題。 

 4. 使用 strace、pstack、pmap、gdb 分析 mysqld 的程式碼,可能需要開啟 core dump; 

 5. 使用 CMake 的選項 -DWITH_DEBUG=1 重新編譯 mysqld,然後執行重新編譯後的 mysqld,檢視 trace 檔案、error log 進行排錯。

  MySQL 記憶體佔用的計算

  全域性記憶體

 innodb_buffer_pool_size   innodb_log_buffer_size  thread_cache_size table_open_cache  table_definition_cache key_buffer_size 

執行緒記憶體

 binlog_cache_size thread_stack

單次操作記憶體

 join_buffer_size  read_buffer_size read_rnd_buffer_size tmp_table_size  sort_buffer_size

計算公式

  MySQL 8 中最大記憶體佔用參考值計算公式:


SELECT ( @@innodb_buffer_pool_size + @@innodb_log_buffer_size + @@key_buffer_size 
+ @@max_connections * (@@binlog_cache_size + @@thread_stack + @@read_buffer_size 
+ @@read_rnd_buffer_size + @@sort_buffer_size + @@join_buffer_size + @@tmp_table_size ) 
) / 1024 /1024 AS MAX_MEM_MB;

innodb_buffer_pool_size

+ key_buffer_size

+ max_connections*(sort_buffer_size+read_buffer_size+binlog_cache_size)

+ max_connections*2MB


臨時解決可以使用下面的命令釋放快取:

echo 1 > /proc/sys/vm/drop_caches

0:0是系統預設值,預設情況下表示不釋放記憶體,由作業系統自動管理

1:釋放頁快取

2:釋放dentries和inodes

3:釋放所有快取

 從長遠看還是要修改對應的引數進行解決。

MySQL 客戶端的記憶體洩漏

MySQL 客戶端的記憶體洩漏時通常會有下面的提示

`

mysql: Out of memory at line 42, 'malloc.c'
mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k)
ERROR 2008: MySQL client ran out of memory

這通常是客戶端收到的返回結果集太大造成的,解決辦法有兩種:

 1. 檢查正在執行的 SQL ,看看您真的需要這麼大的返回結果集嗎?

 2. 允許 mysql 時加上 --quick 選項,這會減少客戶端單次收到的返回集,但會增加 mysqld 的負載。

 



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70018393/viewspace-2900264/,如需轉載,請註明出處,否則將追究法律責任。

相關文章