最近,一个同事因为有数百表已经废弃,所以打算将表drop掉已回收掉使用的空间。其实每张表的数据量很小,但是我们看到每次drop的时候大量的query 被堵塞了,用户反映超时报错的情况,所以这里对这个问题做了一个小的探讨(本帖的讨论基于mysql5.1) 。
由于product 环境大部分情况下设置的innodb_file_per_table=1,所以每个table一个tbs,每次删除表都要对物理文件.ibd进行delete。由于要删除物理文件,所以该物理文件对应的dirty page也要clean掉。所以这个时候,innodb触发了两个操作:
1.调用buf_LRU_invalidate_tablespace 遍历buffer pool LRU list,将所有space id为该表的page flush 到disk,并将该page移动到buffer pool LRU list 的尾端。
2. buf_LRU_invalidate_tablespace 会调用buf_LRU_block_remove_hashed_page 将该表对应的AHI(adaptive hash index) destory掉。
但上述的操作会调用一个global buffer pool mutex,避免在invalidate或者drop过程中,page发生移位(page是随时随地在变动的),防止page被遗漏。
在目前公司的生产环境中,buffer pool为40G左右,~2M的pages存在BP中,每个LRU list scan大概0.5s,单张表的操作大概就会有1s时间在scan LRU list.所以在线上库删除废弃的table,如果涉及上百/上千张表,就可能导致长时间不可用状态 。
facebook mark给出了几个可以缓解这个行为带来后果的建议
1.通过一个flush list来记录那些dirty page(通过引入buf_LRU_remove_dirty_pages_for_tablespace函数来实现),这样每次调用buf_LRU_invalidate_tablespace只需要scan flush list即可,由于flush list相比buffer pool LRU list小很多,所以每次操作持有mutex的时间会短很多。
2.每次一个batch(1024个page)来操作,操作后sleep 一段时间,然后下次继续,只到该操作完成为止。
当然对与AHI的destroy这里并没有进行更详细的优化。
所以对目前的现状,如果为了不影响业务,建议drop table 先rename掉,然后在低峰时段+sleep的方式回收 。
阅读(3384) | 评论(0) | 转发(0) |