如下來分享一個關於MySQL數據庫慢查詢和FGC頻繁的性能案例。html
1、系統架構java
一個簡單的dubbo服務,服務提供者提供接口,而且提供接口的實現,提供方註冊服務到Zookeeper註冊中心,而後消費者要用其某個服務的時候,就去zookeeper上訂閱該服務。這樣,咱們只須要使用接口,而後經過spring getbean,就可讓這個接口實例化,拿來使用,經過傳參去Mysql數據庫查詢數據。mysql
同時由於消費者只能獲得接口,而沒法看到接口的實現,也保證了服務者的安全。spring
服務註冊與調用sql
腳本實現接口調用數據庫
關於如何編寫dubbo服務腳本可參考上篇文章: https://www.cnblogs.com/zhang-zhi/p/9929447.html安全
2、現象及問題服務器
上圖爲10用戶併發時,系統的總體性能表現,包括TPS與平均響應時間指標。架構
從上圖能夠看出,該系統主要存在如下方面幾個問題:併發
一、其中一個事務響應時間過長,超過1秒;
二、部分接口響應時間波動較大;
三、系統業務處理能力:即TPS,存在波動且起伏加大。
3、分析思路及解決方法
主要分析思路能夠從如下幾個方面考慮:
一、業務問題,系統代碼自己業務邏輯問題,如:事務失敗率;
二、系統服務器資源出現瓶頸致使,如:CPU、內存、I/O等;
三、數據庫層面問題,如:慢查詢;
四、java應用的堆內存相關;
五、受第三方系統的問題影響;
六、其它方面等等。
問題排查及解決
一、首先,controller中系統沒有出現業務失敗,查看日誌,沒有發現有錯誤日誌,因此能夠初步排查代碼邏輯處理失敗;
二、其次,先解決比較明顯的問題,那個響應時間過長的接口,一般咱們先想到的就是可能存在慢查詢問題;
打開慢查詢:
1 mysql> show variables like "slow_query_log%"; 2 +-----------------------------------+---------------------------------+ 3 | Variable_name | Value | 4 +-----------------------------------+---------------------------------+ 5 | slow_query_log | ON | 6 | slow_query_log_always_write_time | 10.000000 | 7 | slow_query_log_file | /disk1/mysql5.7.21/tmp/slow.log |//慢查詢日誌存放路徑 8 | slow_query_log_use_global_control | | 9 +-----------------------------------+---------------------------------+ 10 4 rows in set (0.00 sec) 11 //設置慢查詢開關,0表明關閉慢查詢,1表明打開慢查詢。 12 mysql> set global slow_query_log = 1; 13 Query OK, 0 rows affected (0.00 sec) 14 //查看慢查詢時間 15 mysql> show variables like "long_query%"; 16 +-----------------+----------+ 17 | Variable_name | Value | 18 +-----------------+----------+ 19 | long_query_time | 2.000000 | 20 +-----------------+----------+ 21 1 row in set (0.00 sec) 22 //設置慢查詢爲1秒 23 mysql> set long_query_time=1; 24 Query OK, 0 rows affected (0.00 sec) 25 26 mysql>
經過查看慢查詢日誌,找到慢查詢sql,以下:
①接下來,對找到的sql進行分析,查看sql執行計劃:
如何查看執行計劃:
1 mysql> explain select * from test; 2 +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ 3 | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | 4 +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ 5 | 1 | SIMPLE | test | NULL | index | NULL | PRIMARY | 4 | NULL | 6 | 100.00 | Using index | 6 +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ 7 1 row in set, 1 warning (0.00 sec) 8 9 mysql>
如下是本次發現慢查詢sql的執行計劃:
其中最重要的字段爲:id、type、key、rows、Extra
一、id:select查詢中的序列號,包含一組數字,表示查詢中執行select字句或操做表的順序;
二、type:訪問類型,sql查詢優化一個很重要的指標,結果值從好到壞依次是:
System>const>eq_ref>ref>fulltext>ref_or_null>index_merge>uniqe_subquery>index_subquery>range>index>ALL,通常來講,好的sql查詢至少能達到range級,作好爲ref。
三、Key:實際使用的索引,若是未NULL,則沒有使用索引;
四、rows:根據表統計信息及索引選取狀況,大體估算出找到所需的記錄所須要的行數,通常該值越小越好;
五、Extra:不適合在其它字段中顯示,可是十分重要的額外信息。
從sql的執行計劃明顯能夠看出,sql缺乏相應的索引致使出現慢查詢問題,與開發確認後,添加索引後,該接口的響應時間明顯變快,如下爲添加索引後的sql執行計劃。
②也能夠打開profile功能,對sql進行分析,看時間具體消耗在哪裏
1 mysql> show variables like "%profiling%"; 2 +------------------------+-------+ 3 | Variable_name | Value | 4 +------------------------+-------+ 5 | have_profiling | YES | 6 | profiling | OFF | 7 | profiling_history_size | 15 | 8 +------------------------+-------+ 9 3 rows in set (0.00 sec) 10 //設置profiling開關,1表明打開,0表明關閉 11 mysql> set profiling=1; 12 Query OK, 0 rows affected, 1 warning (0.00 sec) 13 //執行sql語句 14 mysql> select * from test; 15 +----+ 16 | id | 17 +----+ 18 | 1 | 19 | 2 | 20 | 3 | 21 | 4 | 22 | 5 | 23 | 6 | 24 | 10 | 25 +----+ 26 7 rows in set (0.00 sec) 27 //查看profiles文件 28 mysql> show profiles; 29 +----------+------------+--------------------+ 30 | Query_ID | Duration | Query | 31 +----------+------------+--------------------+ 32 | 1 | 0.00037925 | select * from test | 33 +----------+------------+--------------------+ 34 1 row in set, 1 warning (0.00 sec) 35 //查看profile文件中,第一個查詢的profile狀況,查看時間消耗在哪裏 36 mysql> show profile for query 1; 37 +----------------------+----------+ 38 | Status | Duration | 39 +----------------------+----------+ 40 | starting | 0.000065 |//開始 41 | checking permissions | 0.000009 |//檢查權限 42 | Opening tables | 0.000043 |//打開表 43 | init | 0.000027 |//初始化 44 | System lock | 0.000014 |//系統鎖 45 | optimizing | 0.000004 |//優化 46 | statistics | 0.000016 |//統計 47 | preparing | 0.000011 |//準備 48 | executing | 0.000002 |//執行 49 | Sending data | 0.000113 |//發送數據 50 | end | 0.000004 |//結束 51 | query end | 0.000008 |//查詢結束 52 | closing tables | 0.000008 |//關閉表/刪除TEMP表 53 | freeing items | 0.000022 |//釋放items 54 | cleaning up | 0.000037 |//清理 55 +----------------------+----------+ 56 15 rows in set, 1 warning (0.00 sec)
慢查詢sql的profiling結果爲:
優化後的sql profiling結果:
優化後,單筆查詢響應時間大大縮短,約爲2毫秒
三、系統業務處理能力弱且TPS波動較大問題,能夠先查看系統應用服務器或其它一些組件的CPU資源使用率及線程棧信息,看是否存在線程阻塞或死鎖問題。
nmon查看CPU資源使用狀況
vmstat -Sm 1--查看系統內存、cpu等資源使用狀況
CPU、內存資源消耗能夠看出,一切都很很正常,經過jstack命令查看線程棧信息,也不存在線程阻塞及死鎖問題,因此能夠排除這方面的緣由。
由於系統TPS波動很大,咱們能夠看一下系統的GC狀況。
jstat -gcutil pid 1000
發現FGC頻繁,大約2秒一次,找到問題所在,接着看一下JVM的對內存分配狀況
jmap -heap pid
解決方法:
將JVM的啓動參數設置爲:-Xms4096M -Xmx4096M,重啓系統,在一樣的壓力下,進行測試,獲得優化後的測試結果爲:
TPS截圖:
RT截圖:
優化後,系統性能表現明顯提高,TPS能夠達到3000筆/秒,系統響應時間約爲100毫秒,完成知足系統上線要求。