點位、gtid、binlog、redolog

  從庫都是通過讀取日誌的形式來進行“追”主庫的備份。在邏輯備份中,日誌的記錄方式有兩種,一種是點位,另一種是gtid

(1)點位

  點位記錄方式是由兩部分組成,第一部分是日誌的編號,因爲假如一個日誌的容量是1.1G,當這個日誌滿了後就會分裂成多個日誌,此時從庫要從主庫的哪一個日誌開始讀取追趕主庫,就要用到第一部分的“位“來定位是哪個日誌;第二部分是用來定位日誌的事務,也就是從庫要執行第幾個日誌的第幾個事務。就是通過這個點位的方式,來實現從庫定位到主庫讀取哪個日誌的哪個事務。
但是這裏就會出現一個問題,例如:
在這裏插入圖片描述
其中A是主庫,B是A的從,C是B的從。在A表中的點位假設要同步的事務點位是0010:107,但是在從庫B中,該事務的點位可能就變成其他了,例如變成0010:110(後面講爲什麼,主要因爲從庫的binlog記錄是通過relay log來的,記錄的是數據頁的物理修改,而不是某一行或某幾行修改成怎樣怎樣,它用來恢復提交後的物理數據頁(恢復數據頁,且只能恢復到最後一次提交的位置))。
  此時,B庫的relay log去讀取A庫的binlog的日誌內容,然後寫到B庫的binlog中記錄點位,C庫也是讀取B庫的relay log在commit後寫到binlog中。因此,如果A庫是已經存儲的一段時間後的數據庫,此時B庫去同步A庫時,B庫的relay log裏確實有A庫需要進行同步的點位信息,但是當B庫的relay log刷新到B庫的binlog時,binlog裏記錄的點位信息記錄的就是B庫自己的事務點位信息(relay log中的點位的位置),C庫同理,所以當B庫掛掉後,C庫是無法通過binlog和relay log來和A庫進行同步的。
  這就是點位複製的一個缺點,因此引出gtid記錄方式。

(2)gtid

  gtid(global transaction ID)是對於一個已經提交事務的編號,是由master_uuid組成,是一個全局的唯一編號。這樣當出現上面的ABC情況,當B掛掉後,可以通過這個全局的編號讓C從庫找到A主庫要同步的事務。
  邏輯備份其最大的缺陷是備份和恢復速度較慢,如果數據庫大於50G,mysqldump備份就不太適合。邏輯備份是備份sql語句,在恢復的時候執行備份的sql語句實現數據庫數據的重現。
  在innodb中,他最具有特色的就是redolog日誌。
  而對於myisam,他是沒有事務的,一般用於系統表,所以當myisam進行主從備份的時候一般是通過鎖表的形式,鎖表鎖1次,直到複製完。
  Innodb中採取的是日誌先行,也就是redolog會在實際數據文件修改之前先落地,以保證事務的持久性,所以redolog是同步落地(可能落地內存,這裏的內存指的是cache,也可能落地磁盤),binlog是異步落地。之所以這樣,是因爲當我們主庫insert後,要保證數據庫的高可用,肯定要持久化,但是面對大量的數據,你去insert或者update開銷很大,所以此時不能用數據做到同步,我們去同步的是redolog,讓redolog同步落地保證高可用。
  Redolog記錄的是數據庫所發生的變化,只會針對自己的數據庫的數據,不會和從庫進行交互。由於redolog的落地是根據策略來選擇是同步落地到內存,還是同步落地到磁盤,因此redolog落地到磁盤一般是一個刷的過程。而對於Binlog,他有一個sync_binlog參數來控制數據庫的binlog刷到磁盤上去,接下來就講redolog和binlog的落地過程。

(3)binlog

① sync_binlog=0
當事務提交後,Mysql僅僅是將binlog_cache中的數據寫入Binlog文件,但不執行fsync之類的磁盤 同步指令通知文件系統將緩存刷新到磁盤,而讓Filesystem自行決定什麼時候來做同步,這個是性能最好的。但風險大,因爲一旦系統Crash,在binlog_cache中的所有binlog信息都會被丟失。
② sync_binlog=n
在進行n次事務提交以後,Mysql將執行一次fsync之類的磁盤同步指令,同志文件系統將Binlog文件緩存刷新到磁盤,所以風險小,但是性能消耗大。Mysql中默認設置sync_binlog=0,即不作任何強制性的磁盤刷新指令,這時性能是最好的,但風險也是最大的。

binlog的三種模式(row、statement、mixed):
① row:row模式是日誌會記錄每一行數據的修改,然後再在slave端再對相同的數據進行修改。優點是不記錄sql上下文相關信息,會詳細的記錄下每一行數據修改的細節。但缺點是會產生大量的日誌內容,因爲每次記錄都將以每行記錄的修改來記錄的,例如我執行一條update,binlog中將不止是記錄這條update鎖對應的事件,而是這條語句所更新的每一條記錄的變化情況。
  例如update product set A=3 where……,那麼在日誌中會記錄update的A=3,B=0,C=0……就是把沒有變更的都會記錄下來(因爲屬於變化情況)。

