1. 程式人生 > >讓天下沒有難用的資料庫 » RDS彈性升級後效能反而下降的案例

讓天下沒有難用的資料庫 » RDS彈性升級後效能反而下降的案例

剛剛結束的2015年雙11,天貓以912億的成交量再次打破去年的記錄成為一個奇蹟,大家可能不知道,這些天貓的訂單最後的處理都是放在阿里雲聚石塔的機房完成,從2012年開始,淘寶的ISV,商家就開始把他們的訂單,CRM後臺系統逐漸遷移到雲上,最核心的資料庫就是存放在RDS中。

雙11之前使用者都會進行大批量的彈性升級,期間有較多使用者反饋,在彈性升級後效能出現了大幅度的下降,其中由一個使用者有兩個RDS,一個RDS進行了彈性升級,另外一個RDS沒有出現彈性升級,結果彈性升級後的RDS反而出現了效能下降,這讓我們反思不得其解。RDS的彈性升級包括了兩部分,一部分是磁碟容量的升級,另一部分是記憶體容量的升級(記憶體升級會同時升級資料庫的連線數,CPU,IOPS),那麼是什麼原因導致了效能下降?

1.是不是彈性升級後,後端的DB效能提升,前端的流量增加,導致後端DB響應緩慢?

通過後端的監控檢視,資料庫的QPS並沒有顯著的增加,但是RT卻是增加了許多,所以此種情況排除。

2.是不是SQL的執行計劃發生改變,導致資料庫的效能降低?

通過監控發現即使是普通的insert 語句也會出現執行緩慢的情況,慢日誌出現了較多非常簡單的SQL,所以此種情況排除。

3.看到有非常簡單的SQL也執行緩慢,排查主機是否存在資源瓶頸?

通過監控顯示,例項所在的物理主機的壓力非常的低,不是主機的資源爭搶導致的效能瓶頸,所以此種情況排除。

4.在排除了以上可能的情況後,在資料庫連接出現較多連線堆積的時候,進行一次pstack檢視資料庫中連線到底在等待些什麼:

#0  0x00000000008d3fd9 in buf_LRU_invalidate_tablespace ()#1  0x0000000000904ef6 in fil_delete_tablespace ()
#2  0x00000000008627cf in row_drop_table_for_mysql ()
#3  0x000000000084d64e in ha_innobase::delete_table(char const*) ()
#4  0x0000000000554368 in rm_temporary_table(handlerton*, char*) ()
#5  0x0000000000556ea2 in close_temporary(TABLE*, bool, bool) ()
#6  0x000000000055a878 in drop_temporary_table(THD*, TABLE_LIST*, bool*)
#7  0x0000000000600939 in mysql_rm_table_no_locks(THD*, TABLE_LIST*)
#8  0x00000000006016dd in mysql_rm_table(THD*, TABLE_LIST*, char, char) ()
#9  0x0000000000599b35 in mysql_execute_command(THD*) ()
#10 0x0000000000788629 in sp_instr_stmt::exec_core(THD*, unsigned int*) ()
#11 0x000000000078d267 in sp_lex_keeper::reset_lex_and_exec_core(THD*, unsigned int*, bool, sp_instr*) ()
#12 0x000000000078d724 in sp_instr_stmt::execute(THD*, unsigned int*) ()
#13 0x000000000078b1b3 in sp_head::execute(THD*, bool) ()
#14 0x000000000078c587 in sp_head::execute_procedure(THD*, List<Item>*)
#15 0x0000000000597f84 in mysql_execute_command(THD*) ()
#16 0x000000000059bed4 in mysql_parse(THD*, char*,  Parser_state*) ()
#17 0x000000000059deac in dispatch_command(enum_server_command, )
#18 0x0000000000641b8d in do_handle_one_connection(THD*) ()
#19 0x0000000000641cdc in handle_one_connection ()
#20 0x0000003bd6807851 in start_thread () from /lib64/libpthread.so.0
#21 0x0000003bd64e767d in clone () from /lib64/libc.so.6

看到了buf_LRU_invalidate_tablespace 這個函式後,其實就豁然開朗了,使用者業務中頻繁的drop table,在5.5版本DROP TABLE操作會對innodb的整個buffer pool的LRU鏈進行兩次掃描(DROP期間的掃描操作會持有buf_pool::mutex,導致整個資料庫hang主),如果記憶體很大,則會導致阻塞時間加長(5.6版本改進只掃描flush list,則會大大降低影響),相關的bug列表可以參考:

該如何解決此問題?其實有三種辦法,第一就是在將使用者的例項記憶體降級,減小DROP期間的影響;第二就是將例項的版本升級到5.6版本;第三就是調整應用中的業務,優化Drop table的業務。最終採取了最簡單的辦法,就是把例項的記憶體降低迴原來的規格後,應用恢復正常。

這是今年雙11比較普遍的一個問題,使用者升級完規格後效能反而出現下降,所以如果你的應用中如果有大量的drop table,同時資料庫的版本是MySQL 5.5,則建議升級到5.6版本(注意5.6版本開啟了GTID,應用程式中不要有create  temporary table的操作)。