mysql的邏輯日志、物理日志與物理邏輯日志

轉(zhuǎn)載:邏輯日志與物理日志

日志主要分為邏輯日志和物理日志:

  • 邏輯日志 Logic log[1];
  • 物理日志 Physical log[2];

1. 物理日志與邏輯日志的存儲(chǔ)內(nèi)容

1.1 Physical Logging

物理日志和邏輯日志在存儲(chǔ)內(nèi)容上有很大區(qū)別,存儲(chǔ)內(nèi)容是區(qū)分它們的最重要手段。

物理日志:

  • 存儲(chǔ)內(nèi)容:存儲(chǔ)數(shù)據(jù)庫中特定記錄的變更,通常是 page oriented,即描述具體某一個(gè) page 的修改操作;
  • 例子:一條更新請(qǐng)求對(duì)應(yīng)的初始值(original value)以及更新值(after value);

邏輯日志:

  • 存儲(chǔ)內(nèi)容:存儲(chǔ)事務(wù)中的一個(gè)操作;
  • 例子:事務(wù)中的 UPDATE、DELETE 以及 INSERT 操作。

下圖是一種典型的物理日志:

物理日志.png

figure1.典型的物理日志

我們可以看到,更新操作作用于 Page42,將字段 “Kemera” 修改為 “camera”。更新操作對(duì)應(yīng)的日志為:

"Page 42:image at 367,2; before:'ke';after:'ca'"

其中:

  • Page 42 用于說明更新操作作用的 page;
  • 367:用于說明更新操作相對(duì)于 page 的 offset;
  • 2:用于說明更新操作的作用長(zhǎng)度,即 length,2 代表僅僅修改了兩個(gè)字符;
  • before:‘Ke’:這里表示 undo information,也可以稱為 undo log;
  • after:‘ca’:這里表示 redo log information,也可以稱為 redo log;

當(dāng)然,一條物理日志可以有多個(gè)字段的修改,下面是一個(gè)抽象版本:

(Page ID,Record Offset,length,(Filed 1, Value 1) … (Filed i, Value i) … )

注意事項(xiàng):

  • 物理日志實(shí)際上以字節(jié)編碼落盤,而不是字符編碼,因此通常肉眼不可見;
  • image 的含義通常指代鏡像,但這里不是說對(duì) page 做整個(gè)鏡像,而是對(duì)更改或增量(change/delta)操作做鏡像,before image 代表寫操作作用之前的字段副本,after image 代表寫操作作用之后的字段副本;

可見,physical log 中的一條記錄對(duì)應(yīng)于狀態(tài)機(jī)(state mechine)上某一個(gè) page 上的某些字段做了什么改動(dòng)的落盤。

1.2 Logical Logging

邏輯日志又被稱為 high-level logging,這是相對(duì)于物理日志而言的。

下圖是一個(gè)典型的邏輯日志:

邏輯日志.png

Figure2.典型的邏輯日志

在上圖中,有一張 CameraLingo 表,我們?cè)噲D糾正 itermID 為 0 的拼寫錯(cuò)誤,即將 “Kemera” 修改為 “Cemera”。邏輯日志的格式如下:

CameraLingo:update(0,'Kermera'=>'camera')

邏輯日志被稱為 high level 的原因是其更抽象,其不需要指明更新操作具體作用于哪一塊 page,因此也對(duì)底層少了一些限制。如果利用物理日志進(jìn)行宕機(jī)后的數(shù)據(jù)恢復(fù),那么需要確保 page 不能夠改變,但利用邏輯日志并不在乎底層 page 是否改變。

熟悉 MySQL 的同學(xué)可以發(fā)現(xiàn)邏輯日志與一條 SQL 語句非常類似,事實(shí)上確實(shí)如此,邏輯日志的本質(zhì)就是對(duì)更新語句(update query)本身的落盤。在本節(jié)的例子中,只需要指明在哪一張表上的哪一行,對(duì)哪一些字段進(jìn)行什么修改即可。邏輯日志不用物理上的 page,而用邏輯上的表。