② statement:每一條會修改數據的sql都會記錄到master的binlog中,slave在複製的時候sql進程會解析成和原來master端執行過的相同的sql再次執行。他的優點是解決了row的傷痛,不需要記錄每一行數據的變化,減少了binlog日誌量,但是缺點是爲了讓這些語句在slave端能正確執行,則還需要記錄上下文信息。

③mixed:row和statement的結合,mysql會根據執行的每一條具體的sql語句來區分對待記錄的日誌形式,也就是在statement和row之間選一個。

(4)redolog

  在InnoDB中,有一個獨有的存儲層redolog:就是說當我們在編寫sql語句的時候,每寫一句就會把這一句sql先記錄在redolog這個存儲層日誌裏,當我們編寫sql爲commit之後,redolog就會進入prepare狀態,此時纔會把redolog裏面的內容寫到服務層binlog裏面,當binlog開始執行到commit後,我們數據庫的數據纔會更新,然後從庫的replay log纔去讀binlog裏面的數據進行同步,這也是innoDB的一個特色。當我們binlog開始執行但是沒有執行到commit,說明數據回滾了,那麼去回滾的其實並不是binlog,而是redolog,通過redolog的undo去執行回滾。
  Redolog在後面也有提及,無論是物理複製還是邏輯複製,都會有redolog,所謂的日誌先行就是指的這個,他以頁爲單位,記錄的是當前頁的變化。

O_DIRECT選項:O_DIRECT選項是Linux文件寫入中的一個選項,開啓了這個選項以後,數據就可以跳過系統層的緩存,直接寫入磁盤。但是對於redolog而言,這個選項是關閉的,因此對於redolog,他會根據innodb_flush_log_at_trx_commit 這個參數來控制redolog刷新到磁盤的策略。

① innodb_flush_log_at_trx_commit=1 (默認)
  表示每次事務提交的時候,調用fsync函數來實現redolog的落盤持久化。也就是每次事務提交時,redolog buffer會被寫入到日誌文件並刷寫到磁盤。這也是默認值。這是最安全的配置,但由於每次事務都需要進行磁盤I/O,所以也最慢。

② innodb_flush_log_at_trx_commit=0
  表示事務在執行過程中,日誌一直放在redo log buffer中,但是在事務commit的時候,不寫入redo log file,而是通過master線程每秒操作一次,從redo log buffer寫入到redo log file中然後刷到磁盤。由於跟事務提交無關。在機器crash並重啓後,會丟失一秒的事務日誌數據。

③ innodb_flush_log_at_trx_commit=2
  每次事務提交的時候,把事務日誌數據從redobuffer緩存區寫到日誌文件redofile中或者操作系統的緩存catch中;每隔一秒,刷新一次日誌文件,但不一定刷新到磁盤上,而是取決於操作系統的調度;也就是說,redologfile是由操作系統來調度的,如果爲2則他可能會把日誌數據存到操作系統緩存中,如果操作系統緩存滿了他就刷到磁盤裏(這就跟1一樣了)。但這裏需要注意的是,這裏的操作系統緩存和redolog buffer的緩存是兩個部分,操作系統緩存由操作系統調度的,只要在操作系統緩存中,Mysql crash就不會丟失操作系統緩存中的數據。
  當取值爲 2 時,每次事務提交會寫入日誌文件,但並不會立即刷寫到磁盤,日誌文件會每秒刷寫一次。這時如果 mysqld 進程崩潰,由於日誌已經寫入到系統緩存,所以並不會丟失數據;在操作系統崩潰的情況下,通常會導致最後 1s 的日誌丟失。所以,當設置爲2 的時候,MySQL Crash 並不會造成數據的丟失,但是OS Crash 或者是主機斷電後可能丟失的數據量就完全控制在文件系統上了。
  對於一些數據一致性和完整性要求不高的應用,配置爲 2 就足夠了;如果爲了最高性能,可以設置爲 0。有些應用,如支付服務,對一致性和完整性要求很高,所以即使最慢,也最好設置爲 1。
  上面說的操作系統的緩存其實就是cache,是cpu和內存之間的緩衝,操作系統用cache來提升訪問速度,將經常使用的操作結果放到cache中避免總是讀取磁盤的操作降低磁盤壓力。
  而buffer指的是讀寫緩衝區,用於內存和硬盤之間的數據交互,就是把要寫入硬盤的內容先在內存中堆積,然後攢足後一次性寫到硬盤裏(也可以直接調用fsync來直接持久化到硬盤,此時BUFFER緩存清空,除此之外linux有一個守護進程定期清空緩衝內容(即寫入磁盤)),從而減少磁盤碎片和硬盤的反覆尋道。buffer是由各種進程分配的,例如mysql需要則分配buffer給Mysql,當mysql宕機了,那麼mysql對應的buffer也沒了。
  簡單來說,buffer是即將要被寫入磁盤的,而cache是被從磁盤中讀出來的,cache就相當於落地持久化了,所以上面的innodb_flush_log_at_trx_commit=2的情況,把日誌信息要麼落地到磁盤redolog file中,要麼落地到系統文件緩衝cache中,只要系統不宕機,就不會丟失。Buffer和cache都是都是ram中的數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章