MySQL 5.6.12的Innodb性能改进

简介:
简单的记录下,在MySQL5.6.12中innodb层的3点跟性能相关的改进
1.在文件操作部分,移除了许多sleep操作,而是改用condition wait
对应的bug  http://bugs.mysql.com/bug.php?id=68588。 在Mark的测试中,有近一倍的性能提升
主要修改都几种在函数fil_flush中:
每个文件结构体node都增加了一个event:
fil_node_create:
     node->sync_event = os_event_create();
fil_node_free:      
  os_event_free(node->sync_event)

fil_flush:

当文件上已经有线程在做flush时:
5638                 if (node->n_pending_flushes > 0) {
5639                         /* We want to avoid calling os_file_flush() on
5640                         the file twice at the same time, because we do
5641                         not know what bugs OS's may contain in file
5642                         i/o */
5643
5644                         ib_int64_t sig_count =
5645                                 os_event_reset(node->sync_event);
5646
5647                         mutex_exit(&fil_system->mutex);
5648
5649                         os_event_wait_low(node->sync_event, sig_count);
5650
5651                         mutex_enter(&fil_system->mutex);
5652
5653                         if (node->flush_counter >= old_mod_counter) {
5654
5655                                 goto skip_flush;
5656                         }
5657
5658                         goto retry;
5659                 }

5661                 ut_a(node->open);
5662                 file = node->handle;
5663                 node->n_pending_flushes++;
5664
5665                 mutex_exit(&fil_system->mutex);
5666
5667                 os_file_flush(file);
5668
5669                 mutex_enter(&fil_system->mutex);
5670
5671                 os_event_set(node->sync_event);
5672
5673                 node->n_pending_flushes--;

 

好吧,我承认我摘录上述代码的目的,只是简单记录下innodb condition wait的用法…
2.用户线程在查找空闲block,会刷单个page,这可能导致sync所有的文件
用户线程做了single page flush后,加入一个IO异步请求队列后,会调用 buf_flush_sync_datafiles.随后会唤醒IO线程,并在之后fsync所有的数据文件。           
该bzr主要修改包括:
* 所有batch flush操作异步进行(和以前一样)
buf_dblwr_flush_buffered_writes:
914         for (ulint i = 0; i < first_free; i++) {
915                 buf_dblwr_write_block_to_datafile(

916                         buf_dblwr->buf_block_arr[i], false);              // false表示异步写

917         }

* single page flush以寻找一个空闲块,这是同步操作
buf_flush_single_page_from_LRU->buf_flush_page->buf_flush_write_block_low->buf_dblwr_write_single_page
1130         /* We know that the write has been flushed to disk now

1131         and during recovery we will find it in the doublewrite buffer

1132         blocks. Next do the write to the intended position. */

1133         buf_dblwr_write_block_to_datafile(bpage, sync);      //该backtrace的sync为TRUE

buf_flush_page在多处被调用到,其增加了一个sync参数,用于表示该page flush操作需要同步还是异步进行。而在5.6.11中会在调用buf_flush_page后调用buf_flush_sync_datafiles()来sync所有的数据文件。
另外,有一种情况,在做SINGLE PAGE FLUSH时,采用异步的方式,backtrace如下:

row_import_for_mysql->buf_LRU_remove_pages->buf_flush_dirty_pages->buf_flush_or_remove_pages->buf_flush_page
这其实就是5.6的新特性ibd import功能的backtrace,后面单独开篇介绍

* 将single page flush的dblwr slot处理转移到IO线程

函数:buf_dblwr_update
当IO操作完成写一个page后,这个函数会被调用到,在5.6.12中会做两件事儿:
对于batch flush操作(BUF_FLUSH_LIST 或者BUF_FLUSH_LRU),当预留给batch flush的slot都全部完成刷新后(buf_dblwr->b_reserved = 0),会去sync数据文件(fil_flush_file_spaces(FIL_TABLESPACE)),将batch_running设为false,并发送完成信号
对于single page flush操作,找到当前page的slot,然后将其设置为未使用(in_use[i] = false),随后发送condition 信号(buf_dblwr->s_event)
这里采用顺序遍历,来寻找当前page的slot,是否存在效率问题?
而在5.6.11版本中,只考虑了batch flush操作。

* 移除对dblwr buffer中的sleep,改用condition wait

 写double write buffer时,如果已经在刷dblwr,以前是sleep 10ms,现在改成condition wait了,这里包括batch flush 和single page flush,这两者都增加了条件变量
