由于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.redo是采用同步写的,即使OS上开启异步IO.同步写和异步写在OS是调用不同的API的
2.不管OS是同步写还是异步写,存储上只要写cache没有关闭,都是write back模式的,也就是只保证写到cache就返回了,从cache写到磁盘是有存储慢慢批量写入的,这个跟异步IO没有关系。除非写cache失效,才会write through,但是这样写入的性能将急速下降
谢谢,写这个文章的用意也是为了抛砖引玉,和大家一起讨论。之前在QQ群里面和大家讨论过,上文是我的一些猜想,也是讨论后的初步的共识。
谢谢宁总指出。
博主的意思是想分析在掉电而且存储cache保护电源也坏了的情况下的数据丢失情况。
只是博主自己对这中间的一些细节还没有完全想明白。
这里允许路过么~
re 小白:朕准了!
感谢。
那请准双程,早晚各一次。
小白,朕劝你要注意国母仪态……莫得寸进尺……