mysql5.7 只读视图_MySQL 5.7: Innodb read view在只读场景的优化

额,这个标题有点大,实际上只是我在测试5.7性能过程中遇到的一个问题的解惑.不包含5.7的全部read view优化

———–

最近在测试 MySQL5.7 的只读性能时,和5.6版本对比,发现一个有趣的现象,即在我们的内部版本5.6里,trx_sys->mutex排名第一,而5.7版本则几乎完全看不到该mutex,测试的负载也比较简单,sysbench,使用auto-commit的pk查询

先来看看 performance schema 的输出:

MySQL5.6.16( heavily patched)

root@performance_schema 11:45:34>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 |

+————+——————+—————-+—————————————————+

| 67106658 | 2191100230566684 | 32650732 | wait/synch/mutex/innodb/trx_sys_mutex |

| 33431350 | 116859287127016 | 3495412 | wait/synch/rwlock/sql/LOCK_grant |

| 67160439 | 89180859682708 | 1327620 | wait/synch/rwlock/sql/MDL_lock::rwlock |

| 63988674 | 67704502627896 | 1057736 | wait/synch/mutex/sql/MDL_map::mutex |

| 67087915 | 47565299538868 | 708936 | wait/synch/mutex/sql/LOCK_table_cache |

| 253945845 | 24152737750000 | 95048 | wait/synch/mutex/sql/THD::LOCK_thd_data |

| 67076196 | 21521813780432 | 320460 | wait/synch/mutex/mysys/THR_LOCK::mutex |

| 101588861 | 19607984308264 | 192712 | wait/synch/rwlock/innodb/hash_table_locks |

| 181625203 | 14086715074644 | 77172 | wait/synch/mutex/innodb/trx_mutex |

| 90361030 | 9755600019708 | 107692 | wait/synch/mutex/innodb/trx_undo_mutex |

| 33554506 | 5639702314236 | 167860 | wait/synch/rwlock/innodb/index_tree_rw_lock |

| 397299 | 97044675080 | 244160 | wait/synch/mutex/innodb/os_mutex |

| 43 | 37606650696 | 874573272 | wait/synch/mutex/sql/LOG::LOCK_log |

| 20152 | 7952989672 | 394580 | wait/synch/mutex/sql/LOCK_open |

| 19316 | 4096687392 | 211896 | wait/synch/mutex/innodb/innobase_share_mutex |

| 28983 | 3267197392 | 112488 | wait/synch/mutex/innodb/dict_sys_mutex |

| 10848 | 1396710304 | 128620 | wait/synch/mutex/innodb/buf_pool_mutex |

| 8791 | 820647920 | 93304 | wait/synch/mutex/sql/LOCK_global_system_variables |

| 4579 | 765776448 | 166988 | wait/synch/mutex/sql/LOCK_plugin |

| 9659 | 522640176 | 54064 | wait/synch/mutex/innodb/file_format_max_mutex |

+————+——————+—————-+—————————————————+

MySQL5.7.5

root@performance_schema 03:01: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 |

+————+—————-+—————-+—————————————————+

| 6205753 | 5513113478224 | 888132 | wait/synch/rwlock/sql/LOCK_grant |

| 12428382 | 4463207301384 | 358828 | wait/synch/mutex/sql/LOCK_table_cache |

| 34298703 | 4162953914096 | 121208 | wait/synch/mutex/sql/THD::LOCK_query_plan |

| 18881544 | 4085456883944 | 216256 | wait/synch/sxlock/innodb/hash_table_locks |

| 20546361 | 2594608664108 | 126004 | wait/synch/mutex/sql/THD::LOCK_thd_data |

| 6232362 | 1653423256736 | 265088 | wait/synch/sxlock/innodb/index_tree_rw_lock |

| 13699272 | 1590037239708 | 115976 | wait/synch/mutex/sql/THD::LOCK_thd_query |

| 29688 | 2876063536 | 96792 | wait/synch/mutex/innodb/fil_system_mutex |

| 16923 | 2151605936 | 126876 | wait/synch/mutex/innodb/buf_pool_mutex |

| 5214 | 559759472 | 107256 | wait/synch/mutex/innodb/log_sys_mutex |

| 1664 | 355917264 | 213640 | wait/synch/mutex/innodb/innobase_share_mutex |

| 2614 | 291241024 | 111180 | wait/synch/mutex/innodb/dict_sys_mutex |

