天天看點

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檢視資料庫中連接配接到底在等待些什麼:

RDS彈性更新後性能反而下降的排查

#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清單可以參考:

http://bugs.mysql.com/bug.php?id=64284

http://bugs.mysql.com/bug.php?id=51325

         該如何解決此問題?其實有三種辦法,第一就是在将使用者的執行個體記憶體降級,減小drop期間的影響;第二就是将執行個體的版本更新到5.6版本;第三就是調整應用中的業務,優化drop table的業務。最終采取了最簡單的辦法,就是把執行個體的記憶體降低回原來的規格後,應用恢複正常。

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