如题,mysql 、redis 之类的数据库似乎都会实现自己的文件管理系统,根据我在网上查到的消息,这类直接 IO 是不需要经过内核的。
Linux 内核在处理文件时,比如三个进程同时向指向同一个文件的三个 fd 写入内容,默认情况下因为都会使用系统调用写入,所以似乎是 linux 会自动处理好并发可能产生的乱序写入问题(乱序写入指多线程互相覆盖导致实际内容比期望内容少,且编码错乱,似乎是不会发生这种问题)
学习 IO 的时候产生一个问题就是直接 IO 是否意味着用户需要自己协调进程间通信以保证同一时间没有两个人在写入?如若不然可靠性是怎么保证的呢。
谢谢大家
1
codehz 2021-04-13 23:10:46 +08:00 via Android
谁跟你说 direct io 不走内核???
只是没内核缓冲而已,内核还是没绕过,自己管理缓冲以实现更高的效率。。。也就是同步的层次低了点,不能保证单次写入的原子性而已(主要是为了 aio ) |
2
LeeReamond OP @codehz 感谢回复,所以意思是所谓的直接 io 是指,他只是在把缓冲区输出到硬盘的时候需要系统调用,这个意义上的系统调用减少,然后提高了效率?
|
3
codehz 2021-04-14 00:29:03 +08:00 via Android 1
@LeeReamond 没有减少系统调用,相反,由于几乎只能配合 native aio 使用(不然比 buffered io 还慢),事实上还略微增加了调用的总个数。。。
提高效率的原因就是省去的内核缓冲区,可以直接从用户缓冲区写到块设备上,于是就会有潜在的竞争状态(如果多个线程同时操作,或者一个线程里提交重叠的异步 io 请求) (然后,由于直接写入磁盘,所以也不需要额外的文件系统同步了,数据库就需要这个) |
4
LeeReamond OP @codehz 还是不是很理解,主要是两点,其一是关于“于是就会有潜在的竞争状态”这部分,所以理论上直接 IO 确实需要自己处理竞争,统一进程内可以用线程争用的解决方案,跨进程的话需要用跨进程方案才能避免出错?这也是最开始疑惑的地方。
另外关于提高效率的部分,它用用户缓冲区代替内核缓冲区本身不是一种减少系统调用的行为么。而你说的“直接从用户缓冲区写到块设备上”,这里是指物理写入硬盘的行为吧,还是说块设备仍然是一种 linux 的虚拟缓冲,实际写入行为在更后面 |
5
codehz 2021-04-14 12:42:03 +08:00 via Android 1
@LeeReamond 直接写入的意思是,(同步的情况下) read/write 系统调用等待数据落盘之后再返回,系统调用还是那个调用,怎么就减少了系统调用呢(当然你不能说之前都一字节发一个,然后 direct io 这边整理起来一起发这种不公平的对比,这里假设都是按相同的大小发调用,那么同步的情况下,数量完全没差别),但是由于硬件只能按块为单位读写,一旦没有按块对齐的方式发出 direct io 的读写调用,势必会浪费带宽(比如小于一个块)或者产生多次读写(跨越了块边界)以增加延迟,通常来说反而更慢,最差可以相差几个数量级,buffered io 就不一样了,有缓存就可以把一堆读写收集起来,在不对齐的情况下平摊了访问的延迟,效率更高。
上面说的有点问题,竞争条件应该只在读写之间冲突,单纯的写或者读,是不会造成冲突的,驱动同时保证了(逻辑上)只有一个写入的操作,但是由于没内核缓冲和额外的保护机制,读取的时候可能出现交替的新旧内容。 |