MySQL数据库与I/0操作

    1. linux块设备I/O操作的分类

第一类是使用C标准库中的fopen/fread/fwrite系列的函数,我们可以称其为bufferedI/O(标准I/O)。

第二类是使用Linux的系统调用的open/read/write系列的函数,我们可以称其为non-bufferedI/O



DirectI/O:也有人叫RawI/O

可以通过设置系统掉调用的open()函数的O_DIRECT标志来实现DirectI/O,他绕过OSCache,就是操作系统的高速缓存,直接读取Device



non-bufferedI/O

说明:不是说unbufferedI/O读写磁盘时不用缓冲,实际上使用了内核是存在高速缓冲。

目的:提供效率

Application<->Operation System Cache <->File System/Volume Manager<->Device

bufferedI/O

目的:提高效率

bufferedI/O中都是库函数,而unbufferedI/O中为系统调用,使用库函数的效率是高于使用系统调用的。

bufferedI/O就是通过尽可能的少使用系统调用来提高效率的。

Application<->LibraryBuffer<->Operation System Cache<->File System/VolumeManager<->Device



两者关系:

调用与被调用

bufferedI/O库函数(freadfwrite等,用户空间)----call---> unbuffered I/O系统调用(readwrite等,内核空间)------->读写磁盘

bufferedI/O库函数都是调用相关的unbufferedI/O系统调用来实现的,他们并不直接读写磁盘,实际上是用户多实现了一层类似于高速缓存的机制。

它的基本方法是,在用户进程空间维护一块缓冲区,第一次读(库函数)的时候用read(系统调用)多从内核读出一些数据,

下次在要读(库函数)数据的时候,先从该缓冲区读,而不用进行再次read(系统调用).

同样,写的时候,先将数据写入(库函数)一个缓冲区,多次以后,在集中进行一次write(系统调用),写入内核空间.



innodbI/O结构:



1、通过把innodb_flush_method设置为O_DIRECT,为一个纯的buffered I/O系统,或者是bufferedI/O + direct I/O

2、使用innodb_flush_method默认fdatasync,为bufferedI/O + unbuffered I/O

问题:

何时使用 bufferedI/O



1.2 文件I/Omysql的底层关系:

1O_DIRECT不能用在InnoDB日志文件,二进制日志文件,MyISAM相关数据文件上

2、关于innodb_flush_method每个参数在内核的操作细节是什么?

innodb_flush_method参数的值实际上是让innodb引擎在打开文件时让系统调用open()函数得到的参数,具体细节如下:


文件I/O操作的三个操作openwriteflush


Open操作:

open("test.file"O_WRONLY|O_APPDENT|O_SYNC)

系统调用Open会为该进程一个文件描述符fd。这里使用了O_WRONLY|O_APPDENT|O_SYNC打开文件。

类似于 O_SYNC还有O_DSYNCO_RSYNCO_DIRECT,比较如下:

O_DSYNC告诉内核,当向文件写入数据的时候,只有当数据写到了磁盘写入操作才算完成(write才返回成功)。

O_SYNC不仅要求数据已经写到了磁盘,而且对应的数据文件的属性(元数据)也需要更新完成才算write操作成功。

O_RSYNC表示文件读取时,该文件的OScache必须已经全部flush到磁盘了;

O_DIRECT表示读/写操作都会跳过OScache,直接在disk上读/写。因为没有了OScache,所以会O_DIRECT降低文件的顺序读写的效率。



Write操作:

write(fdbuf6)

在使用open打开文件获得文件描述符之后,我们就可以调用write函数来写入数据了,write会根据前面的open参数不同,而表现不同。



flush阶段:

为了保证磁盘上实际文件系统与缓冲区高速缓存中内容的一致性,系统提供了syncfsyncfdatasync三个函数确保文件数据flush到了disk上。所以说flush阶段和openwrite其实不是在一个流程里的。

Sync函数表示将文件在OScache中的数据排入写队列,然后就返回,它并不等待实际写磁盘操作结束,所以sync并不可以靠,但是速度最快。

fsync函数只对由文件描述符filedes指定的单一文件起作用,并且等待写磁盘操作结束,然后返回。fsync可用于数据库这样的应用程序,这种应用程序需要确保将修改过的块立即写到磁盘上,并且还会同步更新文件的属性,速度最慢。

fdatasync函数类似于fsync,但它只影响文件的数据部分,不更新文件的属性信息。

fsyncfdatasync的区别等同于O_SYNCO_DSYNC的区别。


具体影响表现:

innodb_flush_method有三个值,分别是fdatasyncO_DSYNCO_DIRECT,其中fdatasync是默认值。

它们控制了InnoDB刷新日志和数据的模式。

看看这个三个参数是如何影响程序MySQL对日志和数据文件的操作:


Openlog

Flushlog

Opendatafile

Flushdata

Fdatasync


fsync()


fsync()

O_DSYNC

O_SYNC





fsync()

O_DIRECT



fsync()

O_DIRECT

Fsync()



fdatasyncInnoDB使用fsync()函数去更新日志和数据文件。

O_DSYNCInnoDB使用O_SYNC模式打开并更新日志文件,用fsync()函数去更新数据文件。

O_DIRECTInnoDB使用O_DIRECT模式打开数据文件,用fsync()函数去更新日志和数据文件。

我们看到O_DIRECTfdatasync和很类似,但是它会使用O_DIRECT来打开数据文件。

一个可能成立的结论:如果是大量随机写入操作,O_DIRECT会提升效率。但是顺序写入和读取效率都会降低。

fdatasync被认为是安全的,调用fsyncflush数据。使用O_DSYNC是有些风险的,但是实际使用过程中性能提高很多,20%左右。



1.3 IO调度算法

I/O调度程序的功能:

1、合并和排序(包括bio合并到request

2、队列生产和消费,如查找最合适的request,交到分发队头去,让驱动去优先处理

3、增加系统的吞吐量

4、同时减少了系统的响应时间



IO调度器算法的选择,既取决于硬件特征,也取决于应用场景。



Linux有四种IO调度算法:CFQDeadlineAnticipatoryNOOPCFQ是默认的IO调度算法。

完全随机的访问环境下,CFQDeadlineNOOP性能差异很小,但是一旦有大的连续IOCFQ可能会造成小IO的响应延时增加,所以数据库环境建议修改为deadline算法,表现更稳定。

IO调度算法都是基于磁盘设计,所以减少磁头移动是最重要的考虑因素之一,但是使用Flash存储设备之后,不再需要考虑磁头移动的问题,可以使用NOOP算法。NOOP的含义就是NonOperation,意味着不会做任何的IO优化,完全按照请求来FIFO的方式来处理IO


传统的SAS等机械盘:

CFQDEADLINEANTICIPATORY都是不错的选择;

对于专属的数据库服务器,DEADLINE的吞吐量和响应时间都表现良好。

固态硬盘比如flash卡,SSDFusionIO等:

NOOP算法,因为其他三个算法的优化是基于缩短寻道时间的,而固态硬盘没有所谓的寻道时间且IO响应时间非常短。NOOP的含义就是NonOperation,意味着不会做任何的IO优化,完全按照请求来FIFO的方式来处理IO



怎么修改:

查看和修改IO调度器的算法非常简单。假设我们要对sda进行操作,如下所示:
echo
'deadline'>/sys/block/sdb/queue/scheduler
cat
/sys/block/sdb/queue/scheduler

noopanticipatory[deadline]cfq



减少预读:/sys/block/sdb/queue/read_ahead_kb,默认128,调整为16

增大队列:/sys/block/sdb/queue/nr_requests,默认128,调整为512



deadline

1、三种队列

顺序队列,/



FIFO,先进先出队列,/



通用层的分发队列 (驱动层就是从这个队列读取数据的)

2、读请求和写请求是分开来处理的,而且读的请求的响应时间应该比写的要短

3、调度器先处理read,也就是read请求优先。但在处理过程中考虑到了写饥饿。如果此时还有写请求,则写饥饿计数+1,如果写饥饿次数大于了writes_starved,则写饥饿已经“超标”了,因此直接跳到dispath_writes去处理写请求。如果写饥饿没有“超标”,则继续处理读请求。

4、请求的超时时间

这就是deadline的算法核心所在。调度器首先调用deadline_check_fifo来检查队列中队首,也就是最老的一个请求是否超时。如果超时则指定当前处理的请求为该超时的请求。但如果没有超时,但已经扫描了电梯的末尾:!dd->next_rq[data_dir]。此时需要返回到电梯首部。但与传统的电梯算法不同,deadline调度器不是返回到sector最小的request开始继续扫描。而是返回到等待时间最久的那个requst,从那个request开始,沿sector递增方向继续扫描。也就是说,如果超时,或者扫描到电梯尾,都会返回来处理等待最久的request,并从这个request开始继续进行电梯扫描。当然,如果既没有发生超时,也没有扫描到电梯末尾,则沿sector递增方向上的下一个request就是当前要处理的request



deadlineIO调度算法流程图

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值