当脏页刷新非常频繁时,会看到很明显的性能提升
*其他
另外一个没提到的修改是函数buf_flush_LRU_tail
在5.6.11的版本中,并没有对buf_flush_LRU的返回值进行处理。而在5.6.12中,增加了如下逻辑:
2092                 for (ulint j = 0;
2093                      j < scan_depth;
2094                      j += PAGE_CLEANER_LRU_BATCH_CHUNK_SIZE) {
2095 
2096                         ulint   n_flushed = 0;
2097 
2098                         /* Currently page_cleaner is the only thread
2099                         that can trigger an LRU flush. It is possible
2100                         that a batch triggered during last iteration is
2101                         still running, */
2102                         if (buf_flush_LRU(buf_pool,
2103                                           PAGE_CLEANER_LRU_BATCH_CHUNK_SIZE,
2104                                           &n_flushed)) {
2105 
2106                                 /* Allowed only one batch per
2107                                 buffer pool instance. */
2108                                 buf_flush_wait_batch_end(
2109                                         buf_pool, BUF_FLUSH_LRU);
2110                         }
2111 
2112                         if (n_flushed) {
2113                                 total_flushed += n_flushed;
2114                         } else {
2115                                 /* Nothing to flush */
2116                                 break;
2117                         }
2118                 }
3.优化batch flush的效率,之前的时间复杂度为O(N*N)
每个buffer pool实例增加了一个新的变量:
        const buf_page_t*       flush_list_hp;/*!< “hazard pointer”

used during scan of flush_list

while doing flush list batch.

Protected by flush_list_mutex */

根据注释,其在批量刷新时使用,用 flush_list_mutex  来保护
buf_flush_set_hp : 设置 flush_list_hp指针,指向参数传递的page
buf_flush_update_hp:当flush_list上的block移除或者移动时,需要检查buf_flush_set_hp指针是否被其他正在扫描flush list的线程设置,如果flush_list_hp指向我们下一个将要扫描的page,则将其设置为NULL,表示需要重新扫描
有两个地方会调用到这个函数:
* 从flush list上移除一个page的时候(buf_flush_remove)
* 为flush list上的一个page重分配控制块,buf_flush_relocate_on_flush_list
buf_do_flush_list_batch:
在该函数的修改是核心部分,主要消除了在bug#69170中描述的o(n*n)的时间复杂度。所有作用于flush list的线程,都需要先检查flush_list_hp指针,
这里的方法很简单,从flush list的尾部开始扫描, 每次获取一个page后,将bp->flush_list_hp的指针指向该page的前一个, 然后释放bp->flush_list_mutex
然后执行该page的刷新
flushed = buf_flush_page_and_try_neighbors(

bpage, BUF_FLUSH_LIST, min_n, &count);

再次持有flush_list_mutex锁,查看bp->flush_list_hp是否发生变化,如果发生变化了,则表明该指针被其他线程设置了,也就是说,有其他线程对flush list做了操作,因此需要从flush list尾部重新开始扫描
在5.6.11的版本中,总是无条件的从尾部开始重新扫描。

 


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
3月前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
160 3
|
7月前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
3月前
|
存储 关系型数据库 MySQL
介绍MySQL的InnoDB引擎特性
总结而言 , Inno DB 引搞 是 MySQL 中 高 性 能 , 高 可靠 的 存 储选项 , 宽泛 应用于要求强 复杂交易处理场景 。
149 15
|
8月前
|
存储 网络协议 关系型数据库
MySQL8.4创建keyring给InnoDB表进行静态数据加密
MySQL8.4创建keyring给InnoDB表进行静态数据加密
272 1
|
3月前
|
缓存 监控 关系型数据库
使用MYSQL Report分析数据库性能(上)
最终建议:当前系统是完美的读密集型负载模型,优化重点应放在减少行读取量和提高数据定位效率。通过索引优化、分区策略和内存缓存,预期可降低30%的CPU负载,同时保持100%的缓冲池命中率。建议每百万次查询后刷新统计信息以持续优化
237 6
|
3月前
|
缓存 监控 关系型数据库
使用MYSQL Report分析数据库性能(中)
使用MYSQL Report分析数据库性能
162 1
|
4月前
|
缓存 关系型数据库 MySQL
MySQL数据库性能调优:实用技术与策略
通过秉持以上的策略实施具体的优化措施,可以确保MySQL数据库的高效稳定运行。务必结合具体情况,动态调整优化策略,才能充分发挥数据库的性能潜力。
204 0
|
6月前
|
关系型数据库 MySQL 分布式数据库
Super MySQL|揭秘PolarDB全异步执行架构,高并发场景性能利器
阿里云瑶池旗下的云原生数据库PolarDB MySQL版设计了基于协程的全异步执行架构,实现鉴权、事务提交、锁等待等核心逻辑的异步化执行,这是业界首个真正意义上实现全异步执行架构的MySQL数据库产品,显著提升了PolarDB MySQL的高并发处理能力,其中通用写入性能提升超过70%,长尾延迟降低60%以上。
|
7月前
|
存储 SQL 关系型数据库
京东面试:mysql深度分页 严重影响性能?根本原因是什么?如何优化?
京东面试:mysql深度分页 严重影响性能?根本原因是什么?如何优化?
京东面试:mysql深度分页 严重影响性能?根本原因是什么?如何优化?
|
8月前
|
SQL 缓存 关系型数据库
使用温InnoDB缓冲池启动MySQL测试
使用温InnoDB缓冲池启动MySQL测试
150 0

推荐镜像

更多