且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

RDS弹性升级后性能反而下降的排查

更新时间:2022-08-12 18:08:40

         刚刚结束的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的操作)。