另一方面,得益于 high level 的抽象,一個(gè)邏輯日志可以對(duì)應(yīng)多條物理日志,下面舉一個(gè)例子:

CameraLingo:capitaLetter(term)

上述邏輯日志的語義是對(duì) CameraLingo 表中所有 term 字段對(duì)應(yīng)的屬性首字母大寫,如果表足夠大,此次邏輯日志涉及多個(gè) page 上的修改,因而需要多個(gè)物理日志。

需要指出的是 high level 的數(shù)據(jù)結(jié)構(gòu)抽象不僅僅局限于 table,例如 key-value 也是一個(gè)典型的 high level 數(shù)據(jù)結(jié)構(gòu)。

1.3 Physiological Logging

除了物理日志以及邏輯日志,還有一種日志被稱為 Physiological Logging[3],其試圖同時(shí)獲得物理日志與邏輯日志的優(yōu)勢(shì)。

下圖是一個(gè)典型的 Physiological Logging:

邏輯物理日志.png

Figure3.典型的 Physiological Logging

Physiological Logging 的格式也可以如下表示:

(Page ID,Record Offset,(Filed 1, Value 1) … (Filed i, Value i) … )

其中,Page ID、Record Offset 的設(shè)計(jì)源于物理日志。(Field1,Value1) 的設(shè)計(jì)來源于邏輯日志。

Physiological Logging 的特點(diǎn)是:

  • 與物理日志相同,更新操作相對(duì)于 page 進(jìn)行,每一條日志僅僅涉及一個(gè) page 的修改;
  • 與邏輯日志相同:日志內(nèi)容為更新語句(update query)本身,而不是狀態(tài)機(jī)某些字段更新前后的狀態(tài)。

2. 物理日志與邏輯日志的比較

2.1 事務(wù)并發(fā)控制

什么是事務(wù)并發(fā)控制,為什么需要事務(wù)并發(fā)控制?

我們需要使用事務(wù)并發(fā)控制的原因基于以下事實(shí)(以 MySQL 為語境解釋):

  1. 事務(wù)由 SQL 語句構(gòu)成,每一個(gè) SQL 語句可分解為多個(gè)不可分隔的讀/寫操作;
  2. 事務(wù)的執(zhí)行實(shí)際上是一連串不可分割讀寫操作的執(zhí)行;
  3. 事務(wù)調(diào)度器負(fù)責(zé)調(diào)度不可分割讀寫操作的執(zhí)行順序,它們可能來自于不同事務(wù);
  4. 事務(wù)并發(fā)控制的一個(gè)目標(biāo)就是實(shí)現(xiàn)并行化事務(wù);

邏輯日志很難實(shí)現(xiàn)一致的事務(wù)并發(fā)控制。由于邏輯日志難以攜帶并發(fā)執(zhí)行順序的信息,當(dāng)同時(shí)有多個(gè)事務(wù)產(chǎn)生更新操作時(shí),數(shù)據(jù)庫內(nèi)部會(huì)將這些操作調(diào)度為串行化序列執(zhí)行,需要機(jī)制來保障每次回放操作的執(zhí)行順序與調(diào)度產(chǎn)生的順序一致。

另一方面,物理日志本身就是存儲(chǔ)就是基于不可分隔的更新操作,因此其存儲(chǔ)先后順序就代表了執(zhí)行器的調(diào)度順序。而且由于很容易判斷兩個(gè) page 是否是同一個(gè) page,如果不是,完全可以安全并行地并行執(zhí)行。

為了實(shí)現(xiàn)宕機(jī)前后事務(wù)并發(fā)控制的一致性,數(shù)據(jù)庫選擇使用 Physical Logging 作為其 Redo Log。

2.2 冪等性

冪等性在日志上的語義是:無論日志回放多少次,最終得到的結(jié)果保持一致。

物理日志能夠做的冪等性,因?yàn)槠浔举|(zhì)是對(duì)狀態(tài)機(jī)某一個(gè)字段在更新前后狀態(tài)的記錄,無論執(zhí)行多少次,最終得到的狀態(tài)總是相同的。下面是一個(gè)例子:

