开启异步IO的相关风险

由于IO的请求不是每次等待完成指令后再发送下一个请求,而是存在于队列中,且遵循FIFO。因此如果遇到存储掉电的情况,就可能会出现数据的不一致。虽然这种情况出现的可能性不大,因为存储中有电池,能保证cache中的信息写到存储中。但是在这里还是提一下数据丢失的风险。

由于我们的异步IO的队列中是针对使用裸设备的IO请求,即redo log、datafile和controlfile,这边分3种情况讨论存储掉电时候,数据的丢失情况(注:以下情况考虑的是cache中的IO请求丢失,但是文件未损坏的情况):

(1)当记录A insert到表中,已经commit,记录B insert到表中,未commit,此时checkpoint未发生时。此时的IO队列中有insert A的redo请求,insert B的redo请求,但未有buffer向dbfile写的请求。此时掉电,oracle端的情况是oracle认为redo的IO请求已经写到redo log,os端的情况redo的IO请求还没写到redo log中。重启数据库时候之前的oracle端认为redo和dbfiles的scn不一致,需要介质恢复,但是在启动的时候,读取redo log,由于在os级上尚未写入,redo log和dbfiles的scn一致,因此正常启动,但是丢失AB记录。

(2)当记录A insert到表中,已经commit,记录B insert到表中,未commit,此时发生了checkpoint。此时的IO队列中有insert A的redo请求,insert B的redo请求,A记录从db buffer向dbfile写的请求,还有控制文件被更新的请求。当都未写到裸设备时掉电,oracle端的情况是oracle认为redo的IO请求已经写到redo log中,db buffer的请求已经写入了数据文件,控制文件已经被更新,os端的情况是redo的IO请求和写dbfiles的IO请求均未完成,控制文件未更新。重启数据库时,由于scn还是一致的,因此能正常打开,但丢失cache中的A、B记录。

(3)当记录A insert到表中,已经commit,记录B insert到表中,未commit,此时发生了checkpoint。此时的IO队列中有insert A的redo请求,insert B的redo请求,A记录从db buffer向dbfile写的请求,还有控制文件被更新的请求。当redo的请求已经被写入redo log,但是A记录从db buffer向dbfiles写的请求和更新控制文件的请求还没写的时候掉电。Oracle端的情况是oracle认为redo的IO请求已经写到redo log中,db buffer的请求已经写入了数据文件,控制文件已经被更新,os端的情况是redo完成写入redo log,但是dbfiles未写,控制文件未更新。重启数据库,oracle读取了redolog、控制文件、dbfile,发现redo log、dbfile不一样,需要介质恢复。AB数据不丢失。

相关文章

7条评论

  1. 我觉得这个文章有待商榷

    1.redo是采用同步写的,即使OS上开启异步IO.同步写和异步写在OS是调用不同的API的
    2.不管OS是同步写还是异步写,存储上只要写cache没有关闭,都是write back模式的,也就是只保证写到cache就返回了,从cache写到磁盘是有存储慢慢批量写入的,这个跟异步IO没有关系。除非写cache失效,才会write through,但是这样写入的性能将急速下降

  2. 谢谢,写这个文章的用意也是为了抛砖引玉,和大家一起讨论。之前在QQ群里面和大家讨论过,上文是我的一些猜想,也是讨论后的初步的共识。
    谢谢宁总指出。

  3. 博主的意思是想分析在掉电而且存储cache保护电源也坏了的情况下的数据丢失情况。

    只是博主自己对这中间的一些细节还没有完全想明白。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据