【学习笔记7】ARIES学习

ARIES(Algorithm for Recovery and Isolation Exploiting Semantics)
ARIES的性质: WAL协议的算法

1. 数据结构

图1: ARIES数据结构

如图1,在ARIES中主要有三大模块:buffer pool manager,transaction system和log system。ARIES支持灵活的buffer pool管理策略,例如可以使用steal+no-force的page管理策略。

1.1 日志条目

name description
LSN 日志条目的编号,log sequence number
Type 日志类型
TRX-ID 写当前日志条目的事务id
PrevLSN 当前事务上一条日志LSN,与CLR的UndbNxtLSN共同串联起rollback的日志链
PageID 日志条目的更新page目标
UndoNxtLSN CLR独有,表示当前某条日志的回滚完成,下一条目标回滚日志LSN,与PrevLSN共同形成rollback日志链

1.2 page

name description
page_LSN 最新更新当前page的日志LSN

1.3 DPT(dirty page table)

DPT由多条dirty page entry组成,每条entry的主要字段:

name description
page_id 当前条目对应的page的id
RecLSN 当一个非脏的page被pined去修改时,buffer pool manager记录日志LSN

RecLSN表明自此日志开始,当前page有可能被修改且没有flush到stable storage。在recover过程中,RecvLSN可以减少对潜在dirty page的检查。

1.4 ATT(Active Transaction Table)

由多条事务条目组成,每条条目的主要字段有:

name description
trx-id 当前条目对应事务的id
state 事务状态:prepared(in-doubt),unprepared
LastLSN 当前事务最新写的日志LSN
UndoNxtLSN 当前事务回滚时,下一条要处理的日志LSN

2.系统常规运行

  1. 事务在常规运行过程中,当修改page时,不断地向日志系统中写日志条目,一般的update日志为undo-redo log,包含了当前操作的redo信息(page-oriented信息)和undo信息(logical undo信息)【ARIES采用page-oriented redo log和logical undo log,page-oriented log可以隔离各个事务的history repeatition,响应了ARIES的I(isolation),而使用logical undo可以使数据库系统提供更好的并发性能】;更新ATT的LastLSN和UndoNxtLSN;如果是更新非脏页,更新DPT并设置其条目的RecvLSN;更新修改的page的page_lsn。
  2. 事务常规回滚时,写CLR(compensation log record)。CLR是read-only的日志,记录了目标日志的undo操作。【核心问题:CLR是undo log,那他是logical undo log还是page-orientd undo log? 上文阐述了ARIES采用logical undo log的策略,但是CLR并不是logical undo log,而是page-oriented undo log。不过虽然CLR的实际内容是page-oriented,但是其语义却是logical undo log。因为其是由上文提到的普通update日志的logical undo信息生成的,这也是ARIES最精妙的地方。】CLR使用UndoNxtLSN字段和其他日志的PrevLSN共同形成了事务回滚的日志链,使得在重复的系统故障中,DB的recovery是幂等的。同时,CLR可以描述undo行为,而undo行为可以是logical undo,因此ARIES支持logical undo。
  3. 在系统运行过程中,buffer pool manager周期性flush dirty pages。ARIES对buffer pool的page管理策略没有限制,支持steal+no-force的管理策略。
  4. 在系统运行过程中,系统周期性做checkpoint。ARIES支持fuzzy checkpoint,fuzzy checkpoint是异步的checkpoint,在其异步输出时可以不阻塞其他事物的处理。Fuzzy checkpoint格式:
<begin_chkpt>
......
<end_chkpt, ATT, DPT, others>

<end_chkpt>写入后,系统中写入master_record,用以记录最新的checkpoint的<begin_chkpt>。在写DPT信息时,为了避免对事务造成场阻塞,可以少量地对DPT内容进行加锁写入。正确性不会影响,由recovery的analysis pass保证。

3. Recovery

如图展示了ARIES的recovery总体框架图。


图2:ARIES Recovery

ARIES的recovery过程有三个阶段:Analysis Pass、Redo Pass和Undo Pass

3.1 Analysis Pass

Analysis阶段以master record作为输入,找到最新的成功begin_chkpt LSN,并输出RedoLSN、ATT和DPT。RedoLSN用于指示Redo阶段开始redo行为的日志LSN。