"Page 42:image at 367,2; before:'ke';after:'ca'"

邏輯日志并不能夠提供冪等性的語義,因?yàn)槟骋粋€(gè)更新操作本身不具備冪等性。例如:

CameraLingo:update(0,age=>age+1)

如果 age 的原值為 0,如果執(zhí)行一次,那么 age 更新為 1。如果執(zhí)行兩次,那么 age 更新為 2。

當(dāng)然,如果更新操作本身是冪等的,邏輯日志也可以是冪等的,例如:

CameraLingo:capitaLetter(term)

上述邏輯日志無論回放多少次(至少一次),最終得到的結(jié)果也就是將首字母大寫。

2.3 數(shù)據(jù)量大小

邏輯也不是一無是處,其在日志數(shù)據(jù)量上占優(yōu)。

來自客戶端的一條更新語句可能會(huì)對(duì)應(yīng)多個(gè) page 上的更新,因此邏輯日志與物理日志在日志數(shù)量上有巨大的區(qū)別。

#查詢語句
CameraLingo:capitaLetter(term)
#物理日志
"Page 42:image at 3,1; before:'k';after:'K'"
"Page 42:image at 22,1; before:'a';after:'A'"
....
"Page 42:image at 442,1; before:'b';after:'B'"
#邏輯日志
CameraLingo:capitaLetter(term)

別小看!日志數(shù)據(jù)量大小是特別重要的特性,其對(duì)以下過程都有影響:

  • 磁盤 I/O 吞吐量;
  • 落盤文件大小;
  • 網(wǎng)絡(luò)帶寬;

這里的重點(diǎn)是網(wǎng)絡(luò)帶寬。分布式系統(tǒng)會(huì)通過 primary 副本向 secondary 副本發(fā)送日志的方式來進(jìn)行分布式事務(wù)的維護(hù),因此使用物理日志進(jìn)行傳播就不合適。例如,MySQL 就選擇邏輯日志進(jìn)行維護(hù)分布式事務(wù)。

2.4 日志重放效率

邏輯日志比物理日志在重放時(shí)有著更低的效率,這主要有兩個(gè)方面的原因:

  • 額外的解釋步驟:邏輯日志需要額外地解釋更新語句、額外查找實(shí)際 page 位置;
  • 物理日志可以并發(fā)進(jìn)行:當(dāng)系統(tǒng)判斷兩個(gè)物理日志作用于不同的 page 時(shí),就可以進(jìn)行完全的并行處理,而邏輯日志通常只能串行執(zhí)行。

2.5 磁盤/內(nèi)存式日志系統(tǒng)的 trade-off

其次,基于磁盤的存儲(chǔ)系統(tǒng)與基于內(nèi)存的存儲(chǔ)系統(tǒng)對(duì)邏輯日志以及物理日志有著不同的 trade-off(權(quán)衡),如下面兩張圖所示。

基于磁盤的存儲(chǔ)系統(tǒng)的日志 I/O 效率與 replay 效率.png
figure.基于內(nèi)存的存儲(chǔ)系統(tǒng)的日志 I/O 效率與 replay 效率.png

3. 工業(yè)實(shí)踐與典型案例

3.1 MySQL

MysQL 對(duì)存儲(chǔ)引擎層以及 sever 提供了不同的日志方案。以 InnoDB 存儲(chǔ)引擎為例。

(1)server 層的 bin log

MySQL 的 server 層使用 binlog,其屬于邏輯日志[4]。bin log 分為兩種類型:

  1. 基于語句的日志記錄(Statement-based logging):主要記錄了該 MySQL 執(zhí)行語句(包括 inserts, updates, deletes);
  2. 基于行的日志記錄(Row-based logging):主要記錄了對(duì)單個(gè)行的修改,其在 MySQL 5.1.5 后引入;

無論是 SQL 更新語句還是行上具體某個(gè)修改,都是邏輯日志,因?yàn)槎紱]有涉及在具體哪一個(gè) page 上進(jìn)行修改。

