MySQL的Redo Log跟Binlog

文章目錄

    • 概要
    • Redo Log日志
      • Redo Log的作用
      • Redo Log的寫入機制
    • Binlog日志
      • Binlog的作用
      • Binlog寫入機制
    • 兩段提交

概要

Redo Log和Binlog是MySQL日志系統中非常重要的兩種機制,也有很多相似之處,本文主要介紹兩者細節和區別。

Redo Log日志

Redo Log的作用

準備一張測試表

create table test_redo(id int primary key, c int);

假設現在要執行這樣一條sql

update test_redo set c = c + 1 where id = 1;

修改一條數據,首先是修改了Buffer Pool中該條數據所在的數據頁。假如說我們剛提交了事務,發生了某個故障,內存中的數據都失效了,就會導致所做的修改跟著丟失了。這是不能接受的。
如何避免這樣的情況發生?
一個簡單粗暴的做法是:在事務提交完成之前把該事務所修改的所有頁面都刷新到磁盤
這樣做有以下兩個問題:

  1. 刷新一個完整的數據也太浪費
    比如上面只修改了一個字段,就要刷新整個頁(16KB),InnoDB是以頁為單位進行IO的,很浪費
  2. 隨機IO速度很慢
    涉及到多個頁時,頁與頁之間在磁盤上可能是不連續的,隨機IO要比順序IO慢很多。

為了達到系統崩潰后,服務重啟也能恢復原來提交的事務修改的目的,同時避免出現上面提到的問題,Redo Log就是一種解決方案。

Redo Log,重做日志,其本質是記錄?下事務對數據庫做了哪些修改。

將第0號表空間的100號頁面的偏移量為1處的值更新為2

具體來說,當有一條記錄需要更新的時候,InnoDB 引擎就會先把記錄寫到 Redo Log里面,并更新內存,這個時候更新就算完成了。同時,InnoDB 引擎會在適當的時候,將這個操作記錄更新到磁盤里面。

這就是 MySQL 里經常說到的 WAL 技術,WAL 的全稱是 Write-Ahead Logging,它的關鍵點就是先寫日志,再寫磁盤。

通過事務執行過程中產生的redo日志刷新到磁盤的方式,跟前面提到的簡單粗暴的方式比較,有如下好處:

  • redo日志占用的空間非常少
  • redo日志是順序寫入磁盤的

有了 redo log,InnoDB 就可以保證即使數據庫發生異常重啟,之前提交的記錄都不會丟失,這個能力稱為crash-safe

Redo Log的寫入機制

日志文件
InnoDB 的 redo log 是固定大小的,比如可以配置為一組 4 個文件,每個文件的大小是 1GB,那么總共就可以記錄 4GB 的操作。從頭開始寫,寫到末尾就又回到開頭循環寫,如下面這個圖所示

在這里插入圖片描述
write pos 是當前記錄的位置,一邊寫一邊后移,寫到第 3 號文件末尾后就回到 0 號文件開頭。checkpoint 是當前要擦除的位置,也是往后推移并且循環的,擦除記錄前要把記錄更新到數據文件。

write pos 和 checkpoint 之間空著的部分,可以用來記錄新的操作。如果 write pos 追上 checkpoint,表示寫滿,這時候不能再執行新的更新,把 checkpoint 推進一下。

可通過以下查詢redo log文件的數量跟大小

show variables like '%innodb_log_file%';

在這里插入圖片描述
在服務器端可看到對應的文件
在這里插入圖片描述

redo log buffer

假如執行如下sql

begin;
insert into t1 ...
insert into t2 ...
commit;

這個事務要往兩個表中插入記錄,插入數據的過程中,還沒有執行 commit 的時候,就是是不能直接寫到 redo log 文件里的。這時候回顯記錄在redo log buffer
redo log buffer 就是一塊內存,用來先存 redo 日志。也就是說,在執行第一個 insert 的時候,數據的發生了修改,redo log buffer 也寫入了日志。但是,真正把日志寫到 redo log 文件(文件名是 ib_logfile+ 數字),是在執行 commit 語句的時候做的

單獨執行一個更新語句的時候,InnoDB 會自己啟動一個事務,在語句執行完成的時候提交。過程跟上面是一樣的。

