美文网首页
关于磁盘IO的那些事儿

关于磁盘IO的那些事儿

作者: 沉思故事 | 来源:发表于2018-07-01 08:47 被阅读93次

    在本文中我将引用五篇有关disk io 的好文章来与读者一起学习探讨关于磁盘IO的事。我大概会提取一些关键点,如果你不太理解或想要深入,不要错过那些链接哦。当然任何文章都不要盲信,不肯定时就要多方论证。

    on disk io, part 1

    network io 被关注得多,disk io关注得少,部分原因在于network io 有许多特性和不同的实现,而disk(或file system) io只是很少一部分工具子集

    sector是块设备的最小传输单元;文件系统最小可寻址单元是block,block是相邻的sector的组合;IO是虚拟内存来操作,它会缓存block在buffer中,虚拟内存操作的是page,它会被映射到block (https://superuser.com/a/350499 这个答案解释得不错,文件系统的block理解为logical block)

    读时先查看page cache,如果没有则page in;写时先写到page cache,等合适时再flush

    关于DIRECT IO

    有些时候不想通过page cache写disk,可能出于效率原因,可以通过指定O_DIRECT来绕过page cache直接写块设备。设计合理的话可以提供更加细粒度的IO控制,应用端常需有自己的cache layer

    我详细查看了作者引用的关于Linus在linux kernel新闻组的回复,他说:

    • O_DIRECT特别适用于诸如database的应用,若能支持异步则会更好
    • Linus认为O_DIRECT接口设计很糟糕,提供了一种比它更好的two-phases way(顺便吐槽了一下database设计者没有好的设计品味)
    • 使用AIO是非常好的,但它只是为了掩盖糟糕的设计;倘若接口设计良好不用AIO也是可以的

    像mysql, postgresql也是使用了O_DIRECT的,比如pg用于写WAL;同时开启O_DIRECT和page cache当然是不推荐的;

    如果要进行direct IO,则需保证io starting address 和io size必须与block大小保持对齐; 无论是否使用direct IO,保持读写时的地址和大小对齐是个好习惯,减少kernel的额外工作

    底下有评论说:

    对于压缩和序列化操作,用direct io 和user caching要比OS本身的page cache要好
    buffer cache和page cache不是一回事 ? 这还有待资料验证

    关于nonblock

    O_NONBLOCK选项不适用于regular filesNon-blocking I/O with regular files,因为文件系统操作本身就是非阻塞的,所以像select,poll也不适合监控普通文件状态

    其它参考

    Ensuring data reaches disk

    fflush是针对于FILE*,将数据从用户层推到OS层,fsync是针对于fd的,将数据推到持久设备上
    /dev/raw设备的访问默认是O_DIRECT
    O_SYNC/O_DSYNC还会同步写文件的metadata ?
    对于新创建的文件,fsync不仅仅是针对于文件还针对于存放这个文件的目录;
    为避免覆盖旧数据系统故障导致数据丢失,可以先写temp file,fsync后,再rename,再fsync directory
    write/fflush等调用可能并不报IO error,因为数据还在page cache,但fsync,msync,close时则会出现io error,此时对这些调用的返回值是有必要的;
    一些文件系统支持在mount指定是否要flush的选项;
    
    **评论值得一看**
    

    part 2, more flavours of io

    mmap

    文件内容不是立即调入内存的,采用的是延迟加载的形式,因此第一次访问时会有page fault. 使用MAP_POPULATE可强制read ahead
    内存映射是通过page cache来实现;
    对mmapped 文件的随机访问就和普通指针一样,只不过没有lseek操作
    mmap的缺陷:

    • 内核要维护相应的数据结构
    • mapped files大小有限制

    此答案建议何时用mmap何时用read

    如果要随机访问,有保留很长时间,用mmap,如果是顺序读取,读完了丢弃使用read;最后谁用起来简单用谁

    page cache优化

    fadvise可提供kernel合适的建议,以提高性能。比如如果要顺序读取文件,可以在真正读取之前用它告诉kernel 提前预读;
    mlock可以锁住page,但要慎用以防耗尽内存

    aio

    glibc并未shipped,需单独安装libaio才能使用;
    与O_DIRECT配合使用,不支持buffered io
    与posix aio不是一回事,后者是user space aio;

    linux aio example

    vectored io

    可以读small chunks, 减少了系统调用数,且保持了读写原子性;
    很少通用型数据库使用vectored io,毕竟它们要处理很多文件,关注延时,cache block-wise,而分析型或列式数据库比较适合使用vectored io,可以并行读入大量数据

    目前的方式都有其内在的模式,比如使用O_DIRECT你可能要创建buffer cache,使用page cache需要用到fadvise,使用aio需要用到future-like的接口(指的就是epoll 的回调函数在事件ready后被调用)

    On Disk IO, Part 3: LSM Trees
    immutable的好处在于不用为数据保留额外空间以防更新成更大的数据;减少了竞争与锁;
    immutable/mutable都需要做housekeeping,immutable需要跟踪生成的文件定期做merge,mutable需要减少碎片化

    各种DB在LSM的实现上有相似点,都有sorted string table;
    sstable就是一个持久化的、有序的、不可变的数据结构,分为data区和索引区;
    写都先到内存中的数据结构如skiplist/b-tree,到了一定大小或一定时间就flush到磁盘上成为sstable;
    前面的值被后面的update所删除或者写入了新值,称old value is shadowed by new value;

    LSM这种设计,在高写负载情况下是可能有高延时的;CPU和磁盘IO可能被Flush,compaction所占满;
    有写放大现象;

    part 4, b-tree

    关于b-tree笔者已经比较熟悉了,但这篇文章还是贴出来,人家都讲得挺好,就不多说了。推荐这篇论文

    相关文章

      网友评论

          本文标题:关于磁盘IO的那些事儿

          本文链接:https://www.haomeiwen.com/subject/dvvedftx.html