| 1683 | 251709776 | 149548 | wait/synch/mutex/sql/LOCK_open |

| 945 | 148695184 | 156960 | wait/synch/mutex/innodb/file_format_max_mutex |

| 1683 | 132639920 | 78480 | wait/synch/mutex/sql/LOCK_global_system_variables |

| 896 | 83248096 | 92868 | wait/synch/mutex/innodb/flush_list_mutex |

| 234 | 69119952 | 295172 | wait/synch/mutex/sql/LOCK_connection_count |

| 598 | 58556544 | 97664 | wait/synch/mutex/sql/LOCK_plugin |

| 117 | 46728736 | 399376 | wait/synch/mutex/sql/LOCK_transaction_cache |

| 286 | 44845216 | 156524 | wait/synch/mutex/sql/LOCK_thd_list |

+————+—————-+—————-+—————————————————+

20 rows in set (0.54 sec)

很奇怪,在5.7里几乎完全看不到trx_sys mutex,而在我们优化版本里,却非常的明显,直接排在第一位了。

简单看了下代码,在5.6里read_view_remove 需要持有try sys mutex锁。而在5.7里,对应MVCC::view_close 对于只读事务无需持有trx_sys->mutex

另外一个原因是,在分配read view时,5.7是有针对性的对纯读场景下的视图做了优化,可以直接重用。

也就是说,对于只读场景,无论是read view的分配还是释放,都无需获取trx_sys->mutex.

以下简单的介绍下相关逻辑。

0.新的结构体MVCC,用来管理所有的read view

MVCC类的对象挂在trx_sys->mvcc上,在初始化事务子系统时创建

trx_sys->mvcc = UT_NEW_NOKEY(MVCC(1024));

(5.7里使用统一的接口来分配 和释放内存 ,主要是为了能监控内存的使用状况

1024表示默认默认初始缓存的readview个数

)

MVCC:

在5.7里采用缓存rearview的方式避免过多的分配/释放readview内存,因此创建了两个链表:

m_free : 表示当前空闲的read view

m_views:表示当前活跃的read view

初始化时所有的read view 都加入到空闲链表上。

1.赋予readview

row_search_mvcc->trx_assign_read_view->MVCC::view_open

两种情况,一种是重用已经为当前事务分配了readview (事务结束后依然属于该事务对象,而不是直接回收),另外一种情况是从空闲链表上新分配read view.

对于前者,如果当前会话只读事务 并且没有活跃读写事务,那么该read view可以被重用。如果当前存在读写事务,则需要将该read view从m_views移除,走正常分配流程.

在分配readview对象时,如果m_free上没有空闲的,那么就重新malloc一个新的rearview对象.

对于重用的场景,理论上应该可以做更近一步的优化.这里重用的逻辑还是太简单粗暴了,必须在只读场景下才能直接重用readview.

2.关闭readview

trx_commit_in_memory->MVCC::view_close

这里也分两种情况:

第一种情况,在auto-commit-read-only场景下,无需持有trx_sys mutex,直接将read view设置为关闭

ptr->m_closed = true;

而对于读写事务,则需要从MVCC::m_views链表中移除并加入到MVCC::m_free链表上。这需要持有trx_sys->mutex

另外一个关闭readview的trace:

in ha_innobase::external_lock->MVCC::view_close, 也就是read-commit级别,如果显式的开启事务,不管是不是只读的,都需要关闭事务,并在下一条SQL再次打开read view.这种情况下的read view是不可重用的。

3.purge线程

purge线程总是需要根据最老的视图clone一个readview,以确定哪些数据可以被purge掉。

trx_sys->mvcc->clone_oldest_view(&purge_sys->view)

这里会逆序遍历m_views,找到一个状态不是被closed的read view,然后继续。

4.问题

在关闭read view时,总是要对read view指针 (p & ~1),也就是最低位置0,如果需要重用read view时,就将read view 低位置1 (reinterpret_cast(p | 0x1))

而在重用read view时,又将read view的低位恢复为0,这种修改指针的方式看起来是安全的,因为内存总是在偶数位上开始分配

不过没想通这么干的含义,除了标示这个read view被close了并且可能被事务重用外,没看到别的用途.

后面再仔细看看.

5.TODO

根据上述,我们可以针对性的改造5.6的MVCC子系统。

当前我们的内部分支已经合并了percona对事务系统的优化, readview对象被缓存到prebuilt_view中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值