為此,MySQL 提供了三個(gè)模式進(jìn)行配置:

  • Statement:基于語句的 binlog 日志記錄(statement-based replication-SBR);
  • Row:基于行的 binlog 日志記錄(row-based replication-RBR);
  • Mixed:混合模式,通?;谡Z句,有必要的情況下基于行實(shí)現(xiàn)(mixed-based replication-MBR);

MySQL 從 V5.1.8 開始提供 Mixed 模式,V5.7.7 之前的版本默認(rèn)是Statement 模式,之后默認(rèn)使用 Row 模式, 但是在 8.0 以上版本已經(jīng)默認(rèn)使用 Mixed 模式了。

MySQL 在 [5] 中指出了上述兩種邏輯日志的優(yōu)缺點(diǎn)。

基于語句的 binlog:

  • 優(yōu)點(diǎn):
    • 技術(shù)成熟;
    • 數(shù)據(jù)更少,即使一個(gè)更新操作會(huì)影響非常多的行。
    • 包括任何更新語句,因此可以用于數(shù)據(jù)庫維護(hù)人員維護(hù)數(shù)據(jù)庫;
  • 缺點(diǎn):并非所有 SQL 語句的執(zhí)行效果都支持基于語句的復(fù)制。例如調(diào)動(dòng)一個(gè)函數(shù) now() 來獲取系統(tǒng)時(shí)間,在不同的機(jī)器、時(shí)間上重放日志將得到不同的結(jié)果;

基于行的 binlog:

  • 優(yōu)點(diǎn):

    • 所有更改都可以復(fù)制,包括上面提到的 now() 函數(shù);
    • 以下類型的語句所需行鎖更少,可以實(shí)現(xiàn)更好的并發(fā)性:
  • 缺點(diǎn):

    • 數(shù)據(jù)量相比基于語句的 binlog 要大很多,在備份與恢復(fù)上性能較差;
    • 丟失了原有 SQL 更新語句,不利于復(fù)盤;

(2)數(shù)據(jù)引擎層的 redo log/undo log

MySQL 的 InnoDB 存儲(chǔ)引擎使用 redo log 以及 undo log,它們屬于 Physiological Logging,雖然很多人認(rèn)為其屬于物理日志。

MySQL InnoDB 的 redo log 可以分為三種類型:作用于Page,作用于 Space 以及提供額外信息的 Logic 類型。

這里以作用于 Page 的 redo log 的格式為例:

image.png

可見,MySQL 的 redo log 屬于 Physiological Logging:

  • 物理上,其使用 Page Number + Record Offset 來指定具體作用于哪一個(gè) page 上的一條記錄。
  • 邏輯上,使用 Field Number(Field編號(hào))來說明更新操作作用于哪些字段;

3.2 Redis

Redis 是一個(gè)內(nèi)存型 key-value NoSQL 數(shù)據(jù)庫的典型代表。

Redis 基于 AOF(Append Only File)提供持久化機(jī)制[7]。

AOF 中的每一條日志代表 Redis 節(jié)點(diǎn)接收到的一條寫操作,其格式為 Redis 命令格式,因此 AOF 屬于邏輯日志。

Redis 基于內(nèi)存快照(RDB)+check point + AOF 的方式實(shí)現(xiàn)持久化。

3.3 Kafka

在關(guān)系型數(shù)據(jù)庫看來,日志不是數(shù)據(jù)本身,例如對(duì)于 MySQL 的 InnoDB 存儲(chǔ)引擎來說,數(shù)據(jù)本身是存儲(chǔ)于磁盤上的 B+Tree 樹,日志是用于確保單機(jī)事務(wù)以及分布式事務(wù)的一種手段。換言之,關(guān)系型數(shù)據(jù)庫提供的讀/查詢 API 不是直接讀日志,而是直接讀 B+Tree。

但是對(duì)于 Kakfa 而言,日志本身就是數(shù)據(jù)本身。因此就沒有必要將這類數(shù)據(jù)庫分為邏輯日志與物理日志。Kakfa 的日志一方面服務(wù)于單機(jī)事務(wù)與分布式事務(wù),另一方面服務(wù)于消息的讀/寫 API。

