HTML5 apache Firefox mysql google Android Windows nginx linux命令 程序员 wordpress linux 微软 php java 开源 Python centos Ubuntu shell

只读场景下InnoDB的性能优化

数据库的读写分离听起来非常简单,但在实现上却没有那么容易。其原因为读写事务中往往有着关联关系,例如读被更改的记录。但如果业务为只读事务,读事务中不会涉及到任何被写事务中更新的记录,那么这个场景相对于原先传统的读写混合设计思维下的逻辑,肯定会有大大的优化空间。另外,在读写混合场景下,特别是偏读业务场景,因为活跃的事务绝大部分是读事务,会更改记录的只是极小部分的写事务,如果能将读事务优化,相应的写事务也应该会有提高。

只读场景下优化,目前我所知道的优化大致有如下两类:

1. 将InnoDB层的事务进行区分:只读事务和读写事务。
这是很容易想到的,读事务在创建读视图时,看到的活跃事务不再是所有的事务,而是当前的读写事务。

2. 将InnoDB层的事务MVCC关键逻辑优化:减少活跃事务相关的操作关键路径上的耗时。
这是传统意义上来优化只读事务:减少只读事务所创建的读视图的开销。

基于思路1)的典型实现中为Oracle mysql-5.6中只读事务和读写事务的分离。在autocommit=1下,select偏多的场景的确有较大的性能提升;对于autocommit=0,虽然官方提供 START TRANSACTION read ONLY 的语法,但在实现场景下很难推广。

基于思路2)的典型实现中,我所了解到就是Percona对读视图的优化。其优化核心思路为:将当前活跃事务列表的线性遍历查询转化为二分查找,从而将原先的依次内存拷贝转为批量内存拷贝。在我的测试没影场景下,只读有2倍性能提升,读写有1.5倍提升。

下面是我读代码所理解的优化。

实现上对trx_list的改变:

a. 每个trx在各自的heap中分配review空间,不再在各自的heap中,取而用malloc/free替代。
b. 增加合局的 trx_sys->trx_serial_list,以trx_no递增排序。
c. 每个view的trx_ids中的trx_id为严格递减 => percona 改为递增,性能有提升。
d. 增加descriptors,以trx_id递增排序。

关键的几个函数优化:

a. read_view_sees_trx_id 将线性查找优化为bsearch
b. trx_is_active 通过id在trx_ids中找对应的事务是否active, 优化成 bsearch(trx_sys->descriptors)
c. read_view_open_now 遍历trx_sys->trx_list 构造 view->trx_ids,优化成bsearch, 然后2步memcpy(view->descr, trx_sys->descr, i*sizeof(trx_id_t))。另外,将trx_serial_list的遍历寻找view->low_limit_no,优化为直接与第一个元素的比较。
d. read_cursor_view_create_for_mysql 同上

延伸阅读

评论