自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL 為什么需要兩階段提交?

數(shù)據(jù)庫(kù) MySQL
我們中文一般稱作歸檔日志,如果大家看過(guò)松哥之前發(fā)的 MySQL 主從搭建,應(yīng)該對(duì)這個(gè)日志有印象,當(dāng)我們搭建 MySQL 主從的時(shí)候就離不開(kāi) binlog。

為什么要兩階段提交?一階段提交不行嗎?

小伙伴們知道,MySQL 中的事務(wù)是兩階段提交,我們見(jiàn)到的很多分布式事務(wù)也都是兩階段提交的,例如 Seata,那么為什么要兩階段提交呢?一次直接提交了不行嗎?今天我們來(lái)聊聊這個(gè)話題。

1. 什么是兩階段提交

1.1 binlog 與 redologbinlog

binlog

我們中文一般稱作歸檔日志,如果大家看過(guò)松哥之前發(fā)的 MySQL 主從搭建,應(yīng)該對(duì)這個(gè)日志有印象,當(dāng)我們搭建 MySQL 主從的時(shí)候就離不開(kāi) binlog。

binlog 是 MySQL Server 層的日志,而不是存儲(chǔ)引擎自帶的日志,它記錄了所有的 DDL 和 DML(不包含數(shù)據(jù)查詢語(yǔ)句)語(yǔ)句,而且是以事件形式記錄,還包含語(yǔ)句所執(zhí)行的消耗的時(shí)間等,需要注意的是:

  • binlog 是一種邏輯日志,他里邊所記錄的是一條 SQL 語(yǔ)句的原始邏輯,例如給某一個(gè)字段 +1,注意這個(gè)區(qū)別于 redo log 的物理日志(在某個(gè)數(shù)據(jù)頁(yè)上做了什么修改)。
  • binlog 文件寫(xiě)滿后,會(huì)自動(dòng)切換到下一個(gè)日志文件繼續(xù)寫(xiě),而不會(huì)覆蓋以前的日志,這個(gè)也區(qū)別于 redo log,redo log 是循環(huán)寫(xiě)入的,即后面寫(xiě)入的可能會(huì)覆蓋前面寫(xiě)入的。
  • 一般來(lái)說(shuō),我們?cè)谂渲?binlog 的時(shí)候,可以指定 binlog 文件的有效期,這樣在到期后,日志文件會(huì)自動(dòng)刪除,這樣避免占用較多存儲(chǔ)空間。

根據(jù) MySQL 官方文檔的介紹,開(kāi)啟 binlog 之后,大概會(huì)有 1% 的性能損耗,不過(guò)這還是可以接受的,一般來(lái)說(shuō),binlog 有兩個(gè)重要的使用場(chǎng)景:

  • MySQL 主從復(fù)制時(shí):在主機(jī)上開(kāi)啟 binlog,主機(jī)將 binlog 同步給從機(jī),從機(jī)通過(guò) binlog 來(lái)同步數(shù)據(jù),進(jìn)而實(shí)現(xiàn)主機(jī)和從機(jī)的數(shù)據(jù)同步。
  • MySQL 數(shù)據(jù)恢復(fù),通過(guò)使用 mysqlbinlog 工具再結(jié)合 binlog 文件,可以將數(shù)據(jù)恢復(fù)到過(guò)去的某一時(shí)刻。

redo log

前面我們說(shuō)的 binlog 是 MySQL 自己提供的,在 MySQL 的 server 層,而 redo log 則不是 MySQL 提供的,是存儲(chǔ)引擎 InnoDB 自己提供的。所以在 MySQL 中就存在兩類日志 binlog 和 redo log,存在兩類日志既有歷史原因(InnoDB 最早不是 MySQL 官方存儲(chǔ)引擎)也有技術(shù)原因,這個(gè)咱們以后再細(xì)聊。

我們都知道,事務(wù)的四大特性里面有一個(gè)是持久性,即只要事務(wù)提交成功,那么對(duì)數(shù)據(jù)庫(kù)做的修改就被永久保存下來(lái)了,寫(xiě)到磁盤(pán)中了,怎么做到的呢?其實(shí)我們很容易想到是在每次事務(wù)提交的時(shí)候,將該事務(wù)涉及修改的數(shù)據(jù)頁(yè)全部刷新到磁盤(pán)中,一旦寫(xiě)到磁盤(pán)中,就不怕數(shù)據(jù)丟失了。

