IO/内存/文件系统

linux io协议栈

IO/内存/文件系统

裸设备读写

数据库公认最快的IO方式是读写裸设备,Oracle数据库一般将日志和数据全部存放到裸设备上.

什么是裸设备

在Unix/Linux, 文件分为两个大类:字符设备文件和块设备文件.

裸设备是一种没有经过格式化,不被Unix通过文件系统来读取的特殊块设备文件, 也叫裸分区(原始分区), 通过字符设备驱动读写裸设备

裸设备的优点

裸设备不通过Unix/Linux的文件系统管理, 节省了文件管理的开销; 文件系统作为物理磁盘的抽象, 并且维护这个抽象的一整套逻辑, 是需要一定开销的;

对裸设备的操作不通过系统的缓冲区, 数据在ORACLE的数据缓冲区(BUFFER CACHE)和磁盘间直接传递, 能在一定程度上提高I/O性能, 适合大量IO的场景使用

缺点

  • 容量管理不便, 需要提前规划容量
  • 裸设备的创建和扩展等操作都需要root权限

写日志

写日志是数据库常用的保证可靠性的重要手段之一, 其原因是文件系统本身不可靠, 所以事务需要通过日志来保证一致性. 可以参考崩溃一致性, 在多种情况下, 可认为已经完成文件写入的情况, 发生异常并恢复后会发现并没有写成功.

日志式与非日志式文件系统

日志文件系统会跟踪记录文件变化, 理论上讲同一大小的文件, 日志文件系统占用的空间会稍大一些, 但文件日志提供了快速恢复等功能.

对于非日志型文件系统, 当进行一个写操作时,操作系统首先修改文件系统的元数据(metadata),然后再写入实际数据。

如果元数据正在被修改时, 发生系统崩溃或机器掉电, 文件系统就有可能被损坏. 日志型文件系统比非日志文件系统会多出一个专门写日志的日志区, 可根据需要选择先写日志或先写数据.

多数日志型文件系统支持三种日志方式,分别是回写、顺序、全日志, 默认是顺序模式, 即先写数据后写日志.
Linux的ext2/ext3/ext4均为日志型文件系统. Windows的NTFS也是日志型文件系统.

日志算法
WAL: Write-Ahead Logging, 预写日志系统, HBase和MySQL都使用WAL, 具体流程为

  1. 修改记录前,一定要先写日志;
  2. 事务提交过程中,一定要保证日志先落盘,才能算事务提交完成。

通过WAL方式,在保证事务特性的情况下,可以提高数据库的性能。

缓冲IO/非缓冲IO/直接IO

缓冲/非缓冲IO

Linix对IO文件的操作分为不带缓存的IO操作(文件IO)和带缓冲的IO(标准IO).
标准IO符合ANSI C的标准, 不依赖系统内核, 可移植性强, 能减少对read和write的系统调用次数, 读写文件时会在用户层建立一个缓冲区.

不带缓存的IO, 并不是直接对磁盘操作, 只是用户层没有缓存, 在内核仍然是缓存的(系统调用).操作系统会将IO数据缓存在文件系统的页缓存(page cache)中.

两者的区别在于, 不带缓存的IO每次写入时都会写入磁盘, 而标准IO是有缓冲区的, 缓冲区满或者程序flush/close时, 才会写入磁盘; 最终都会调用无缓冲的C标准I/O库函数, 包括open 、read 、write 、close 等系统函数

标准IO调用malloc来分配缓存, 有三种类型:

  1. 全缓存: 当填满标准I/O缓存后才执行I/O操作. 磁盘上的文件通常是全缓存的
  2. 行缓存: 当输入输出遇到新行符或缓存满时, 才由标准I/O库执行实际I/O, 常见的Stdin/Stdout通常是行缓存
  3. 无缓存: 相当于read/write调用. stderr通常是无缓存的,因为必须尽快输出

Stdin/Stdout默认是全缓冲,但在终端中是行缓冲。linux中行缓冲的大小是1k,全缓冲的大小是4k. 由于linux的lazy机制, 只有当实际进行输入/输出时才会分配缓冲区.

缓存I/O,在一定程度上分离了内核和用户空间, 保护了系统的运行安全; 可以减少读盘的次数, 从而提高性能.不过另一方面, DMA将数据从磁盘读到页缓存或者将数据从页缓存直接写回到磁盘上,而不能直接在应用程序地址空间和磁盘之间进行数据传输,多次拷贝时会有较大的cpu及内存开销.

数据流向:

  1. 无缓存IO: 数据-> 内核缓存区-> 磁盘
  2. 标准IO: 数据-> 流缓存区-> 内核缓存区-> 磁盘

CIO/DIO
CIO/DIO技术一般用于数据库中, 如裸设备读写.

DIO即direct IO. DIO直接与硬盘交互, 直接将磁盘数据读到用户空间的缓冲区或用户空间的内存直接写入磁盘,不使用内核的缓存而使用用户自己的缓存.

IO/内存/文件系统

CIO即Concurrent IO, 当某个文件被多个进程同时访问时, 就出现了Inode竞争的问题, 读操作使用的共享锁, 多个读操作可以并发进行, 而写操作使用排他锁. 当锁被写进程占用时, 其他所有操作均阻塞, 此时整个应用的性能将会大大降低。

当文件系统支持CIO并开启CIO时, CIO默认会开启文件系统的DIO,进行数据存储的时候不会经过数据buffer, 而且会串行执行. 因此在文件系统层面无需考虑数据一致性.
CIO的实现依赖于底层的driver

待续

参考

  1. Use concurrent I/O to improve DB2 database performance
  2. linux io协议栈框图

相关推荐