Analysis Pass由begin_chkpt LSN开始分析到日志文件末尾。APT和DPT由checkpoint信息初始化,并在序列分析所有的日志信息时,如果更新的page不在DPT,则将该page添加到DPT中;如果有新事务(<begin>),则将该事物添加到ATT中;如果事务结束(<end>),则将事务从ATT中移除。对于普通的日志条目,根据其信息更新ATT和DPT。最终,RedoLSN = min(LSN(<begin_chkpt>), min(ATT_ENTRY[RecLSN]))

RESTART_ANALYSIS(Master_Addr, Trans_table, Dirty_pages, RedoLSN) ; 
    lnlitiallze the tables Trans_Table and Dirty_Pages to empty; 
    Master_Rec := Read_Disk(Master_Addr) ; 
    Open_Log_Scan (Master_Rec.ChkptLSN) ;   /*open log scan at Begin_Chkpt record */ 
    LogRec := Next_ Logo; /* read in the Begin_Chkpt record */ 
    LogRec := Next_ Logo; /* read log record followlng Begln_Chkpt */ 
    WHILE NOT(End_of_Log) DO; 
         IF trans related record & LogRec.TransID not in Trans Table THEN /* not chkpt/OSflle_return*/ 
              Insert (LogRec.TransID, 'U' , LogRec.LSN, LogRec. PrevLSN) into TransTable; /* log record */       
         SELECT (LogRec.Type)  
              WHEN( 'update' I 'compensation') DO; 
                  Trans_Table[LogRec.TransID].LastLSN := LogRec.LSN; 
                  IF LogRec.Type = 'update'   THEN 
                       IF LogRec is undoable THEN Trans_Table[logRec.TransID].UndoNxtLSN := LogRec.LSN;               
                  ELSE Trans_Table[LogRec.TransID].UndoNxtLSN := LogRec.UndoNxtLSN;  
                                  /* next record to undo is the one pointed to by this CLR */ 
                  
                  IF LogRec is redoable & LogRec.pageID NOT IN Dirty_Pages THEN 
                        insert(LogRec.PageID, LogRec.LSN) into Dirty_Pages; 
              END; /* WHEN( 'update'I 'compensation') */ 
              WHEN( 'Begln_Chkpt') ; /* found an Incomplete checkpoint's Begln_Chkpt record ignore It */ 

              WHEN( 'End_Chkpt')  DO; 
                  FOR each entry in LogRec.TransTable DO; 
                      IF Trans ID NOT IN Trans_Table THEN DO; 
                          insert entry (TransID, State, LastLSN, UndoNxtLSN) In TransTable; 
                      END; 
                  END; /* FOR */ 
                  
                  FOR each entry in LogRec.DirtyPagLst DO; 
                      IF PagelD NOT IN Dirty_Pages  THEN insert entry (PageID, RecLSN) In Dirty_Pages; 
                      ELSE set RecLSN of Dirty_Pages entry to RecLSN In Dirty_PagLst; 
                  END; /* FOR */ 
               END; /* WHEN( 'End Chkpt') */ 
    
              WHEN( 'prepare' | 'rollback')  DO; 
                    IF LogRec.Type = 'prepare' THEN Trans_Table[LogRec.TransID].State := 'P' ; 
                    ELSE TransTable[LogRec.TransID].State := 'U'; 
                    Trans_Table[LogRec.TransID].Last LSN := LogRec.LSN; 
              END; /* WHEN( 'prepare'I 'roll back') */ 

              WHEN('end') 
                    delete Trans_Table entry for which TransID = LogRec.TransID; 
              
               WHEN( 'OSfile_return') 
                    delete from Dirty_Pages all pages of returned file; 
         END; /* SELECT */ 
         LogRec := Next_ Log(); 
     END; /*WHILE */ 

    FOR EACH TransTable entry with (State = 'U') & (Undo Nxt LSN = O) DO; /* rolled back trans */ 
        write end record and remove entry from Trans_Table;   /* with missing end record */ 
    END;   /* FOR */ 
    RedoLSN := minimum(Dirty_Pages.RecLSN) ; /* return start position for redo */ 
    RETURN;

3.2 Redo Pass