但是要是每次都這么搞,數(shù)據(jù)庫(kù)就不知道慢到哪里去了!因?yàn)?Innodb 是以頁(yè)為單位進(jìn)行磁盤(pán)交互的,而一個(gè)事務(wù)很可能只修改一個(gè)數(shù)據(jù)頁(yè)里面的幾個(gè)字節(jié),這個(gè)時(shí)候?qū)⑼暾臄?shù)據(jù)頁(yè)刷到磁盤(pán)的話,不僅效率低,也浪費(fèi)資源。效率低是因?yàn)檫@些數(shù)據(jù)頁(yè)在物理上并不連續(xù),將數(shù)據(jù)頁(yè)刷到磁盤(pán)會(huì)涉及到隨機(jī) IO。

有鑒于此,MySQL 設(shè)計(jì)了 redo log,在 redo log 中只記錄事務(wù)對(duì)數(shù)據(jù)頁(yè)做了哪些修改。那有人說(shuō),寫(xiě) redo log 不就是磁盤(pán) IO 嗎?而寫(xiě)數(shù)據(jù)到磁盤(pán)也是磁盤(pán) IO,既然都是磁盤(pán) IO,那干嘛不把直接把數(shù)據(jù)寫(xiě)到磁盤(pán)呢?還費(fèi)這事!

此言差矣。

寫(xiě) redo log 跟寫(xiě)數(shù)據(jù)有一個(gè)很大的差異,那就是 redo log 是順序 IO,而寫(xiě)數(shù)據(jù)涉及到隨機(jī) IO,寫(xiě)數(shù)據(jù)需要尋址,找到對(duì)應(yīng)的位置,然后更新/添加/刪除,而寫(xiě) redo log 則是在一個(gè)固定的位置循環(huán)寫(xiě)入,是順序 IO,所以速度要高于寫(xiě)數(shù)據(jù)。

redo log 本身又分為:

  • 日志緩沖(redo log buffer),該部分日志是易失性的。
  • 重做日志(redo log file),這是磁盤(pán)上的日志文件,該部分日志是持久的。

MySQL 每執(zhí)行一條 DML 語(yǔ)句,先將記錄寫(xiě)入 redo log buffer,后續(xù)在某個(gè)時(shí)間點(diǎn)再一次性將多個(gè)操作記錄寫(xiě)到 redo log file,這種先寫(xiě)日志再寫(xiě)磁盤(pán)的技術(shù)就是 MySQL 里經(jīng)常說(shuō)到的 WAL(Write-Ahead Logging) 技術(shù)(預(yù)寫(xiě)日志)。

1.2 兩階段提交

在 MySQL 中,兩階段提交的主角就是 binlog 和 redolog,我們來(lái)看一個(gè)兩階段提交的流程圖:

從上圖中可以看出,在最后提交事務(wù)的時(shí)候,有 3 個(gè)步驟:

  • 寫(xiě)入 redo log,處于 prepare 狀態(tài)。
  • 寫(xiě) binlog。
  • 修改 redo log 狀態(tài)變?yōu)?commit。

由于 redo log 的提交分為 prepare 和 commit 兩個(gè)階段,所以稱之為兩階段提交。

2. 為什么需要兩階段提交

如果沒(méi)有兩階段提交,那么 binlog 和 redolog 的提交,無(wú)非就是兩種形式:

  • 先寫(xiě) binlog 再寫(xiě) redolog。
  • 先寫(xiě) redolog 再寫(xiě) binlog。

這兩種情況我們分別來(lái)看。