redo log buffer是什么時候持久化到Redo Log中的呢?有如下3種策略,可通過innodb_flush_log_at_trx_commit進行配置。它有3種取值:

  1. 設置為 0 的時候,表示每次事務提交時都只是把 redo log 留在 redo log buffer 中,由后臺線程每隔1s執行一次刷盤操作 ;
  2. 設置為 1 的時候(默認值),表示每次事務提交時都將 redo log 直接持久化到磁盤;
  3. 設置為 2 的時候,表示每次事務提交時都只是把 redo log 寫到 OS cache,然后由后臺Master線程再每隔1秒執行OS
    cache -> flush cache to disk 的操作。

在這里插入圖片描述

一般建議選擇取值2,因為 MySQL 掛了數據沒有損失,整個服務器掛了才會損失1秒的事務提交數據。設置為1時最為安全,但是性能也是最差。

Binlog日志

Binlog的作用

Redo Log 是屬于InnoDB引擎所特有的日志,而MySQL Server層也有自己的日志,即 Binary log(二進制日志),簡稱Binlog。Binlog是記錄所有數據庫表結構變更以及表數據修改的二進制日志,不會記錄SELECT和SHOW這類操作。Binlog日志是以事件形式記錄,還包含語句所執行的消耗時間。

最開始 MySQL 里并沒有 InnoDB 引擎。MySQL 自帶的引擎是 MyISAM,但是 MyISAM 沒有 crash-safe 的能力,binlog 日志只能用于歸檔。而 InnoDB 是另一個公司以插件形式引入 MySQL 的,既然只依靠 binlog 是沒有 crash-safe 能力的,所以 InnoDB 使用另外一套日志系統——也就是 redo log 來實現 crash-safe 能力。

Binlog日志有以下兩個最重要的應用場景:

  1. 主從復制:在主庫中開啟Binlog功能,這樣主庫就可以把Binlog傳遞給從庫,從庫拿到Binlog后實現數據恢復達到主從數據一致性。
  2. 數據恢復:通過mysqlbinlog工具來恢復數據

Binlog日志文件記錄模式有STATEMENT、ROW和MIXED三種,具體含義如下。

  • ROW(row-based replication, RBR):日志中會記錄每一行數據被修改的情況,然后在slave端對相同的數據進行修改。
    優點:能清楚記錄每一個行數據的修改細節,能完全實現主從數據同步和數據的恢復。
    缺點:批量操作,會產生大量的日志,尤其是alter table會讓日志暴漲。

  • STATMENT(statement-based replication, SBR):每一條被修改數據的SQL都會記錄到master的Binlog中,slave在復制的時候SQL進程會解析成和原來master端執行過的相同的SQL再次執行。簡稱SQL語句復制。
    優點:日志量小,減少磁盤IO,提升存儲和恢復速度
    缺點:在某些情況下會導致主從數據不一致,比如last_insert_id()、now()等函數。

  • MIXED(mixed-based replication, MBR):以上兩種模式的混合使用,一般會使用STATEMENT模式保存binlog,對于STATEMENT模式無法復制的操作使用ROW模式保存binlog,MySQL會根據執行的SQL語句選擇寫入模式。

可通過以下sql查看Binlog信息

show variables like '%log_bin%';
show variables like '%binlog%';

格式查看

mysql> show variables like 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+
1 row in set (0.00 sec)

Biglog文件格式

MySQL的binlog文件中記錄的是對數據庫的各種修改操作,用來表示修改操作的數據結構是Log event。不同的修改操作對應的不同的log event。比較常用的log event有:Query event、Row event、Xid event等。binlog文件的內容就是各種Log event的集合。
Binlog文件中Log event結構如下圖所示:

在這里插入圖片描述

查看當前的二進制日志文件列表及大小。指令如下:

mysql> SHOW BINARY LOGS;
+---------------+-----------+-----------+
| Log_name      | File_size | Encrypted |
+---------------+-----------+-----------+
| binlog.000004 |    712684 | No        |
| binlog.000005 |       179 | No        |
| binlog.000006 |       179 | No        |
| binlog.000007 |   3412930 | No        |
+---------------+-----------+-----------+
4 rows in set (0.00 sec)

查看具體的文件
語法:show binlog events [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count];

