当前位置: 首页 > 科技观察

MySQL的零拷贝技术

时间:2023-03-13 07:30:50 科技观察

原文:https://spongecaptain.cool/post/mysql/zerocopyofmysql1。首先,你需要了解Buffer和cache的区别:Bbuffer和Cache很相似,因为它们都是用来存储数据的,都是用来Layer读取字节数据的。很多时候他们的概念是一样的:首先,在翻译上,Buffer应该翻译成“缓冲”,Cache应该翻译成“缓存”。这两者根本不是一回事。在硬件层面,Buffer应该是内存,Cache应该是与CPU集成的高速缓存。Buffer为了让不同速度的设备能够同步,创建一个缓冲区,写入Buffer的数据用来取出来写入其他设备。缓存是为了提高读取速度,将经常或立即需要的数据预先读取到缓存中,写入缓存的数据供其他设备从中读取。从软件层面来说,Buffer是块设备的缓冲区,Cache是??文件系统的缓存。以Linux为例,Buffer(BufferCache)以块的形式缓冲块设备的运行,并定时或手动同步到硬盘。用于缓冲写入操作,然后一次性将很多变化写入硬盘,避免频繁写入硬盘,提高写入效率。缓存(PageCache)将文件系统的文件以页面的形式缓存起来,读取给需要使用的程序。是为读取操作提供缓冲,避免频繁读取硬盘,提高读取效率。总而言之,Buffer里的东西是给写到别处的,Cache里的东西是给别处读的。Buffer和Cache的目的不一定:Buffer的主要目的是在不同的应用程序、线程、进程之间共享字节数据。例如,为了让不同速度的设备同步数据,会使用共享的Buffer;目的是提高字节数据的读写速度,例如操作系统提供了基于时间局部性和地址局部性的页缓存机制;当然,在很多情况下,Buffer和Cache具有相同的语义,所以我们可以认为buffer不仅用于提高读写速度,还用于数据共享和同步。深入理解零拷贝:深入理解零拷贝技术二、MySQL的缓冲区设计MySQL的缓冲区设计如下图所示:图1.MySQL的缓冲区设计如上图所示。配套技术。其中有:应用层:RedoLogBuffer:缓存写操作,用于实现MySQLInnoDB的事务性;InnoDBBufferPool:用于缓存MySQL表数据。读内存代替磁盘,通过减少磁盘读操作提高读操作性能;写内存代替磁盘,通过减少磁盘写操作来提高写操作性能;操作系统的VFS(Virtualfilesystem,虚拟文件??系统)层:PageCache:操作系统通过缓存和预读机制对文件系统中的块进行基于页的缓存管理;DirectBuffer:当使用DirectI/O提供的相关API时,操作系统不再提供基于PageCache机制的缓存,而是直接使用DirectBuffer;磁盘的DiskBuffer:磁盘也可以提供磁盘缓存,通常在MySQL中diskcache是??关闭的,我们只需要了解DiskBuffer的概念即可。3.直写/回写和直接I/O;WriteThrough和WriteBack是指将内存空间作为缓存的应用在处理写操作时是否直接放在磁盘上:WriteThrough:写操作“穿越”缓存区,直接Writeback,这种策略可以保证数据不会因为宕机丢失内存缓冲区中的数据;WriteBack:一次写操作只更新内存缓冲区中的数据,数据通常每隔一定时间写入一次磁盘;MySQL提供了一些参数来控制PageCache数据刷新的具体行为,例如:(1)innodb_flush_log_at_trx_commitinnodb_flush_log_at_trx_commit参数用于控制基于PageCache[2]的RedoLogBuffer的数据刷新机制。该参数用于控制以下两个特性之间的平衡:严格的事务管理机制;执行事务提交提交操作时的高性能;innodb_flush_log_at_trx_commit有三个可选的配置值:1(默认值):每次事务提交时都要将日志刷到磁盘,提供了最可靠的事务保证;0:日志每1秒刷盘一次,表示缓存中还没有来得及刷盘的数据会在宕机时丢失;2:日志在事务提交后刷新到磁盘,间隔为1秒,这意味着缓存中没有来得及刷新到磁盘的数据将在停机期间丢失;注意:配置0和2不保证每秒100%刷新到磁盘,因为DDL修改和InnoDB活动可能导致日志刷新更频繁。另一方面,由于事务调度问题,刷新频率甚至会降低。刷新频率默认为1s,由参数innodb_flush_log_at_timeout配置。(2)innodb_flush_methodinnodb_flush_method参数同时控制redologbuffer和innodbbufferpoolbufferflush策略,其中:logfiles:redologbuffer是日志文件在内存中的缓存区,logfiles就是RedoLog文件在磁盘上;数据文件:innodb缓冲池是数据文件在内存中的缓存区,数据文件是磁盘上的数据文件(B+树);innodb_flush_method参数[3]目前有6个可选配置值:fdatasync;O_DSYNCO_DIRECTO_DIRECT_NO_FSYNClittlesyncnosync这里只讨论类Unix操作系统,不讨论Windows系统。其中littlesync和nosync仅用于内部性能测试,不推荐使用。fdatasync,取值为0,这是默认的配置值。日志文件和数据文件都通过fsync同步;O_DSYNC,即值为1。日志文件使用O_SYNC打开刷新日志文件,数据文件使用fsync刷新数据;O_DIRECT,即值为4。使用DirectI/O打开数据文件,每次写操作执行fsync系统调用;O_DIRECT_NO_FSYNC,值为5。使用DirectI/O打开数据文件,但每次写操作不调用磁盘的fsync系统调用;补充说明:用O_SYNC打开文件意味着文件的每一次写操作都直接导致数据本身和Metadata刷到磁盘。为什么O_DIRECT和O_DIRECT_NO_FSYNC配置之间存在差异?首先,我们需要明白更新操作分为两个具体的子步骤:①文件数据更新到磁盘②文件元数据更新到磁盘。在某些操作系统中,除非主动调用fsync,否则O_DIRECT将导致文件元数据不会被放置在磁盘上。为此,MySQL提供了O_DIRECT和O_DIRECT_NO_FSYNC[5]两种配置。如果您确定在您的操作系统上,即使您不进行fsync调用,也可以确保文件元数据被刷新,那么请使用O_DIRECT_NO_FSYNC配置,这对MySQL性能略有帮助。否则使用O_DIRECT,否则文件元数据丢失可能导致MySQL运行不正常。4.MySQL日志刷新策略MySQL日志刷新策略通过sync_binlog参数配置,有3个可选配置:sync_binlog=0:MySQL应用完全不负责同步日志到磁盘,刷新日志数据在缓存到磁盘时自行决定交给操作系统来完成;sync_binlog=1:MySQL应用在事务提交前将缓存区的日志刷到磁盘;sync_binlog=N:当N不为0或1时,MySQL会在提交前收集N条日志,将缓存区的日志同步到磁盘。其实这个参数也是用来控制日志是通过WriteThrough还是WriteBack策略刷到磁盘的。注意:使用PageCache机制的数据刷新机制,即使是基于同步策略,即每次写操作都需要将数据直接放到磁盘上,但是在数据放到磁盘之前,数据必须先写入PageCache中,然后将PageCache中的具体Page刷入磁盘。5、MySQL典型配置innodb_flush_log_at_trx_commit参数配置为1:RedoLog使用PageCache,每次写操作的log在事务提交前通过fsync刷到磁盘;innodb_flush_method参数配置为O_DIRECT:InnoDBBufferPool使用DirectI/O,每次写操作引起的文件数据(包括文件元数据)通过fsync系统调用刷新到磁盘;写入重做日志涉及的步骤是:将日志写入重做日志缓冲区;日志被写入重做日志缓冲区;日志写入页面缓存;通过系统调用fsync将PageCache中的脏页刷新到磁盘;日志提交;修改一行表记录涉及的步骤是:将更新后的数据写入InnoDBBufferPool;定时执行如下逻辑(异步执行):InnoDBBufferPool脏数据通过文件的write方法进行刷新;文件的write方式直接导致数据写入磁盘;定期执行文件的fysnc调用,确保文件元数据写入磁盘;REFERENCE[1]BufferandCache[2]MySQL::MySQL8.0ReferenceManual::15.14InnoDB启动选项和系统变量[3]MySQL8.0innodb_flush_method[4]MySQL::MySQL8.0ReferenceManual::17.1.6.4BinaryLoggingOptionsandVariables[5]为什么MYSQL选项为O_DIRECT时仍然使用fsync()刷新数据?