假設(shè)我們要向表中插入一條記錄 R,如果是先寫(xiě) binlog 再寫(xiě) redolog,那么假設(shè) binlog 寫(xiě)完后崩潰了,此時(shí) redolog 還沒(méi)寫(xiě)。那么重啟恢復(fù)的時(shí)候就會(huì)出問(wèn)題:binlog 中已經(jīng)有 R 的記錄了,當(dāng)從機(jī)從主機(jī)同步數(shù)據(jù)的時(shí)候或者我們使用 binlog 恢復(fù)數(shù)據(jù)的時(shí)候,就會(huì)同步到 R 這條記錄;但是 redolog 中沒(méi)有關(guān)于 R 的記錄,所以崩潰恢復(fù)之后,插入 R 記錄的這個(gè)事務(wù)是無(wú)效的,即數(shù)據(jù)庫(kù)中沒(méi)有該行記錄,這就造成了數(shù)據(jù)不一致。

相反,假設(shè)我們要向表中插入一條記錄 R,如果是先寫(xiě) redolog 再寫(xiě) binlog,那么假設(shè) redolog 寫(xiě)完后崩潰了,此時(shí) binlog 還沒(méi)寫(xiě)。那么重啟恢復(fù)的時(shí)候也會(huì)出問(wèn)題:redolog 中已經(jīng)有 R 的記錄了,所以崩潰恢復(fù)之后,插入 R 記錄的這個(gè)事務(wù)是有效的,通過(guò)該記錄將數(shù)據(jù)恢復(fù)到數(shù)據(jù)庫(kù)中;但是 binlog 中還沒(méi)有關(guān)于 R 的記錄,所以當(dāng)從機(jī)從主機(jī)同步數(shù)據(jù)的時(shí)候或者我們使用 binlog 恢復(fù)數(shù)據(jù)的時(shí)候,就不會(huì)同步到 R 這條記錄,這就造成了數(shù)據(jù)不一致。

那么按照前面說(shuō)的兩階段提交就能解決問(wèn)題嗎?

我們來(lái)看如下三種情況:

情況一:一階段提交之后崩潰了,即寫(xiě)入 redo log,處于 prepare 狀態(tài) 的時(shí)候崩潰了,此時(shí):

由于 binlog 還沒(méi)寫(xiě),redo log 處于 prepare 狀態(tài)還沒(méi)提交,所以崩潰恢復(fù)的時(shí)候,這個(gè)事務(wù)會(huì)回滾,此時(shí) binlog 還沒(méi)寫(xiě),所以也不會(huì)傳到備庫(kù)。

情況二:假設(shè)寫(xiě)完 binlog 之后崩潰了,此時(shí):

redolog 中的日志是不完整的,處于 prepare 狀態(tài),還沒(méi)有提交,那么恢復(fù)的時(shí)候,首先檢查 binlog 中的事務(wù)是否存在并且完整,如果存在且完整,則直接提交事務(wù),如果不存在或者不完整,則回滾事務(wù)。

情況三:假設(shè) redolog 處于 commit 狀態(tài)的時(shí)候崩潰了,那么重啟后的處理方案同情況二。

由此可見(jiàn),兩階段提交能夠確保數(shù)據(jù)的一致性。

責(zé)任編輯:武曉燕 來(lái)源: 江南一點(diǎn)雨
相關(guān)推薦

2024-05-21 14:12:07

2024-12-06 07:10:00

2023-01-18 10:35:49

MySQL數(shù)據(jù)庫(kù)

2023-12-05 09:33:08

分布式事務(wù)

2023-07-26 09:24:03

分布式事務(wù)分布式系統(tǒng)

2017-08-30 18:15:54

MySql

2018-10-29 08:44:29

分布式兩階段提交事務(wù)

2023-11-29 07:47:58

DDIA兩階段提交

2022-12-21 19:04:35

InnoDBMySQL

2024-01-26 08:18:03

2020-02-03 12:12:28

MySQL數(shù)據(jù)庫(kù)SQL

2024-07-22 08:57:58

2021-10-12 19:12:15

單步實(shí)現(xiàn)系統(tǒng)

2024-12-23 13:00:00

MySQLMVCC數(shù)據(jù)庫(kù)

2011-02-16 09:42:04

DevOps

2022-07-27 08:52:10

MySQL二階段提交

2024-03-26 16:24:46

分布式事務(wù)2PC3PC

2023-10-24 08:25:20

TCC模式事務(wù)

2015-04-16 15:42:21

關(guān)系型數(shù)據(jù)庫(kù)NoSQL

2022-06-28 14:54:26

加密貨幣數(shù)組貨幣安全
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)