-- 文件內容太多了 這里限制了從 pos 156開始查看 限制5條
mysql> show binlog events in 'binlog.000004' from 156 limit 5 \G;
*************************** 1. row ***************************Log_name: binlog.000004Pos: 156Event_type: Anonymous_GtidServer_id: 1
End_log_pos: 235Info: SET @@SESSION.GTID_NEXT= 'ANONYMOUS'
*************************** 2. row ***************************Log_name: binlog.000004Pos: 235Event_type: QueryServer_id: 1
End_log_pos: 317Info: BEGIN
*************************** 3. row ***************************Log_name: binlog.000004Pos: 317Event_type: Table_mapServer_id: 1
End_log_pos: 402Info: table_id: 92 (small_admin.QRTZ_CRON_TRIGGERS)
*************************** 4. row ***************************Log_name: binlog.000004Pos: 402Event_type: Delete_rowsServer_id: 1
End_log_pos: 502Info: table_id: 92 flags: STMT_END_F
*************************** 5. row ***************************Log_name: binlog.000004Pos: 502Event_type: XidServer_id: 1
End_log_pos: 533Info: COMMIT /* xid=392 */
5 rows in set (0.00 sec)

binlog是二進制文件,無法直接查看,借助mysqlbinlog命令工具了,可以查看其中的內容

# mysqlbinlog使用語法 
[root@node1 data]# mysqlbinlog --no-defaults --help

查看文件

mysqlbinlog --no-defaults --base64-output=decode-rows -vv binlog.000004 |tail -100

Binlog寫入機制

事務執行過程中,先把日志寫到 binlog cache,事務提交的時候,再把 binlog cache 寫到 binlog 文件中。

一個事務的 binlog 是不能被拆開的,因此不論這個事務多大,也要確保一次性寫入。這就涉及到了 binlog cache 的保存問題。

系統給 binlog cache 分配了一片內存,每個線程一個,參數 binlog_cache_size 用于控制單個線程內 binlog cache 所占內存的大小。如果超過了這個參數規定的大小,就要暫存到磁盤。

事務提交的時候,執行器把 binlog cache 里的完整事務寫入到 binlog 中,并清空 binlog cache。

在這里插入圖片描述

write 和 fsync 的時機,是由參數 sync_binlog 控制的:

  1. sync_binlog=0 的時候,表示每次提交事務都只 write,不 fsync;
  2. sync_binlog=1 的時候,表示每次提交事務都會執行 fsync;
  3. sync_binlog=N(N>1) 的時候,表示每次提交事務都 write,但累積 N 個事務后才 fsync。

因此,在出現 IO 瓶頸的場景里,將 sync_binlog 設置成一個比較大的值,可以提升性能。在實際的業務場景中,考慮到丟失日志量的可控性,一般不建議將這個參數設成 0,比較常見的是將其設置為 100~1000 中的某個數值。

但是,將 sync_binlog 設置為 N,對應的風險是:如果主機發生異常重啟,會丟失最近 N 個事務的 binlog 日志。

兩段提交

結合redo log 跟bin log ,執行update test_redo set c = c + 1 where id = 1 這條語句的大致過程如下:

  1. 執行器先找引擎取 id=1 這一行。id 是主鍵,引擎直接用樹搜索找到這一行。如果 id=1 這一行所在的數據頁本來就在內存中,就直接返回給執行器;否則,需要先從磁盤讀入內存,然后再返回。
  2. 執行器拿到引擎給的行數據,把c的值加 1,比如原來是 N,現在就是 N+1,得到新的一行數據,再調用引擎接口寫入這行新數據。
  3. 引擎將這行新數據更新到內存中,同時將這個更新操作記錄到 redo log 里面,此時 redo log 處于 prepare 狀態。然后告知執行器執行完成了,隨時可以提交事務。
  4. 執行器生成這個操作的 binlog,并把 binlog 寫入磁盤。
  5. 執行器調用引擎的提交事務接口,引擎把剛剛寫入的 redo log 改成提交(commit)狀態,更新完成。

在這里插入圖片描述

Q:為什么需要兩段提交?

A:用上面的更新語句作為例子
如果不用兩階段提交,要么就是先寫完 redo log 再寫 binlog,或者是先寫binlog再寫redo log,下面對這兩種情況討論

  1. 先寫 redo log 后寫 binlog。假設在 redo log 寫完,binlog 還沒有寫完時MySQL 進程異常重啟。由于redo log 寫完后,系統即使崩潰,仍然能夠把數據恢復回來,所以恢復后這一行 c 的值是 1。 但是由于 binlog 沒寫完, binlog 里面就沒有記錄這條語句。因此,之后備份日志的時候用這個 binlog 來恢復臨時庫的話,就會與原庫的值有差異。
  2. 先寫 binlog 后寫 redo log。如果在 binlog 寫完之后 crash,由于 redo log 還沒寫,崩潰恢復以后這個事務無效,所以這一行 c 的值是 0。但是 binlog 里面已經記錄了“把 c 從 0 改成 1”這個日志。在之后用 binlog 來恢復的時候就會與原庫有差異。

