通過 mysqlbinlog 和 grep 命令定位binlog文件中指定操作


1.binlog日志基本知識

MySQL的二進制日志binlog可以說是MySQL最重要的日志,它記錄了所有的DDL和DML語句(除了數據查詢語句select),以事件形式記錄,還包含語句所執行的消耗的時間。

binlog有三種格式:Statement、Row以及Mixed。分別是:基於SQL語句的復制(statement-based replication,SBR)、 基於行的復制(row-based replication,RBR)和混合模式復制(mixed-based replication,MBR)。

 

格式 說明 優點 缺點
Statement模式 每一條會修改數據的sql語句都會記錄到binlog中。 不需要記錄每一行的變化,減少了binlog日志量,節約了IO,提高性能。 缺點是在某些情況下會導致master-slave中的數據不一致(如sleep()函數,last_insert_id(),以及user-defined functions(udf)等會出現問題)。
Row模式

不記錄每條sql語句的上下文信息,僅需記錄哪條數據被修改了,修改成什么樣了。

而且不會出現某些特定情況下的存儲過程、或function、或trigger的調用和觸發無法被正確復制的問題。

新版本的MySQL中對row level模式也被做了優化,並不是所有的修改都會以row level來記錄,像遇到表結構變更的時候就會以statement模式來記錄,如果sql語句確實就是update或者delete等修改數據的語句,那么會記錄所有行的變更。

任何情況都可以被復制,這對復制來說是最安全可靠的。多數情況下,從服務器上的表如果有主鍵的話,復制就會快了很多。
復制以下幾種語句時的行鎖更少:(1)INSERT ... SELECT;(2)包含 AUTO_INCREMENT 字段的 INSERT;(3)沒有附帶條件或者並沒有修改很多記錄的 UPDATE 或 DELETE 語句
執行INSERT,UPDATE,DELETE 語句時鎖更少。從服務器上采用多線程來執行復制成為可能。

binlog 大了很多
復雜的回滾時 binlog 中會包含大量的數據
主服務器上執行 UPDATE 語句時,所有發生變化的記錄都會寫到 binlog 中,這會導致頻繁發生 binlog 的並發寫問題
UDF 產生的大 BLOB 值會導致復制變慢
無法從 binlog 中看到都復制了寫什么語句
MIXED模式 實際上就是前兩種模式的結合,在mixed模式下,mysql會根據執行的每一條具體的sql語句來區分對待記錄的日志形式,也就是在statement和row之間選一種。 在Mixed模式下,一般的語句修改使用statment格式保存binlog,如一些函數,statement無法完成主從復制的操作,則采用row格式保存binlog,MySQL會根據執行的每一條具體的sql語句來區分對待記錄的日志形式,也就是在Statement和Row之間選擇一種。

2.查看Row模式和Statement模式的binlog

為了加深印象,下面我們看看兩者模式下的binlog到底長什么樣子。

2.1 測試案例

分別在Row模式 和 Statement模式 下執行以下語句。

創建一張表

        CREATE TABLE IF NOT EXISTS `tt` (
          `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
          `name` varchar(16) NOT NULL,
          `sex` enum('m','w') NOT NULL DEFAULT 'm',
          `age` tinyint(3) unsigned NOT NULL,
          `classid` char(6) DEFAULT NULL,
          PRIMARY KEY (`id`)
         ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

向表中insert 5筆數據

 insert into zyyshop.tt(`name`,`sex`,`age`,`classid`) values('yiyi','w',20,'cls1'),('xiaoer','m',22,'cls3'),('zhangsan','w',21,'cls5'),('lisi','m',20,'cls4'),('wangwu','w',26,'cls6');

用一條SQL語句修改前兩筆數據

update tt set name ='XXX' where id in (1,2);

在Row模式下形成的binlog文件為:mysql3306_bin.000011

在Statement模式下生成的binlog文件為:mysql3306_bin.000012。

2.2 用 show binlog events in 命令去查看分析2各個文件

查詢Row模式記錄如下:

 查詢Statement模式記錄如下:

 通過這個命令查看log,兩者差距不大。

官網知識:https://dev.mysql.com/doc/refman/8.0/en/show-binlog-events.html

2.3 通過mysqlbinlog命令解析

執行的命令分別如下

指定路徑/bin/mysqlbinlog  --no-defaults --base64-output=decode-rows -v 指定路徑/mysql_log/mysql3306_bin.000011
指定路徑/bin/mysqlbinlog  --no-defaults --base64-output=decode-rows -v 指定路徑/mysql_log/mysql3306_bin.000012

我們可以看到Row模式下的binlog記錄豐富的多,例如針對update的那條語句。

Row模式記錄如下:

Statement模式記錄如下:

 

 總結:通過 show binlog events in 命令,查看 Row模式下記錄 和 Statement模式下的記錄,兩者基本一致。通過 mysqlbinlog 可以查看binlog具體的信息。Row模式下的binlog記錄比 Statement模式下豐富的多。

3. 通過 mysqlbinlog 和 grep 命令定位binlog文件中指定操作

既然binlog文件中有詳細的操作信息,如果有人誤操作,我們是否可以快速定位到對應操作信息呢?

快速定位可以幫助我們找到當時具體的操作是什么,也可以找到POS(position)點,方便精准恢復。

例如,書接上回,我們發現表 tt 不在了,被人刪除了。ERROR 1146 (42S02): Table 'TestBinlog2.tt' doesn't exist。

那么我們就可以在binlog查找drop相關的操作,命令如下:

指定路徑/bin/mysqlbinlog  --no-defaults --base64-output=decode-rows -v 指定路徑/mysql_log/mysql3306_bin.000012 | grep drop

可惜沒有數據,這是什么情況呢?不應該啊!!!

會不會大小寫的問題?那么命令修改如下:

 指定路徑/bin/mysqlbinlog  --no-defaults --base64-output=decode-rows -v 指定路徑/mysql_log/mysql3306_bin.000012 | grep -i drop

找到了,但是信息不是很完整,我們可不可以找到,這條命令的更信息信息呢?例如,drop 前后各10條數據。

指定路徑/bin/mysqlbinlog  --no-defaults --base64-output=decode-rows -v 指定路徑/mysql_log/mysql3306_bin.000012 | grep -i  -A 10 -B 10  drop

這正是我們想要的,完美!

4. 其它知識補充

4.1 mysqlbinlog工具

此處主要講解用於查看binglog日志的部分參數,用於還原binlog的參數在此不細講。

mysqlbinlog工具參數說明【用於查看的部分】
參數 說明
-base64-output

inlog輸出語句的base64解碼 分為三類:
默認是值auto ,僅打印base64編碼的需要的信息,如row-based 事件和事件的描述信息。
never 僅適用於不是row-based的事件
decode-rows 配合--verbose選項一起使用解碼行事件到帶注釋的偽SQL語句

--verbose 重新構建偽SQL語句的行信息輸出, -v會增加列類型的注釋信息。
--database=name 列出數據庫的名稱(僅限binlog文件存儲在本地)

 

4.2 grep 命令

grep是一個強大的文本搜索工具命令,用於查找文件中符合指定格式的字符串,支持正則表達式。

grep命令常用參數說明
參數 說明
-A 除了顯示符合條件的那一行之外,並顯示該列之后的指定行的內容內容。
-B 除了顯示符合條件的那一行之外,並顯示該列之前的指定行的內容內容。
-c 計算符合結果的行數。
-i 忽略字符大小寫
-v 反向查找
-e 按指定字符串查找
-E 按指定字符串指定的正則查找
-n 在顯示符合條件的那一行前,標識出該行的行數標號。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM