天天看點

點位、gtid、binlog、redolog

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

(1)點位

  點位記錄方式是由兩部分組成,第一部分是日志的編号,因為假如一個日志的容量是1.1G,當這個日志滿了後就會分裂成多個日志,此時從庫要從主庫的哪一個日志開始讀取追趕主庫,就要用到第一部分的“位“來定位是哪個日志;第二部分是用來定位日志的事務,也就是從庫要執行第幾個日志的第幾個事務。就是通過這個點位的方式,來實作從庫定位到主庫讀取哪個日志的哪個事務。

但是這裡就會出現一個問題,例如:

點位、gtid、binlog、redolog

其中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中的資料。