<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          binlog那些事兒(二)

          共 7751字,需瀏覽 16分鐘

           ·

          2021-12-31 17:14


          讀完上一篇文章:binlog那些事兒,我們應(yīng)該知道:

          ?binlog日志用于主從復(fù)制以及數(shù)據(jù)恢復(fù)。

          ?啟動選項(xiàng)--log-bin[=basename]可以控制MySQL服務(wù)器是否生成binlog,并且控制binlog日志文件所在路徑以及文件名稱。

          ?為了記錄binlog,MySQL服務(wù)器在文件系統(tǒng)上創(chuàng)建了一系列存儲真實(shí)binlog數(shù)據(jù)的文件(這些文件都以數(shù)字編號),以及binlog索引文件。

          ?binlog日志文件中記載了數(shù)據(jù)庫發(fā)生更改的若干事件。

          ?使用SHOW BINLOG EVENTS語句可以查看某個binlog日志文件中存儲的各種事件。

          ?mysqlbinlog實(shí)用工具可以用文本形式查看某個binlog日志文件所記載各種事件。

          掌握了上述內(nèi)容之后,我們可以繼續(xù)展開了。

          binlog日志版本

          binlog是自MySQL 3.23.14版本開始誕生的,到現(xiàn)在為止,共經(jīng)歷了4個版本:

          ?v1?v2?v3?v4

          其中的v4版本從MySQL 5.0就開始使用,直到今天。

          所以本文著重介紹v4版本的binlog格式,其他版本就不關(guān)注了。

          binlog日志文件結(jié)構(gòu)概覽

          廢話少說,先看一下一個binlog日志文件的基本格式:

          b279ba71bf5009d3d350023bf494b2c7.webp

          從上圖中可以看出:

          ?每個binlog日志文件的前4個字節(jié)是固定的,即:0xfe626963

          小貼士:

          0xfe626963中的0x626963的ascii碼是'bin',0xfe626963也被稱作魔數(shù)(magic number),如果一個文件不以0xfe626963開頭,那這個文件肯定不算是一個binlog日志。很多軟件都會在磁盤文件的某個地方添加一個類似的魔數(shù)來表明該文件是本軟件處理的文件格式,比方說Intel處理器的BIOS會將磁盤上的第一個扇區(qū)加載到內(nèi)存中,這個扇區(qū)的最后兩個字節(jié)必須為魔數(shù)0x55aa,Java的class文件字節(jié)碼的開頭四個字節(jié)為魔數(shù)0xCAFEBABE。

          ?每個binlog日志文件都是由若干事件構(gòu)成的。

          ?每個binlog日志文件所存儲的第1個事件都是一個稱作格式描述事件(format description event)的特殊事件,我們稍后詳細(xì)嘮叨一下這個特殊事件。

          其中,每個事件都可以被分成event headerevent data兩個部分,我們以上圖的事件2為例展示一下:

          b2c5a7cf9400ee57ab44078e5d572548.webp

          其中:

          ?event header部分描述了該事件是什么類型、什么時候生成的、由哪個服務(wù)器生成的等信息。

          ?event data部分描述了該事件所特有的一些信息,比方說在插入一條記錄時,需要將這條記錄的內(nèi)容記錄在event data中。

          event header結(jié)構(gòu)

          每個事件都會包括一個通用的event header,我們看一下這個event header的結(jié)構(gòu):

          a77f25cddec21bca26cd30d9ce2c30d6.webp

          event header中包含了如下幾部分內(nèi)容:

          ?timestamp(4字節(jié)):產(chǎn)生該事件時的時間戳。?typecode(1字節(jié)):該事件的類型,事件的類型在枚舉結(jié)構(gòu)Log_event_type中列舉出來(上一篇文章或者本文后續(xù)部分都有提到這個結(jié)構(gòu))。比方說格式描述事件的typecode就是15。?server_id(4字節(jié)):產(chǎn)生該事件的主機(jī)的server_id。?event_length(4字節(jié)):該事件總大小(包括event header + event data)。?next_position(4字節(jié)):下一個事件的位置。?flags(2字節(jié)):該事件的一些附加屬性(稱作flags)。?extra_headers(不確定大小):目前這個字段尚未使用(也就是占用的大小為0),可能在將來的版本中使用,大家目前忽略這個字段就好了。

          event data

          event data由2部分組成,分別是:

          ?固定大小部分?可變大小部分

          c611c660499a4a5d5771ad7c84031bd6.webp

          不過并不是所有事件都有這兩個部分,有的事件可以僅有其中的一個部分或者兩個部分都沒有

          上一篇文章中嘮叨過,MySQL中支持幾十種binlog事件,不同事件具有不同的event data部分。

          我們先看一下binlog的事件類型有多少(上一篇文章中引用MySQL internal文檔中的內(nèi)容,有點(diǎn)陳舊,所以這次直接從MySQL5.7.22的源碼中獲取Log_event_type結(jié)構(gòu)):

          enum Log_event_type{  /**    Every time you update this enum (when you add a type), you have to    fix Format_description_event::Format_description_event().  */  UNKNOWN_EVENT= 0,  START_EVENT_V3= 1,  QUERY_EVENT= 2,  STOP_EVENT= 3,  ROTATE_EVENT= 4,  INTVAR_EVENT= 5,  LOAD_EVENT= 6,  SLAVE_EVENT= 7,  CREATE_FILE_EVENT= 8,  APPEND_BLOCK_EVENT= 9,  EXEC_LOAD_EVENT= 10,  DELETE_FILE_EVENT= 11,  /**    NEW_LOAD_EVENT is like LOAD_EVENT except that it has a longer    sql_ex, allowing multibyte TERMINATED BY etc; both types share the    same class (Load_event)  */  NEW_LOAD_EVENT= 12,  RAND_EVENT= 13,  USER_VAR_EVENT= 14,  FORMAT_DESCRIPTION_EVENT= 15,  XID_EVENT= 16,  BEGIN_LOAD_QUERY_EVENT= 17,  EXECUTE_LOAD_QUERY_EVENT= 18,
          TABLE_MAP_EVENT = 19,
          /** The PRE_GA event numbers were used for 5.1.0 to 5.1.15 and are therefore obsolete. */ PRE_GA_WRITE_ROWS_EVENT = 20, PRE_GA_UPDATE_ROWS_EVENT = 21, PRE_GA_DELETE_ROWS_EVENT = 22,
          /** The V1 event numbers are used from 5.1.16 until mysql-trunk-xx */ WRITE_ROWS_EVENT_V1 = 23, UPDATE_ROWS_EVENT_V1 = 24, DELETE_ROWS_EVENT_V1 = 25,
          /** Something out of the ordinary happened on the master */ INCIDENT_EVENT= 26,
          /** Heartbeat event to be send by master at its idle time to ensure master's online status to slave */ HEARTBEAT_LOG_EVENT= 27,
          /** In some situations, it is necessary to send over ignorable data to the slave: data that a slave can handle in case there is code for handling it, but which can be ignored if it is not recognized. */ IGNORABLE_LOG_EVENT= 28, ROWS_QUERY_LOG_EVENT= 29,
          /** Version 2 of the Row events */ WRITE_ROWS_EVENT = 30, UPDATE_ROWS_EVENT = 31, DELETE_ROWS_EVENT = 32,
          GTID_LOG_EVENT= 33, ANONYMOUS_GTID_LOG_EVENT= 34,
          PREVIOUS_GTIDS_LOG_EVENT= 35,
          TRANSACTION_CONTEXT_EVENT= 36,
          VIEW_CHANGE_EVENT= 37,
          /* Prepared XA transaction terminal event similar to Xid */ XA_PREPARE_LOG_EVENT= 38, /** Add new events here - right above this comment! Existing events (except ENUM_END_EVENT) should never change their numbers */ ENUM_END_EVENT /* end marker */};

          可見在MySQL 5.7.22這個版本中,共支持38種不同的binlog事件類型。把每一種事件格式都嘮叨清楚要花費(fèi)很多篇幅,并且沒有多大的必要,我們下邊只舉一個具體的例子進(jìn)行描述。

          舉一個具體的例子——格式描述事件

          每個binlog日志文件都以格式描述事件作為第一個事件,它對應(yīng)的Log_event_type就是FORMAT_DESCRIPTION_EVENT。我們看一下這種事件的結(jié)構(gòu):

          adfb1560cff1b7d1cfbbb3fcc277c59e.webp

          從圖中我們可以知道,格式描述事件共占用119字節(jié),是由event header和event data兩部分構(gòu)成的,其中event header是各個事件都有的部分,我們上邊詳細(xì)嘮叨過event header中各個字段的含義,這里就不贅述了。另外,在event data部分,格式描述事件的event data中只有固定長度部分,沒有可變長度部分,其中的各個字段含義如下:

          ?binlog_version:使用的binlog版本。?server_version:產(chǎn)生此事件的MySQL服務(wù)器的版本。?create_timestamp:產(chǎn)生此事件時的時間戳,該字段的值和event header中timestamp中的值一樣。?header_length:此事件的event header占用的存儲空間大小。?post-header length:使用1個字節(jié)來表示每個事件的event data部分占用的存儲空間大小(不包括校驗(yàn)和相關(guān)字段),當(dāng)前我使用的MySQL版本為5.7.22,共包含38種不同的事件,post-header length字段就占用了38個字節(jié)。?checksum_alg:表示計(jì)算事件校驗(yàn)和的算法(該字段為1時表示采用CRC32算法)。?checksum:表示本事件的校驗(yàn)和。

          嘮叨了很多,大家真正打開一個binlog日志文件來看一下:

          魔數(shù):      FE62696E 
          timestamp: 8AB5A861 typecode: 0F server_id: 03000000 event_length: 77000000 next_postion: 7B000000 flags: 0000 binlog_version: 0400 server_version: 352E37 2E32312D 6C6F6700 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000000 create_timestamp: 8AB5A861 header_length: 13 post-header length(共38種): 380D0008 00120004 04040412 00005F00 041A0800 00000808 08020000 000A0A0A 2A2A0012 3400checksum_alg: 01 checksum:????? 5B7108A3

          ?

          小貼士:

          其他事件的event data部分大家可以參考一下MySQL internal文檔。另外,也可以使用mysqlbinlog,配合--hexdump啟動選項(xiàng)來直接分析binlog的二進(jìn)制格式。

          基于語句(Statement)和基于行(Row)的binlog

          同一條SQL語句,隨著啟動選項(xiàng)binlog-format的不同,可能生成不同類型的binlog事件:

          ?當(dāng)以啟動選項(xiàng)--binlog-format=STATEMENT啟動MySQL服務(wù)器時,生成的binlog稱作基于語句的日志。此時只會將一條SQL語句將會被完整的記錄到binlog中,而不管該語句影響了多少記錄。

          ?當(dāng)以啟動選項(xiàng)--binlog-format=ROW啟動MySQL服務(wù)器時,生成的binlog稱作基于行的日志。此時會將該語句所改動的記錄的全部信息都記錄上。

          ?當(dāng)以啟動選項(xiàng)--binlog-format=MIXED啟動MySQL服務(wù)器時,生成的binlog稱作基于行的日志。此時在通常情況下采用基于語句的日志,在某些特殊情況下會自動轉(zhuǎn)為基于行的日志(這些具體情況請參考:https://dev.mysql.com/doc/refman/8.0/en/binary-log-mixed.html)。

          小貼士:

          我們也可以通過修改會話級別的binlog_format系統(tǒng)變量的形式來修改只針對本客戶端執(zhí)行語句生成的binlog日志的格式。

          基于語句的binlog

          假如服務(wù)器啟動時添加了--binlog-format=STATEMENT啟動選項(xiàng),我們執(zhí)行如下語句:

          UPDATE s1 SET common_field = 'xx' WHERE id > 9990;

          然后使用mysqlbinlog實(shí)用工具查看一下相應(yīng)的binlog內(nèi)容:

          mysqlbinlog --verbose xiaohaizi-bin.000007...這里省略了很多內(nèi)容# at 308#211207 21:00:27 server id 3  end_log_pos 440 CRC32 0x713f80ae  Query thread_id=2 exec_time=0 error_code=0use `xiaohaizi`/*!*/;SET TIMESTAMP=1638882027/*!*/;update s1 set common_field= 'xx' where id > 9990/*!*/;...這里省略了很多內(nèi)容

          ?

          可見,基于語句的binlog只將更新語句是什么記錄下來了。

          基于行的binlog

          假如服務(wù)器啟動時添加了--binlog-format=ROW啟動選項(xiàng),我們執(zhí)行如下語句:

          UPDATE s1 SET common_field = 'xxx' WHERE id > 9990;

          然后使用mysqlbinlog實(shí)用工具查看一下相應(yīng)的binlog內(nèi)容:

          mysqlbinlog --verbose xiaohaizi-bin.000008...這里省略了很多內(nèi)容### UPDATE `xiaohaizi`.`s1`### WHERE###   @1=9991###   @2='7cgwfh14w6nql61pvult6ok0ccwe'###   @3='799105223'###   @4='c'###   @5='gjjiwstjysv1lgx'###   @6='zg1hsvqrtyw2pgxgg'###   @7='y244x02'###   @8='xx'### SET###   @1=9991###   @2='7cgwfh14w6nql61pvult6ok0ccwe'###   @3='799105223'###   @4='c'###   @5='gjjiwstjysv1lgx'###   @6='zg1hsvqrtyw2pgxgg'###   @7='y244x02'###   @8='xxx'### UPDATE `xiaohaizi`.`s1`### WHERE###   @1=9992###   @2='2sfq3oftc'###   @3='815047282'###   @4='ub'###   @5='73hw14kbaaoa'###   @6='fxnqzef3rrpc7qzxcjsvt14nypep4rqi'###   @7='10vapb6'###   @8='xx'### SET###   @1=9992###   @2='2sfq3oftc'###   @3='815047282'###   @4='ub'###   @5='73hw14kbaaoa'###   @6='fxnqzef3rrpc7qzxcjsvt14nypep4rqi'###   @7='10vapb6'###   @8='xxx'...這里省略了很多內(nèi)容

          ?

          可見,基于行的binlog將更新語句執(zhí)行過程中每一條記錄更新前后的值都記錄下來了。

          基于語句的binlog的問題

          在有主從復(fù)制的場景中,使用基于語句的日志可能會造成主服務(wù)器和從服務(wù)器維護(hù)的數(shù)據(jù)不一致的情況。

          比方說我們有一個表t:

          CREATE TABLE t (    id INT UNSIGNED NOT NULL AUTO_INCREMENT,    c VARCHAR(100),    PRIMARY KEY(ID));

          如果我們執(zhí)行如下語句:

          INSERT INTO t(c) SELECT c FROM other_table;

          這個語句是想將other_table表中列c的值都插入到表t的列c中,而表t的id列是自增列,可以自動生成。

          如果主庫和從庫的服務(wù)器執(zhí)行SELECT c FROM other_table返回記錄的順序不同的話(不同服務(wù)器版本、不同的系統(tǒng)變量配置都可能導(dǎo)致同一條語句返回結(jié)果的順序不同),那么針對表t相同id值的記錄來說,列c就可能具有不同的值,這就會造成主從之間數(shù)據(jù)的不一致。

          而如果將binlog的格式改為基于行的日志的話,由于主庫在執(zhí)行完語句后將該語句插入的每條完整的記錄都寫入binlog日志,就不會造成主從之間不一致了。

          瀏覽 65
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人三级麻豆精品在线观看 | ss视频在线 | 亚洲AV无码乱码国产精品蜜芽 | 欧美一级特黄一区二区 | 久久久久亚洲AV成人无码电影 |