Q:上圖中,如果在時刻A,也就是寫入 redo log 處于 prepare 階段之后、寫 binlog 之前,發生了奔潰呢?
A:由于此時 binlog 還沒寫,redo log 也還沒提交,所以崩潰恢復的時候,這個事務會回滾。這時候,binlog 還沒寫,所以也不會傳到備庫

Q:如果在B時刻,也就是 binlog 寫完,redo log 還沒 commit 前發生 crash,那崩潰恢復的時候 MySQL 會怎么處理?
A:崩潰恢復時的判斷如下

  1. 如果 redo log 里面的事務是完整的,也就是已經有了 commit 標識,則直接提交;
  2. 如果 redo log 里面的事務只有完整的 prepare,則判斷對應的事務 binlog 是否存在并完整: a. 如果是,則提交事務; b. 否則,回滾事務。

Q:redo log 和 binlog 是怎么關聯起來的?
A:它們有一個共同的數據字段,叫 XID。崩潰恢復的時候,會按順序掃描 redo log:
如果碰到既有 prepare、又有 commit 的 redo log,就直接提交;
如果碰到只有 parepare、而沒有 commit 的 redo log,就拿著 XID 去 binlog 找對應的事務。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/165645.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/165645.shtml
英文地址,請注明出處:http://en.pswp.cn/news/165645.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Docker+ Jenkins+Maven+git自動化部署

環境:Centos7 JDK1.8 Maven3.3.9 Git 2.40 Docker 20.10.17 準備工作: 安裝Docker Centos7默認的yum安裝的docker是1.13,版本太低,很多鏡像都要Docker版本要求,升級Docker版本。 卸載已安裝Docker: yum …

你知道如何實現游戲中的透視效果嗎?

引言 游戲中的透視效果可以合理運用CtrlCV實現。 不知道大家有沒有這樣一段經歷:在做Cocos項目時需要一些特定的Shader去做一些特定的效果,例如透視、高光、濾鏡等等,想自己寫吧,不怎么會啊,網上又找不到&#xff0c…

27 - 如何使用設計模式優化并發編程?

在我們使用多線程編程時,很多時候需要根據業務場景設計一套業務功能。其實,在多線程編程中,本身就存在很多成熟的功能設計模式,學好它們,用好它們,那就是如虎添翼了。今天我就帶你了解幾種并發編程中常用的…

redis-cluster集群(目的:高可用)

1、特點 集群由多個node節點組成,redis數據分布在這些節點中,在集群中分為主節點和從節點,一個主對應一個從,所有組的主從形成一個集群,每組的數據是獨立的,并且集群自帶哨兵模式 2、工作原理 集群模式中…

【ZedBoard學習實例1】 VGA顯示彩條

ZedBoard學習實例1 VGA顯示彩條 ZedBoard學習實例1 VGA顯示彩條參考文章改進 ZedBoard學習實例1 VGA顯示彩條 參考文章 彩條控制verilog代碼 主體參考了該文章的代碼,文中還介紹了相關的電路圖,還有ZedBoard的手冊內容。19201080分辨率顯示器的參數 針…

重生之我是一名程序員 37 ——C語言中的棧溢出問題

哈嘍啊大家晚上好! 今天呢給大家帶來一個燒腦的知識——C語言中的棧溢出問題。那什么是棧溢出呢?棧溢出指的是當程序在執行函數調用時,為了保護函數的局部變量和返回地址,將這些數據存儲在棧中。如果函數在函數調用時使用了過多的…

Sentinel核心類解讀:Entry

默認情況下,Sentinel會將controller中的方法作為被保護資源,Sentinel中的資源用Entry來表示。 Sentinel中Entry可以理解為每次進入資源的一個憑證,如果調用SphO.entry()或者SphU.entry()能獲取Entry對象,代表獲取了憑證&#xff…

安卓手機便簽APP用哪個,手機上好用的便簽APP是什么

在日常生活及工作方面,總是有許多做不完的事情需要大家來處理,當多項任務堆疊交叉在一起時,很容易漏掉一些項目,這時候大家會借助經常攜帶的手機來記錄容易忘記的事情,如手機上的鬧鐘、定時提醒軟件都可以用來記錄待辦…

2023亞太杯數學建模A題思路分析 - 采果機器人的圖像識別技術

1 賽題 問題A 采果機器人的圖像識別技術 中國是世界上最大的蘋果生產國,年產量約為3500萬噸。與此同時,中國也是世 界上最大的蘋果出口國,全球每兩個蘋果中就有一個,全球超過六分之一的蘋果出口 自中國。中國提出了一帶一路倡議…

