转载请附本文链接:https://blog.csdn.net/maxlovezyy/article/details/104038335
常识(TODO:加SSD)
- HDD的是机械盘,当跨磁道操作的时候需要机械式地寻道,平均延时很大,一般认为在10ms左右。而对于旋转延时,一般不需要太在意,因为转速都很大,相比寻道延时带来的延时比较小。
- Disk以sector为IO的基本单元。这意味着即使写某个sector的一个字节,也是写一个sector,sector大小一般是512B。而对于文件系统来说,目前ext4默认是4K为一个IO单元。
- Disk有一个默认的最大请求大小(/sys/block//queue/max_sectors_kb),理论上单次IO大小越接近该值,吞吐越大。最直接的理解就是host到device之间的通信开销降低了,也包括磁头调度的优化(窗口越大可优化的空间越大),特别是对于NFS、云盘之类的场景。
- ext4默认的挂载方式对非direct IO数据block的分配是delay的,也就是fsync之前是不会分配block的,目的是尽可能加大待处理blocks窗口大小以优化数据分布。但是带来的问题就是如果积攒的比较多,在分配block时阻塞其他请求的时间就会更长。挂载时可以通过nodelalloc去掉该功能。
- 调度器。linux IO系统有常用的3种调度器,cfq、deadline和noop。noop适合SSD,cfq适合多应用公平调度场景,deadline适合数据库和文件系统(原理一样,可优化的窗口变大了)。
常用优化
- 最主要的优化就是围绕减少HDD寻道带来的开销进行的。尽量顺序写,降低随机IO;尽量buffer一波IO,通过batch的方式处理,包括fsync。由于fsync会sync metadata,而metadata又一般在disk上与data分离,所以基本上必定会增加一次寻道的开销,这么重的开销注定吞吐要下来。可以考虑使用预分配文件的方式利用fdatasync(这一块是有坑等,需要先写一遍文件,fallocate没有用)来优化IO。
- 重新挂载盘,加上nodelalloc参数。目前在离线系统里看中吞吐而非稳定性的情况下可以不考虑。比如偶尔有一个10s左右的抖动是可接受的。
- 按4K对齐写。这方面可以参考之前收藏的小日本的博文,写得不错。
- 为数据库等场景设置deadline IO调度器。