Redo阶段以Analysis阶段输出的DPT和RedoLSN为输入,从stable storage中加载所有可能的dirty page,并从日志文件的RedoLSN开始,序列处理每条日志。如果当前日志是可redo的,日志目标更新page在DPT中,且LSN > Page_LSN && LSN > Dirty_Pages[LogRec.PageID].RecLSN,则将该日志在page上进行redo,同时更新page的Page_LSN为当前Log_LSN。

因此,DPT entry的RecLSN可以减少recovery过程中要校验的page数量。

Redo Pass是无锁的,因为ARIES中日志是page-oriented redo log和page-oriented undo log(CLR,由logical undo语义产生)。每个page的操作都是隔离的。因此,可以进行并行的redo。

RESTART-REDO(RedoLSN, Di rty_Pages); 
      Open_Log_Scan(RedoLSN);     /* open log scan and position at restart pt */ 
      LojRec := Next_ Logo;     /* read log record a: restart redo point */ 
      WHILE NOT(End_of_Log) DO;   /* look at all records till end of log */ 
            IF LogRec.Type = ( 'update'  |  'compensation')  &
                LogRec is redoable   &
                LogRec.PageID IN Dirty-Pages   &
                LogRec.LSN >= Dirty_Pages[LogRec.PageID].RecLSN
            THEN DO;            /* a redoable page update.updated page mg-t not have made It to */
                                /* disk before sys failure.need to access cage and check Its LSN */ 
                    Page := fix&l atch(LogRec.PageID, 'X'); 
                          IF Page.LSN < LogRec.LSN THEN DO /* update not or cage.need to redo It */                         
                                 Redo_Update(Page, LogRec); /*redo update */ 
                                 Pag.LSN := LogRec.LSN; 
                          END; /* redid update */ 
                          ELSE   Dirty_Pages[LogRec. PageID].RecLSN := Page.LSN+1; /* update already on page */
                                /*update dirty page list with correct info, trans will happen if this */ 
                                /* page was written to disk after the checkpt but before sys failure */ 
                          unfix&unlatch (Page); 
            END; /* LSN on page has to be checked */ 
      LogRec: = Next_ Log (); /* read next log record */ 
      END; /* reading till end of log */ 
      RETURN;

3.3 Undo Pass

从日志文件的最后日志开始反时间序分析。每个事务的待undo的log已经通过CLR的UndoNxtLSN和non-CLR的PrevLSN形成了undo日志链,在recovery过程中,下一条待undo的日志就是所有ATT中事务undo日志链的最新日志记录(UndoLSN := maximum(UndoNxtLSN) from Trans_Table entries with State = 'u';)。当一条日志是可undone的时,则将该日志undo,并向日志文件中补写当前被undone日志的CLR并更新ATT事务的UndoNxtLSN;如果是当前事务的首日志,则向日志文件中写当前事务的<end>日志并从ATT中删除;否则更新ATT事务的UndoNxtLSN。

Undo Pass也是无锁的,这是由于所有的更改在语意级都是绝对互斥的,一个还没commit的Tx如果可以进行某种“更改”并生成其伴随的Undo/Redo log,那么绝对不会有其他Tx可以更改同一个Object,从而生成冲突的Undo/Redo log, 换句话说,所有的Redo/Undo/CLR都在高层语意上是无冲突的,不同的Tx也许回改同一个页面,但是它们绝对不会更改同一个Row(如果数据库支持行锁)或者可以更改同一个Row,但是绝不会更改同一个Field(如果数据库支持field级锁);无锁的Rollback是避免死锁的关键, 这样就不会发生Rollback和另外一个Rollback相互死锁的尴尬,此时需要Rollback一个Rollback, 这也是很多数据库设计力图避免的问题(引用知乎分析)

由于每个独立的事物都有自己的undo日志链,因此可以在事物级并行地进行undo【但是如何保证并行时仍然是反时间序?

