MySQL table cache的分区方式

今天在跑高压力高并发下只读查询时,发现个比较有意思的小问题

先来看看performance schema

root@performance_schema 03:13:45>SELECT COUNT_STAR, SUM_TIMER_WAIT, AVG_TIMER_WAIT, EVENT_NAME FROM events_waits_summary_global_by_event_name where COUNT_STAR > 0 and EVENT_NAME like ‘wait/synch/%’ order by SUM_TIMER_WAIT desc limit 20;
+————-+——————+—————-+—————————————————+
| COUNT_STAR | SUM_TIMER_WAIT | AVG_TIMER_WAIT | EVENT_NAME |
+————-+——————+—————-+—————————————————+
| 794349716 | 9217250429384944 | 11603268 | wait/synch/mutex/sql/LOCK_table_cache |
| 395819330 | 8052052171747844 | 20342452 | wait/synch/rwlock/sql/LOCK_grant |
| 18792871674 | 3690042369314320 | 196200 | wait/synch/mutex/sql/THD::LOCK_query_plan |
| 11274795644 | 2143435212448448 | 190096 | wait/synch/mutex/sql/THD::LOCK_thd_data |

可以看到,目前排名最高的是LOCK_table_cache。 从backtrace中发现如下堆栈(简化版本):

18 __lll_lock_wait(libpthread.so.0)…,lock(thr_mutex.h:61),

open_table(thr_mutex.h:61),open_and_process_table(sql_base.cc:4903),open_tables(sql_base.cc:4903),

open_normal_and_derived_tables(sql_base.cc:6084),execute_sqlcom_select(sql_parse.cc:5004),……

大量线程被堵塞在open_table这里了,我们来看看具体的代码 (quoted from 5.7.5, sql/sql_base.cc)

3172 retry_share:

3173   {

3174     Table_cache *tc= table_cache_manager.get_cache(thd);

3175

3176     tc->lock();

3177

3178     /*

3179       Try to get unused TABLE object or at least pointer to

3180       TABLE_SHARE from the table cache.

3181     */

3182     table= tc->get_table(thd, hash_value, key, key_length, &share);

3183

我们知道从5.6开始可以对table cache进行分区,参数table_open_cache_instances来控制分区的个数,从而消除了之前版本的热点锁LOCK_open.

之前没看过这部分的代码,一直以为是根据表名之类的来进行分区的,今天才发现是根据线程id进行分区.

155   /** Get instance of table cache to be used by particular connection. */

156   Table_cache* get_cache(THD *thd)

157   {

158     return &m_table_cache[thd->thread_id() % table_cache_instances];

159   }

这种分区方式可以避免例如热点表这样的场景,但也可能带来负面的影响,例如别的分区里可能有大量空闲的TABLE对象,而当前线程的分区中没有,这种情况下依然要创建TABLE对象加入到当前分区中。

另外LOCK_open并不是能完全避免的,当无法从table cache中找到TABLE对象时,依然要持有LOCK_open来检查TABLE_SHARE的版本是否是有效的。不过创建TABLE对象及加入hash的过程无需持有LOCK_open。

原创文章,转载请注明: 转载自Simple Life

本文链接地址: MySQL table cache的分区方式

Post Footer automatically generated by wp-posturl plugin for wordpress.


Comments

Leave a Reply

Your email address will not be published. Name and email are required


Current month ye@r day *