性能优化,是存储工程师们永远的追求,在我们看来,除了调整存储架构、优化IO路径,能对应用做出有针对性的优化,也是非常重要和有意义的事情,这意味着,除了要了解存储本身,还需要对上层应用或中间件有足够的认识。这次,我们就来看看MySQL的IO特点和存储针对MySQL的优化思路。
MySQL架构组件说明
MySQL及其延续的MariaDB是目前市场上最流行的关系型数据库管理系统,在很多应用场景中,MySQL都是用户首选的RDBMS(RelationalDatabaseManagementSystem关系数据库管理系统)。
MySQL大致包括如下几大基础模块组件:
MySQL客户端连接组件(Connectors)
系统管理和控制工具组件(ManagementServiceUtilities)
连接池组件(ConnectionPool)
SQL组件(SQLInterface)
解析器组件(Parser)
查询优化器组件(Optimizer)
缓存组件(CachesBuffers)
存储引擎(PluggableStorageEngines)
文件系统(FileSystem)
image
InnoDB存储引擎
存储引擎在MySQL的体系架构中位于第三层,负责对MySQL中的数据进行存储和提取,是与文件打交道的子系统,它是根据底层提供的文件访问层抽象接口定制的一种文件访问机制,这个机制就叫作MySQL存储引擎。从MySQL5.5开始,默认采用InnoDB作为存储引擎。因此,优化底层存储对MySQL业务的的性能,就要从了解和分析存储引擎如何与底层的存储系统进行交互开始。
下图是官方的InnoDB引擎架构图,InnoDB存储引擎主要分为内存结构和磁盘结构两大部分。
InnoDB磁盘主要包含Tablespaces、InnoDBDataDictionary、DoublewriteBuffer、RedoLog和UndoLogs。RedoLog和Binlog是MySQL日志系统中非常重要的两种机制,本文主要谈一下对RedoLog和Binlog进行了分析及存储优化。
MySQLIO模型和特点
MySQL写数据过程中,有两个重要的日志文件,RedoLog和Binlog。RedoLog记录了对InnoDB存储引擎的事务日志,RedoLog的写IO是固定文件范围内的循环写,IO大小是字节对齐(存在部分offset相等,执行的是覆盖写)。Binlog记录了对MySQL数据库执行更改的所有操作,Binlog的写IO是文件append写,IO不对齐。
MySQL写请求时的存储行为:单线程执行MySQLinsert写数据时,一个insert对应一个write操作;多线程并发执行insert,MySQL会将部分IO合并,然后下发到文件系统(如果是使用远程文件系统,这个IO会被远程文件系统的客户端捕获,例如YRCloudFile的客户端),调用write请求写入到/MySQL/ib_logfile文件中。一次writeIO之后,立即调用fsync。
在开启Binlog的场景下,写完一次RedoLog后会再写一次Binlog,然后对Binlog做一次fsync,以保证数据安全。当日志数据写入一定量之后,MySQL后台另外一个线程会将所有的写入,以每个IO16K的大小进行整理,并以aio方式写入到/MySQL/ibdata表文件中。
MySQL读请求时的存储行为:MySQL读时,会从MySQL的缓存中查找数据,缓存命中,就不会实际下发readIO到底层文件系统中。
YRCloudFile针对MySQL日志IO行为优化
由于RedoLog、Binlog都是一次IO写入伴随着一次fsync,而根据实际测试发现,fsync对于存储的开销比较大。所以,对MySQL性能的优化,我们需要在完全确保这两个日志文件数据安全的前提下调整这两个LogIO行为。
在YRCloudFile数据服务端,RedoLog写文件以direct方式写入,写入之后我们自动做一次fsync。Binlog由于IO不对齐,不可以采用direct方式写,需要先写入系统缓存,然后做一次fsync。这样,其实客户端就不用再对RedoLog和Binlog文件做remote_fsync了,省去了客户端调用fsync的开销影响。下面是一组实测的数据对比:
从实测结果上,我们可以看出,在调整了YRCloudFile后端针对性地写逻辑后后,MySQL单线程写入的性能得到了翻倍的提升。
存储的研发工程师们就是这样,不但要掌握存储的核心技能,还要