線上事故處理記錄
一、MySQL 導致的服務器 CPU 飆升
有一天,突然收到了服務器 CPU 飆升的告警信息,打開普羅米修斯查看 CPU 的使用情況,發現 CPU 確實飆升了,下面開始去進行問題定位了。 1. 首先連接到對應的服務器,然后執行
top
查看導致 CPU 飆升的進程是什么,發現是 mysqld 進程導致的
- 進入 MySQL 服務器中,執行下面的命令
show processlist
補充: show processlist 命令的主要用途
- 查看當前有哪些客戶端連接
- 查看當前執行的 SQL 語句,能看到慢 SQL、長時間阻塞的查詢等
- 排查鎖等待、死鎖等問題,發現“Locked”的狀態,表示線程在等待鎖
- 排查連接數過多問題,判斷是否有連接未正確釋放或連接池配置不當
其實,此時通過查看結果,我基本可以確認是慢 SQL 導致的問題了,但是我還不能那么 100%確認,為了保險起見,我是這么處理的,我先將對應的 SQL 粘出來,然后使用 kill 命令將對應的線程殺死,來判斷是不是因為這個查詢 sql 導致的 CPU 飆升,結果發現確實 kill 之后,CPU 有所下降,那么說明這個 sql 肯定性能很差,先不說別的,這個 SQL 肯定要先優化一下
- 使用 explain 去分析這個 sql
# 舉個例子而已,不是真實的sql,不要較真偶
explain select xxx from table where code='xxx';
發現這個 SQL 沒有使用索引,于是我去表中查看了一下表結構,發現確實在 code 這個字段上是沒有索引的,于是給這個 code 增加了一個唯一索引,重新 explain 分析這個 SQL,發現效果大大提高
- 正當我認為這個問題被我處理完之后,沒想到過了幾分鐘,又出現問題了,出現了大量請求超時問題,接著分析,發現是開啟了慢日志查詢,有很多 SQL 超過了設置的慢查詢閾值。于是我將慢日志查詢關閉,CPU 又有所下降,但是發現還不是特別理想。
- 接下來怎么做呢?我是這么想的,在 MySQL 這層我已經做了優化了,剩下的只能去看代碼邏輯了,看看他是如何處理的,然后我就去扒代碼,結果發現沒有使用緩存,所有的查詢都是直接走的 DB,所以我增加了 Redis 緩存層,重新發布后,發現 CPU 確實穩定下來了,也沒有再進行飆升。
補充:
在最后再補充一下,有時候 MySQL 層出現問題可能是由于大量的連接導致的,這個時候就要分析為什么有大量的連接同時過來,以及設置一個比較合理的連接數。
本次事故總結: 本次事故是因為沒有做好數據庫評審,由于開發人員沒有建立索引導致慢 SQL 的出現;以及所有查詢都走 DB 沒有使用緩存層導致 MySQL 壓力大。
二、Java 進程導致 CPU 飆升
依然是先收到了 CPU 超載的告警信息,然后去普羅米修斯上看了一下,CPU 一直持續在高負荷,然后我進到對應的服務器中。
-
首先執行 top 命令
top
查看導致 CPU 飆升的進程是什么,發現是對應的 Java 進程導致的 CPU 飆升
-
執行
top -Hp PID
來查看對應的 Java 進程中的線程的資源占用情況,發現有多個線程 CPU 的利用率達到了 99.9%
-
將堆棧信息導出來
jstack -l 進程ID >/jstack_result.txt
4.堆棧信息導出來了,那么多內容如何快速定位到出現問題的線程代碼呢,那么需要將第 2 步得到的線程 PID 轉成對應的 16 進制
printf "%xn" PID
然后在堆棧信息中搜索 記得前面可以加一個 0x 開頭
這樣就可以定位到具體的代碼行數了,你就可以去到代碼里面看看是什么問題了
在這里我通過定位發現了一直在空循環,所以導致 CPU 飆升。 gggg…
本次問題總結:代碼評審沒做到位!!!