RESTART_UNDO(Trans-Table); 
WHILE EXISTS (Trans with State = 'U' in Trans_Table) DO; 
      UndoLSN := maximum(UndoNxtLSN) from Trans_Table entries with State = 'u'; 
                    /* pick up UndoNxtLSN of unprepared trans with maximum UndoNxtLSN */ 
      LogRec := Log-Read (UndoLSN); /* read log record to be undone or a CLR */
      SELECT(LogRec.Type) 
            WHEN('update')  DO; 
                IF LogRec is undoable THEN DO; /*record needs undoing (not redo-only record) */ 
                    Page := flx&latch(LogRec.PageID, 'X'); 
                    Undo_Update(Page, LogRec); 
                    Log_Write('compensation' , LogRec.TransID, Trans_Table[LogRec.TransID].LastLSN, 
                          LogRec.PageID, LogRec.PrevLSN, . . . ,LgLSN, Data);  /* write CLR */ 
                    Page.LSN := LgLSN; /*store LSN of CLR in page */ 
                    Trans_Table[LogRec.TransID].LastLSN := LgLSN; /*store LSN of CLR in table */ 
                    unfix&unlatch(Page); 
               END; /* undoable record case */ 
               ELSE; /* record cannot be undone - ignore it */ 
                    Trans_Table[LogRec.TransID].UndoNxtLSN := LogRec.PrevLSN; /* next record to process is the one preceding this record in its backward chain */ 
                     IF LogRec.PrevLSN = 0 THEN DO; /* have undone completely-write end */ 
                          Log_Wrlte( 'end' ,LogRec.TransID, Trans_Table[LogRec.Transit].LastLSN,  . . .) ; 
                          delete Trans_Table entry where TransID.LogRec.TransID; /* delete trans from table */ 
                     END ; /* trans fully undone */ 
            END; /* WHEN('update') */ 
            WHEN( 'compensation') 
                    Trans_Table[LogRec.TransID].UndoNxtLSN := LogRec.UndoNxtLSN; /* pick up addr of next record to examine */ 
            WHEN( 'rollback' | 'prepare') 
                    Trans_Table[LogRec.TransID].UndoNxtLSN := LogRec.PrevLSN; /* pick up addr of next record to examine */ 
     END; /* SELECT */ 
END; /* WHILE */ 
RETURN ;

ARIES的特性

  1. 支持小于page粒度的并发控制和多粒度锁机制
  2. 支持灵活的buffer pool管理策略(可以采用steal+no-force的最高灵活度策略)
  3. 低page存储负载(每个page只需要存储一个page_LSN字段)
  4. redo/undo的幂等操作不依赖对数据进行限制(通过CLR)
  5. Logical Undo(ARIES采用page-oriented redo log和logical undo log语义,CLR是由logical undo log语义生成的page-oriented undo log)
  6. 支持operation log和novel lock model
  7. 兼容redo-only和undo-only日志
  8. 支持partial/total事务回滚
  9. 支持数据对象跨page存储
  10. 支持动态的从OS获取/移除文件(操作视为redo-only)
  11. Nest top action(通过调整CLR的UndoNxtLSN字段,如果使用redo-only log,则该日志不可回滚,不符合语义)
  12. 高效的checkpoint(fuzzy checkpoint技术以及recovery过程中的checkpoint可以减少recovery时间)
  13. 对同一page的并发事务处理/回滚(只需要latch page)
  14. 事务回滚不需要获取锁(只需要latch page,锁正确性由高层语义保证,partial rollback后可以释放相关锁,同时避免了rollback中死锁的产生)
  15. 即使多次recovery,日志数量亦有限(redo pass不产生log,undo产生CLR,常规处理中事务写的每条日志至多产生一条CLR)
  16. 支持recovery并行(Analysis Pass预获取dirty pages list并执行并行IO,并行redo【page】,并行undo【transaction】,支持deferred recovey)
  17. fuzzy image copying技术
  18. 支持恢复失败事务
  19. recovey只需要一次逆向日志遍历
  20. CLR为redo-only,只需要redo信息(因此CLR的空间占用是事务普通日志的一半,普通日志为redo-undo log)
  21. 支持分布式事务
  22. partial rollback后,可以及时释放相关锁,亦简化了死锁检测逻辑(因为CLR不会被undone且non-CLR日志之多被undone一次)

感想

  1. ARIES最精妙在于CLR的使用,由logical undo语义产生page-oriented的CLR undo log。
  2. 通过page-oriented redo log和CLR实现了各个page之间的隔离性,可以并行redo。
  3. Undo pass的并行感觉效率不高,因为需要保证并行时任然维持反时间序列的正确性。(ARIES文中提到了有page级的undo pass并行,待进行阅读理解。)
  4. Analysis pass可以减少redo pass中的IO数量,提升并行效率
  5. 通过日志的时间序和page的日志隔离性,使得整个recovery的过程是无锁的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容