我正在研究Linux的数据库引擎,我对于通过对内核进行一次系统调用来编写多个块的一致性存在疑问。我用O_DIRECT打开设备。
设备以块为单位写入数据,具体取决于硬件,可能是512,2048或4096.假设我将在一次系统调用中写入2个512字节的块。如果在磁盘写入1个块之后系统完全关闭会发生什么?在正常操作期间,write()系统调用将返回写入的数据的大小,因此当2个值(询问与返回)不匹配时,我可以比较并生成错误,但是在电源关闭时它会变得复杂。它甚至更复杂,因为内核可能不是按照你告诉它的方式向设备发送写请求,所以请求的尾部可以在头部之前写入,然后你关闭电源。
考虑数据库引擎写入事务日志。假设事务大约是4096字节,引擎将需要写入8个512字节的块。突然我们断电了,只写了一半的请求。数据库如何处理这些问题?我想要解决这个问题,首先需要将要写入的块数量写入磁盘上的其他位置。收到正确的返回值后,您可以编写数据。然后,在收到确认后,您必须向磁盘发送另一个写入,更新您想要写入的所有块实际上已成功写入的信息。因此,这将需要3次写入操作,如果内核正在从另一个进程执行磁盘写入,这很可能会导致3次搜索。太低效了。
我正在寻找一种方法来实现对多个块的一致写入,只需对磁盘进行一次写操作。 (一个write()系统调用)这可能吗?
答案 0 :(得分:0)
模拟一些速度黑客,你描述的写两次行为正是数据库所做的。它被称为write-ahead logging,它涉及一个缓冲区,它由操作按顺序写入,偶尔将内存缓冲区刷新到磁盘,并将相应的刷新条目写入日志。然后,当数据库系统开始运行时,它会检查日志中是否有可能未刷新到磁盘的条目,并将这些值刷新到磁盘(因为条目在日志中)。
这实际上比立即写入数据更有效。日志是一个顺序文件,因此向其附加数据不需要搜索,只需要旋转延迟。此外,您不必立即将数据写入实际数据文件,因为您始终可以从日志中恢复它。然后,当没有任何请求进入时,将数据刷新到磁盘并将刷新条目写入日志。这样,DBMS寻求的唯一时间是1)当系统处于安静状态时2)当DMBS耗尽用于保存修改数据的存储器时。只要你的机器中有足够的内存,磁盘就没有太多的搜索,而且这些搜索都是在DBMS不忙的时候发生的。
答案 1 :(得分:-1)
在关闭系统之前,您需要首先关闭数据库引擎!当您关闭引擎时,它应该首先完成所有写入,同步(刷新缓冲区)并使引擎正常停止。您还可以在系统关闭脚本中包含一个命令,以便在关闭系统之前先关闭引擎。