崩潰恢復與組提交

Ⅰ、binlog與redo的一致性(原子)

由內部分佈式事務保證mysql

咱們先來了解下,當一個commit敲下後,內部會發生什麼?sql

步驟 操做
step1 InnoDB作prepare redo log(fsync)
step2 Sever層寫binlog(fsync)
step3 InnoDB層commit redo log(fsync)

第一步寫的redo file,寫入的是trxid而不是page的變化(show binlog events in 'xxx'),準確的說寫在undo頁上數據庫

第三步寫的也是redo file緩存

以上說的寫入指的的成功落盤多線程

這裏的原理是一個內部的分佈式事務,相關參數:innodb_support_xa=onmvc

tips:oracle

5.6默認開啓分佈式事務(binlog和redo log同步),5.7你設置off也沒用,保證強一致性分佈式

Ⅱ、crash分析

服務crash,一個事務可能面對的狀態以下:性能

  • 1成功,2失敗,那3確定失敗,重啓則rollback(利用undo,一個事務的undo在active list(活躍事務列表)中就表示沒提交,redo完後從active list中找沒提交的事務去回滾)
  • 1成功,2成功,3失敗,重啓則commit
  • 1,2,3都成功,重啓commit(將這個事務對應的undo從active list中移走,移到history list中,不能直接清理,其餘事務可能還須要引用,mvcc機制要看,真正清理是後臺purge thread作)

tips:測試

①不談高可用的狀況下,若是兩個日誌都寫成功,其實commit和rollback都沒有問題,用戶並不知道他commit會不會成功,他只知道數據庫斷了,這種事務叫partial transaction,可提交可不提交

②mysql這裏作commit是爲了複製數據同步

③寫重作日誌oracle一次fsync,mysql要三次?

第一步或者第二步失敗,天然沒有第三次,前兩步成功的話,其實第三步不用寫到磁盤持久化,只要寫到操做系統緩存就能夠,不論是否有沒有commit的日誌,都會提交,因此實際上是兩次,可是有組提交加持,可能2次fsync提交了10個事務都有可能

Ⅲ、怎麼個恢復法子?

3.1 面對crash部分怎麼處理?

在innodb層,prepare redo log中會記錄一個trxid,宕機從新起來恢復時

  • step1

    先scan binlog,把全部的trxid拿出來作一個hash table(掃最後一個binlog文件,一個事務的日誌是不能跨文件的)

  • step2

    去scan innodb redo log,掃cp開始日後的部分,也會產生trxid list

  • step3

    這時候去上面那個hash table中search,若是這個trxid在上面的hash表中,就是兩個步驟都沒問題,就commit,若是不在裏面(第二步寫binlog沒成功)就rollback

tips:

上面說的已是在數據庫層面了,也就是說用戶commit以後數據庫裏面作的東西,用戶是不能夠rollback的,也就是說應用層表現爲失敗,並不表明是真正的失敗

以上討論是crash臨界點地方處理

3.2 整個恢復過程是怎樣的呢?

先回顧一下lsn

LSN
    log sequenct number
    重作日誌寫入的字節量
LSN存在於:
    page
    redo log block
    checkpoint

看圖說恢復

  • 先scan redo log,從cp開始掃描,掃到最後一個日誌塊
  • 接着就redo,將全部的page重作(看page中的lsn來判斷到底要不要重作,若是page lsn已經比redo log lsn來的大,就說明先刷了,不用重作了)
  • 最後接到前面的掃兩個hash table,將沒有提交的事務用undo進行rollback

Ⅳ、組提交

背景:commit的本質就是每次提交後執行下面的操做

由innodb_flush_log_at_trx_commit參數決定

  • 1 fsync 寫盤
  • 2 fwrite 寫緩存
hdd盤的iops是100,那一秒鐘只能執行100次fsync,增刪改的qps的最大就是100(每作一個增刪改就提交一次)

因此咱們常常批量導入數據

批量導數據,begin;插10條;commit  這樣就只fsync了一次,這樣qps就提高了10倍

就這樣組提交誕生來了——一次fsync刷新一組事務(多線程)

性能提升10~100+倍,innodb存儲引擎原生支持,事務響應不會變慢的,不用擔憂

看兩個相關參數(5.7纔有)

binlog_group_commit_sync_delay 組提交必定要等待多少微秒,時間越長一次性提交的事務越多,fsync次數越少,性能越好
binlog_group_commit_sync_no_delay_count 累積到多少個才組提交

千萬不要調,你是調很差的呢,好比你調成5個事務,那你業務沒五個線程,那你就被hang住了,數據庫自身已經作的很好了

5.5有個bug,開啓binlog,組提交就會失效,設置雙1的話,性能會不好,那時候爲了緩解這個問題把innodb_flush_log_at_trx_commit設置爲2,crash可能最後一段事務丟失

tips:

  • 5.6和5.5一塊兒跑純更新操做的sysbench測試,前者性能會比後者好8到10倍
  • 5.6中設置爲2,性能基本上沒什麼差異,在3%到5%之間
  • 因此說5.6以前的版本就不要用了,就這麼一個緣由就夠了
  • 另一個提高性能的參數
    sync_binlog參數 5.7默認爲1,以前默認爲0

    0表示事務提交後,binlog寫到操做系統緩存,操做系統控制怎麼寫到文件
      1表示事務提交時binlog寫到磁盤
      100表示100次事務提交刷一次磁盤

    5.5中設置爲0是有提高,5.6以後就不會有這個問題了,並且0可能會有丟數據的風險

到這裏傳說中的innodb事務系統中的雙1到這裏就解釋清楚了,到如今爲止咱們就不用把這兩個值設爲其餘值了

附:官網的一句話:分佈式事務就要用serializable,這時候串行纔有意義,想不通

Ⅴ、補充redo和binlog區別

  • binlog是server層的邏輯日誌
  • redo是innodb層的物理邏輯日誌
  • 二者寫入的時間點不同,binlog只有在事務提交時寫入,redo會在好幾種狀況下寫入,以前分析過

binlog 直接按事務提交順序

redo log 按帶星號的順序提交,只要page發生修改就會記錄到日誌中,因此T2修改的日誌能夠和T1是對同一個page修改

雖然都是T1 T2 T3,可是binlog記錄的是數據庫的操做,相似sql語句的

redo log記錄的是對page的修改,一個事務能夠對多個page進行修改,事務是並行在運行的,因此能夠有多個事務對多個不一樣的page在修改,因此提交順序比較特殊

redo log裏面一個事務的日誌能夠有不少,但binlog只有一個

redo log在事務提交過程當中就開始寫,binlog在事務提交最後纔開始寫

千萬記住redo log裏面沒記錄sql的

協助理解:

一個update操做,提交後寫了一個binlog,可是可能update修改了不少page進而產生了不少redo log,而後根據事務提交順序來寫盤,好比T1事務先操做了page A沒提交,T2事務跟着對page A作了修改提交了,這時候就會寫redo,此時T1事務還沒提交呢

tips:

  • oracle中沒有binlog,無論事務大小,提交的時間都是平均的,由於在事務執行的過程當中日誌就在刷盤了
  • 在mysql中因爲binlog是事務提交後纔開始寫,因此大事務提交時間很長,小事務提交時間比較短
  • 大事務提交會影響到後面事務提交,會排隊,不過排隊是好事,後面排一塊兒組提交
相關文章
相關標籤/搜索