随机读写之DirectIO

本文探讨了Linux DirectIO技术,一种针对性能需求高的场景,如数据库操作,通过绕过PageCache直接与磁盘交互的方法。讲解了顺序读写与随机读写的区别,以及PageCache的工作原理和内存管理。特别提到了DirectIO的使用限制和Java支持情况,以及如何通过调整系统参数应对内存紧张和毛刺现象。
摘要由CSDN通过智能技术生成

随机读写之DirectIO

注:只有 Linux 系统才支持 Direct IO,还被 Linus 喷过,据说在 Jdk10 发布之后将会得到原生支持

buffered io
普通文件操作,对性能、吞吐量没有特殊要求,由kernel通过page cache统一管理缓存,page cache的创建和回收由kernel控制。
默认是异步写,如果使用sync,则是同步写,保证该文件所有的脏页落盘后才返回(对于db transaction很重要,通过sync保证redo log落盘,从而保证一致性)

mmap 对文件操作的吞吐量、性能有一定要求,且对内存使用不敏感,不要求实时落盘的情况下使用。mmap对比buffered io,可以减少一次从page cache -> user space的内存拷贝,大文件场景下能大幅度提升性能。同时mmap将把文件操作转换为内存操作,避免lseek。通过msync回写硬盘(此处只说IO相关的应用,抛开进程内存共享等应用)。

direct io
性能要求较高、内存使用率也要求较高的情况下使用。
适合DB场景,DB会将数据缓存在自己的cache中,换入、换出算法由DB控制,因为DB比kernel更了解哪些数据应该换入换出,比如innodb的索引,要求常驻内存,对于redo log不需要重读读写,更不要page cache,直接写入磁盘就好。
在这里插入图片描述

顺序读写 & 随机读写
定义不难理解,其实就是要有序,不要随机切换位置,比如:
thread1:write position[0~4096)
thread2:write position[4096~8194)
而非
thread1:write position[0~4096)
thread3:write position[8194~12288)
thread2:write position[4096~8194)

思考:顺序写为什么比随机写要快?
这正是page cache在起作用!
disk cache分为两种:buffer cache以块为单位,缓存裸分区中的内容,(如super block、inode)。page cache是以页为单位缓存分区中文件的内容(通常为4K) ,它是位于 application buffer(用户内存)和 disk file(磁盘)之间的一层缓存。linux2.4中,两者是并存的,但会造成mmap情况下,同一份数据会在两个cache空间内存在,造成空间浪费,在linux2.6中,两者合并,buffer cache也使用page cache的数据结构,只是在free统计内存时,会把page cache中缓存裸分区的部分统计为buffer cache。
当用户发起一个 fileChannel.read(4kb) 时:
在这里插入图片描述

1.操作系统从磁盘加载了磁盘块(block) 16kb进入 PageCache,这被称为预读(为了减少实际磁盘IO)
2.应用程序(application buffer)操作(read)其实是从 PageCache 拷贝 4kb 进入用户内存
说明:
((关于扇区、磁盘块、Page(PageCache)在N年前谈过要有一定的了解!
常见的block大小为512Bytes,1KB,4KB,查看本机 blockSize 大小的方式,通常为 4kb
为何加载block为16kb,该值也很讲究blockSize*4,难道也发生了4次IO?非也,这又涉及到IO合并(readahead算法)!另外该值并非固定值值,内核的预读算法则会以它认为更合适的大小进行预读 I/O,比如16-128KB,当然可以手动进行调整。对这块敢兴趣的同学可以看文末的引用资料))

当用户继续访问接下来的[4kb,16kb]的磁盘内容时,便是直接从 PageCache 去访问了!当我看到下图也有些不适应,确实我们离开发操作系统的老外(老码农)还远着呢,只能大致领略的它味道,这里致敬那些从事计算机基础技术的前辈,更期待华为的操作系统鸿蒙出世。
在这里插入图片描述
在这里插入图片描述

内存吃紧时PageCache 会受影响吗?
肯定是会影响的,PageCache 是动态调整的,可以通过 linux 的系统参数进行调整,默认是占据总内存的 20%。可以通过free命令进行监控(cache:page cache和slab所占用的内存之和,buff/cache:buffers + cache),它一个内核配置接口 /proc/sys/vm/drop_caches 可以允许用户手动清理cache来达到释放内存的作用,这个文件有三个值:1、2、3
Writing to this will cause the kernel to drop clean caches, dentries and inodes from memory, causing that memory to become free.

  • To free pagecache:
    • echo 1 > /proc/sys/vm/drop_caches
  • To free dentries and inodes:
    • echo 2 > /proc/sys/vm/drop_caches
  • To free pagecache, dentries and inodes:
    • echo 3 > /proc/sys/vm/drop_caches
  • As this is a non-destructive operation, and dirty objects are notfreeable, the user should run “sync” first in order to make sure allcached objects are freed.
  • This tunable was added in 2.6.16.

毛刺现象
现代操作系统会使用尽可能多的空闲内存来充当 PageCache,当操作系统回收 PageCache 内存的速度低于应用写缓存的速度时,会影响磁盘写入的速率,直接表现为写入 RT 增大,这被称之为“毛刺现象”

Direct IO
去掉PageCache的确可以实现高效的随机读,的确也有存在的价值!采用 Direct IO + 自定义内存管理机制会使得产品更加的可控,高性能。
在这里插入图片描述

如何使用呢?
使用 Direct IO 最终需要调用到 c 语言的 pwrite 接口,并设置 O_DIRECT flag,使用 O_DIRECT 存在不少限制:
~操作系统限制:Linux 操作系统在 2.4.10 及以后的版本中支持 O_DIRECT flag,老版本会忽略该 Flag;Mac OS 也有类似于 O_DIRECT 的机制
~用于传递数据的缓冲区,其内存边界必须对齐为 blockSize 的整数倍
~用于传递数据的缓冲区,其传递数据的大小必须是 blockSize 的整数倍
~数据传输的开始点,即文件和设备的偏移量,必须是 blockSize 的整数倍

目前Java 目前原生并不支持,但github已经有封装好了 Java 的 JNA 库(smacke/jaydio),实现了 Java 的 Direct IO。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

京天不下雨

thanks

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值