根據(jù)[8],我們可知,Kakfa 消息包括如下重要字段:

image.png

可見,Kafka 在 message-logging 中的一條消息并不是用于描述更新,其就是數(shù)據(jù)本身。

總之,當(dāng)日志本身就是數(shù)據(jù)而不是描述更新操作時(shí),不需要將日志區(qū)分為邏輯日志與物理日志。

4. 總結(jié)

4.1 概述

(1)物理日志

格式:記錄在某個(gè)頁面的某個(gè)偏移量初修改了幾個(gè)字節(jié)的值,具體修改的內(nèi)容
優(yōu)點(diǎn):

  1. 日志是冪等的,重復(fù)執(zhí)行改日志不會(huì)導(dǎo)致數(shù)據(jù)發(fā)生不一致的問題;
  2. 可用于實(shí)現(xiàn)宕機(jī)前后事務(wù)并發(fā)控制的一致性。物理日志本身就是存儲(chǔ)就是基于不可分隔的更新操作,因此其存儲(chǔ)先后順序就代表了執(zhí)行器的調(diào)度順序。而且由于很容易判斷兩個(gè) page 是否是同一個(gè) page,如果不是,完全可以安全并行地并行執(zhí)行。
  3. 日志重放效率高
    缺點(diǎn):日志量大;

(2)邏輯日志

格式:記錄對(duì)于表的操作,類似update語句

優(yōu)點(diǎn):日志量??;
缺點(diǎn):

  1. 恢復(fù)時(shí)無法保證冪等性;
  2. 難以保證宕機(jī)前后事務(wù)并發(fā)控制的一致性。,邏輯日志很難實(shí)現(xiàn)一致的事務(wù)并發(fā)控制。由于邏輯日志難以攜帶并發(fā)執(zhí)行順序的信息,當(dāng)同時(shí)有多個(gè)事務(wù)產(chǎn)生更新操作時(shí),數(shù)據(jù)庫內(nèi)部會(huì)將這些操作調(diào)度為串行化序列執(zhí)行,需要機(jī)制來保障每次回放操作的執(zhí)行順序與調(diào)度產(chǎn)生的順序一致。
  3. 日志重放效率低;

(3)物理邏輯日志

格式:對(duì)應(yīng)頁是物理的,頁內(nèi)部操作是邏輯的。即根據(jù)物理頁進(jìn)行日志記錄,根據(jù)不同的邏輯操作進(jìn)行日志寫入。

需要注意的:日志不是冪等性;

4.2 舉例

來源地址:頁斷裂(partial write)與doublewrite技術(shù)

比如:innodb表T(c1,c2, key key_c1(c1)),插入記錄row1(1,’abc’)

邏輯日志:

<insert OP, T, 1,’abc’>

邏輯物理日志:

因?yàn)楸鞹含有索引key_c1, 一次插入操作至少涉及兩次B樹操作(我感覺是二級(jí)索引也維護(hù)了一個(gè)B+),二次B樹必然涉及至少兩個(gè)物理頁面,因此至少有兩條日志:

<insert OP, page_no_1, log_body>

<insert OP, page_no_2, log_body>

物理日志:
由于一次INSERT操作,物理上來說要修改頁頭信息(如,頁內(nèi)的記錄數(shù)要加1),要修改相鄰記錄里的鏈表指針,要修改Slot屬性等,因此對(duì)應(yīng)邏輯物理日志的每一條日志,都會(huì)有N條物理日志產(chǎn)生。

< group_id,file_id,page_no,offset1, value1>

< group_id,file_id,page_no,offset2, value2>

……

< group_id,file_id,page_no,offsetN, valueN>

因此對(duì)于上述一個(gè)INSERT操作,會(huì)產(chǎn)生一條邏輯日志,二條邏輯物理日志,2*N條物理日志。從上面簡(jiǎn)單的分析可以看出,邏輯日志的日志量最小,而物理日志的日志量最大;物理日志是純物理的;而邏輯物理日志則頁間物理,頁內(nèi)邏輯,所謂physical-to-a-page, logical-within-a-page。

REFERENCE

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容