JDK11新特性

目錄 一、JShell 二、Dynamic Class-File Constants類文件新添的一種結構 三、局部變量類型推斷(var ”關鍵字”) 四、新加的一些實用API 1. 新的本機不可修改集合API 2. Stream 加強 3. String 加強 4. Optional 加強 5. 改進的文件API 五、移…

canvas

Canvas 是 Android 中用于繪制圖形的重要類,它提供了許多用于繪制的常用方法。以下是一些常用的 Canvas 方法: 繪制顏色和背景: drawColor(int color): 用指定顏色填充整個畫布。drawRGB(int r, int g, int b): 用 RGB 值指定顏色填充整個畫布…

進程池,線程池與跨進程數據共享爬取某岸網圖片

看教程的時候看到一個,生產者跟消費者的概念比較有意思,但是給的代碼有問題無法正常運行,于是我就搗鼓了一下。 基本概念就是: 生產者: 一個進程獲取網頁沒頁的圖片連接(主進程…

Django框架之中間件

目錄 一、引入 二、Django中間件介紹 【1】什么是Django中間件 【2】Django中間件的作用 【3】示例 三、Django請求生命周期流程圖 四、Django中間件是Django的門戶 五、Django中間件詳解 六、中間件必須要掌握的兩個方法 (1) process_request (2) process_respon…

Redis集群環境各節點無法互相發現與Hash槽分配異常 CLUSTERDOWN Hash slot not served的解決方式

原創/朱季謙 在搭建Redis5.x版本的集群環境曾出現各節點無法互相發現與Hash槽分配異常 CLUSTERDOWN Hash slot not served的情況,故而把解決方式記錄下來。 在以下三臺虛擬機機器搭建Redis集群—— 192.168.200.160192.168.200.161192.168.200.162啟動三臺Redis集…

芯知識 | MP3語音芯片IC的優勢特征及其在現代科技應用中的價值

隨著科技的飛速發展,MP3語音芯片作為一種高度集成的音頻處理解決方案,在現代電子產品中發揮著越來越重要的作用。本文將分析MP3語音芯片的優勢特征,并探討其在各個領域的應用價值。 一、MP3語音芯片的優勢特征 MP3語音芯片具有多種顯著的優…

CC++輸入輸出流介紹

介紹 C中的輸入輸出流主要包括標準輸入輸出流、文件輸入輸出流和內存數據流。 標準輸入輸出流可以通過使用cin和cout進行數據的讀取和輸出文件輸入輸出流可以通過使用ifstream和ofstream對文件進行讀寫操作內存數據流可以通過使用stringstream對字符串進行讀寫操作 應用舉例…

服務器租用收費標準是什么?

服務器在企業轉型中或者是互聯網企業中起著舉足輕重的作用,服務器有強大的存儲能力和計算能力,能夠幫助企業存儲大量信息,完成日常工作,服務器租用就是通過正規的IDC服務器商家那里獲取服務器資源,根據企業自身需求選擇…

Python爬蟲-獲取汽車之家新車優惠價

前言 本文是該專欄的第10篇,后面會持續分享python爬蟲案例干貨,記得關注。 本文以汽車之家新車優惠價為例,獲取各車型的優惠價,示例圖如下: 地址:aHR0cHM6Ly9idXkuYXV0b2hvbWUuY29tLmNuLzAvMC8wLzQyMDAwMC80MjAxMDAvMC0wLTAtMS5odG1sI3B2YXJlYWlkPTIxMTMxOTU= 需求:獲…

OpenStack云計算平臺

目錄 一、OpenStack 1、簡介 2、硬件需求 3、網絡 二、環境搭建 1、安全 2、主機網絡 3、網絡時間協議(NTP) 4、OpenStack包 5、SQL數據庫 6、消息隊列 7、Memcached 一、OpenStack 1、簡介 官網:https://docs.openstack.org/2023.2/ OpenStack系統由…

Zynq-7000系列FPGA使用 Video Processing Subsystem 實現圖像縮放,提供工程源碼和技術支持

目錄 1、前言免責聲明 2、相關方案推薦FPGA圖像處理方案FPGA圖像縮放方案自己寫的HLS圖像縮放方案 3、設計思路詳解Video Processing Subsystem 介紹 4、工程代碼詳解PL 端 FPGA 邏輯設計PS 端 SDK 軟件設計 5、工程移植說明vivado版本不一致處理FPGA型號不一致處理其他注意事項…