<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和relay-log到底長啥樣?

          共 3279字,需瀏覽 7分鐘

           ·

          2020-09-19 03:08

          今天,我們就來深挖一下mysql的復(fù)制機(jī)制到底有哪一些,以及binlog和relay-log的結(jié)構(gòu)到底是什么樣子的。

          binlog作用

          binlog的主要作用是記錄數(shù)據(jù)庫中表的更改,它只記錄改變數(shù)據(jù)的sql,不改變數(shù)據(jù)的sql不會寫入,比如select語句一般不會被記錄,因為他們不會對數(shù)據(jù)產(chǎn)生任何改動。

          用一個實際的場景看下binlog產(chǎn)生的過程,準(zhǔn)備sql:

          create?table?test(text?varchar(20));
          insert?into?test?values?('test_text');
          select?*?from?test;
          flush?logs;

          查看binlog

          show?binlog?events?in?'binlog.000029';

          顯示的結(jié)果如下:

          binlog

          另外,也可以使用mysqlbinlog工具來查看binlog的內(nèi)容:

          show?variables?like?'log_%';?#查看日志目錄
          mysqlbinlog?--short-form?--force-if-open?--base64-output=never?/usr/local/var/mysql/binlog.000029

          從日志我們可以看到執(zhí)行了創(chuàng)建表的語句以及一個Format_desc頭和Ratate輪換事件,這個我們會在后面講到,先看幾個字段代表的含義。

          Log_name代表日志文件的名稱,比如我這里的查詢是直接查詢binlog.000029,默認(rèn)的寫法是show binlog events,但是這樣只會查詢到第一個binlog,并不是當(dāng)前激活狀態(tài)的binlog,如果你不知道binlog有哪些,可以用命令:

          show?binary?logs;?#查看binlog列表
          show?master?status;?#查看最新的binlog

          Pos代表文件開始的位置。

          Event_type代表事件的類型。

          Server_id是創(chuàng)建事件的服務(wù)器ID。

          End_log_pos代表事件在文件中的結(jié)束位置,以上面為例,第一次查詢的結(jié)束位置是723,第二次insert之后文件的開始位置就是從723開始。

          Info代表事件信息,是一段可讀的文本內(nèi)容。

          binlog日志結(jié)構(gòu)

          binlog日志的結(jié)構(gòu)大概是長這樣的,它由索引文件和binlog文件組成,其中binlog事件又包含通用頭、提交頭和事件體3個部分組成。

          首先說說索引文件,索引文件的每一行都包含了一個binlog文件的完整文件名(類似host-bin.001),一些命令比如flush logs將所有日志寫入磁盤會影響到索引文件。

          每個binlog文件以若干個binlog事件組成,以格式描述事件(Format_description)作為文件頭(上面的binlog圖片F(xiàn)ormat_desc事件),以日志輪換事件(rotate)作為文件尾。

          Format_description包含binlog文件的服務(wù)器信息、文件狀態(tài)的關(guān)鍵信息等。如果服務(wù)器關(guān)閉或者重啟,則會創(chuàng)建一個新的binlog文件,同時寫入一個新的format_description。他的格式大致如下。

          2????????????????binlog-version
          string[50]???????mysql-server?version
          4????????????????create?timestamp
          1????????????????event?header?length
          string[p]????????event?type?header?lengths

          日志輪換事件則包含下一個binlog的文件名以及開始讀取的位置,它由服務(wù)器寫完binlog后添加到文件尾,輪換事件并不會每次都存在,格式如下。

          if?binlog-version?>?1?{
          8??????????????position
          }
          string[p]??????name?of?the?next?binlog

          binlog事件包含若干個事務(wù)組成的組(group),每個組對應(yīng)一個事務(wù),如果是create alter語句不屬于事務(wù)語句的話,則他們本身就是一個組,每個組要么全部執(zhí)行,要么都不執(zhí)行。

          binlog事件結(jié)構(gòu)

          每個binlog事件由3個部分組成:

          1. 通用頭,包含binlog中所有事件具備的基本信息。
          2. 提交頭,對于不同類型的事件來說,提交頭的內(nèi)容也不盡相同
          3. 事件體,存儲事件的主要數(shù)據(jù),同樣對于不同類型事件也不同。

          binlog輪換和清理

          從上面的例子我們也可以看出來,binlog并非只有一個,而基于真實的場景來說,始終寫一個binlog文件肯定也是不可取的,而binlog輪換主要有3個場景:

          1. 服務(wù)器啟動,每次服務(wù)器啟動都會生成一個新的binlog文件。
          2. 達(dá)到最大大小,可以通過binlog-cache-size控制大小,達(dá)到最大大小后將更換。
          3. 顯示刷新,flush logs將所有日志寫入磁盤,這時候會創(chuàng)建一個新的文件寫入,從第一個例子也能看出來執(zhí)行完之后生成了一個新的日志binlog.000030的文件并且開始的位置是4。

          隨著時間的推移,我們的binlog文件會越來越多,這時候有兩種方式可以清除binlog:

          1. 通過設(shè)置expire-logs-days控制想保留的binlog日志文件天數(shù),系統(tǒng)將會自動清理。
          2. 通過PURGE BINARY LOGS手動清理

          relay-log結(jié)構(gòu)

          relay-log中繼日志是連接master和slave的核心,我們來深入了解一下它的結(jié)構(gòu)和使用。

          image-20200909161115718

          relay-log的結(jié)構(gòu)和binlog非常相似,只不過他多了一個master.info和relay-log.info的文件。

          master.info記錄了上一次讀取到master同步過來的binlog的位置,以及連接master和啟動復(fù)制必須的所有信息。

          relay-log.info記錄了文件復(fù)制的進(jìn)度,下一個事件從什么位置開始,由sql線程負(fù)責(zé)更新。

          上一篇文章我們提到了整個復(fù)制流程的過程大概是這個樣子:

          知道binlog和relay-log的結(jié)構(gòu)之后,我們重新梳理一下整個鏈路的流程,這里我們假定master.info和relay-log.info都是存在的情況:

          1. Master收到客戶端請求語句,在語句結(jié)束之前向二進(jìn)制日志寫入一條記錄,可能包含多個事件。
          2. 此時,一個Slave連接到Master,Master的dump線程從binlog讀取日志并發(fā)送到Slave的IO線程。
          3. IO線程從master.info讀取到上一次寫入的最后的位置。
          4. IO線程寫入日志到relay-log中繼日志,如果超過指定的relay-log大小,寫入輪換事件,創(chuàng)建一個新的relay-log。
          5. 更新master.info的最后位置
          6. SQL線程從relay-log.info讀取進(jìn)上一次讀取的位置
          7. SQL線程讀取日志事件
          8. 在數(shù)據(jù)庫中執(zhí)行sql
          9. 更新relay-log.info的最后位置
          10. Slave記錄自己的binlog日志

          但是在這里IO和SQL線程有會產(chǎn)生重復(fù)事件的問題,舉一個場景:

          1. 先記錄中繼日志,然后更新master.info位置
          2. 此時服務(wù)器崩潰,寫入master.info失敗
          3. 服務(wù)器恢復(fù),再次同步從master.info獲取到的是上一次的位置,會導(dǎo)致事件重復(fù)執(zhí)行

          既然會有這個問題還為什么要這樣做呢?假設(shè)反過來,先更新master.info再記錄中繼日志,這樣帶來的問題就是丟失數(shù)據(jù)了。而mysql認(rèn)為丟失比重復(fù)更嚴(yán)重,所以要先刷新日志,保大還是保小mysql幫你做了決定。


          推薦閱讀

          1、【大學(xué)逆襲之路-開篇】本科掙 30 萬,秋招提前批offer,帥地做對了什么?(附所有知識清單)


          瀏覽 76
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  国产激情片 | 久久国产主播 | 一级A片电影A片录像 | 色色色中文字幕 | 韩国无码一区二区 |