官术网_书友最值得收藏!

第4章 傳統復制與GTID復制

MySQL 5.6之前的版本只支持傳統復制,即“基于二進制日志文件(binlog file)和位置(binlog pos)的復制”。在該復制模式中,復制拓撲的初始化配置和變更、復制的高可用切換等操作都需要找到正確的二進制日志文件和位置,否則就無法正確復制。然而,尋找該位置信息的過程所涉及的操作步驟較為煩瑣,于是在MySQL 5.6及其之后的版本中,出現了基于GTID的復制(為了表述上的方便,書中也簡稱為GTID復制)模式。它利用GTID自動定位的特性,不再需要二進制日志的位置信息,也就省去了尋找這些信息所需的煩瑣步驟,極大地簡化了復制拓撲的初始化配置和變更,以及復制的高可用切換等操作。本章將對這兩種復制模式做基本的介紹。

4.1 傳統復制

傳統復制是指基于二進制日志文件和位置的復制,實際上它更像是在一些特定操作下(例如,新搭建復制拓撲、調整復制拓撲、主從切換等),告訴從庫如何找到正確的復制位置的一種解決方案(GTID復制模式與此類似,但它把手動定位變更為自動定位)。每個從庫使用基于二進制日志文件和位置的復制配置時,需要在使用CHANGE MASTER TO語句時,指定需要連接的主庫IP地址、賬號、密碼、端口、二進制日志文件名和二進制日志的位置。這些信息可以保存在從庫的磁盤文件中,也可以保存在從庫的配置信息表中。有關細節詳見第8章“從庫中繼日志和狀態日志”。

第2章對復制的基本原理做了詳細介紹,這里我們根據本章的需要,再簡要闡述一遍復制的原理。

? 作為主庫的MySQL實例(數據源)將數據變更作為“事件”寫入二進制日志文件。二進制日志中記錄的數據變更信息可能會以不同的日志記錄格式存儲(具體看系統變量binlog_format如何設置)。作為從庫的MySQL實例讀取主庫的二進制日志,并在從庫的本地數據庫上應用主庫二進制日志中的事件(日志重放)。

? 每個從庫都會收到主庫二進制日志的全部副本內容。每個從庫自行決定如何執行其中的內容。除非另行指定一些過濾規則,否則在從庫上會應用主庫二進制日志中的所有事件。

? 每個從庫都會記錄當前對應主庫的二進制日志文件位置、二進制日志文件名,以及在此文件中它已從主庫讀取和處理的位置(即SQL線程和I/O線程的位置)。每個從庫獨立地應用主庫的二進制日志,相互之間不產生影響并各自記錄自身應用到的位置,而且就算有從庫與主庫的連接發生斷開或重連,也不會影響主庫的操作(這里主要指主庫的可用性)。

在同一個復制架構組內,所有實例的Server ID須唯一,以便唯一標識一個實例機器的二進制日志來源。這樣做可以避免在較為復雜的復制架構中,重復傳輸與應用二進制日志(例如,環形復制和雙主復制)。GTID復制模式也是如此,下文將不再贅述。

關于基于二進制日志文件和位置的復制拓撲的搭建步驟,詳見第14章“搭建異步復制”。

4.2 GTID復制

GTID(Global Transaction Identifier,全局事務標識符)復制,即基于GTID實現的復制,指的是基于事務的復制。使用GTID時,在某個MySQL Server(后文為了表述上的方便,也簡稱為Server)上提交的事務可以被任意從庫應用識別與跟蹤,使用GTID復制在搭建新從庫或者因故障轉移到新主庫時,會自動根據GTID來定位對應的二進制日志文件和位置,更準確地說,是自動尋找從庫缺失的GTID SET對應的二進制日志記錄,極大地降低了這些任務的復雜度。

由于GTID復制是完全基于事務的,因此也更容易確定主庫和從庫的數據是否一致,只要在主庫上提交的所有事務在從庫上也成功提交,就能保證兩者之間的數據一致性。在一個持續正常運行的主從復制拓撲中,主從庫之間的GTID SET一致就可以粗略地認為主從庫的數據是一致的,人為的誤操作除外。另外,為了獲得最佳效果,建議使用基于row格式的復制。

GTID SET信息在主庫與從庫中都會保存。這意味著可以通過GTID SET信息來追蹤二進制日志的來源。此外,一旦在給定Server中提交過某個GTID的事務,則該Server將忽略后續提交的相同GTID的事務。因此,主庫上提交的事務在從庫上只能應用一次,之后碰到重復的GTID時會自動跳過整個事務,這有助于保證主從庫數據一致。

提示:在MySQL 5.6.x中,如果使用GTID復制,則從庫必須使用系統變量log_bin來啟用二進制日志記錄功能,系統變量log_slave_updates將主庫的二進制日志記錄到從庫自身的二進制日志中。因為GTID需要被持久化,MySQL 5.7.x及其之后的版本新增了一張InnoDB存儲引擎的mysql.gtid_executed表來持久化GTID信息,所以可以不啟用系統變量log_bin和log_slave_updates。

4.2.1 GTID的格式和存儲

4.2.1.1 GTID的格式

在主從復制拓撲中,按照使用規范,主庫提供讀/寫操作,從庫提供只讀操作,所以源Server通常是主庫的角色。GTID是在源Server上創建的具有唯一性的標識符,并與源Server上提交的每個事務相關聯。此標識符在給定的復制拓撲中的所有Server上都是唯一的。

通過GTID可以區分事務的來源(通過GTID組成中的UUID可以區分事務是由哪個Server提交的,關于GTID組成的介紹詳見下文)。當主庫事務被提交并將二進制日志寫入二進制日志文件中時,會為其分配新的GTID,保證事務的GTID單調遞增且生成的數字之間沒有間隔。如果事務未寫入二進制日志文件(例如,事務被過濾,或者事務是只讀的),則在源Server上不會為其分配GTID。

在從庫上應用主庫的二進制日志時會保留主庫事務的GTID,即使從庫在復制事務時進行了過濾,主庫事務的GTID也會在從庫中持久化,即數據可能已被過濾,但是GTID仍然會被記錄下來。mysql系統庫下的系統表gtid_executed用于保存從庫中應用的所有事務已分配的GTID。在MySQL 5.7中,當啟用系統變量log_bin和log_slave_updates時,表mysql.gtid_executed中的GTID SET不包括最后一個正在使用的二進制日志文件中的GTID。

從庫在應用主庫的二進制日志時,碰到具有相同GTID的事務時會跳過,也就是說,主庫的事務在從庫上的應用不會超過1次(即不會重復執行),這可以保證主從庫數據的一致性。一旦在給定Server上提交了給定GTID的事務,則該Server將不會嘗試執行具有相同GTID的任何事務,也不會引發錯誤信息且不會執行事務中的語句。

? 如果某個給定GTID的事務正在某個Server上執行,且該事務處于活躍狀態(未提交也未回滾),則在該Server上嘗試執行具有相同GTID的并行事務時都將被阻塞。如果這個活躍的事務被回滾,則第一個被阻塞的并行事務會繼續嘗試使用該GTID來提交,在此期間,如果其他并行會話嘗試使用相同的GTID來提交事務,則會被阻塞。如果給定GTID的事務被提交,則使用了相同GTID的其他并行事務的所有語句都會被跳過。

GTID由用冒號“:”分隔的UUID和TID構成,即GTID = source_id:transaction_id。

? source_id:標識事務的源Server,通常為主庫的server_uuid。

? transaction_id:是由在主庫上提交事務的順序確定的序列號。例如,第一個事務的transaction_id為1(事務的GTID不能使用0作為序列號),假如在該Server上提交的事務已經到了第23個,則第23的事務的GTID為3E11FA47-71CA-11E1-9E33- C80AA9429562:23。

二進制日志中事務的GTID可以在mysqlbinlog工具的輸出中查看,帶GTID的復制狀態可以通過PERFORMANCE_SCHEMA系統庫下的復制狀態表查看,例如,replication_ applier_status_by_worker表。更多信息詳見第9章“通過PERFORMANCE_SCHEMA庫檢查復制狀態”。

GTID SET指的是由一個或多個GTID列表,或一個GTID范圍組成的集合。 GTID SET在MySQL Server中有幾種使用方式。例如:

? 系統變量gtid_executed和gtid_purged存儲的值需要使用GTID SET。

? START SLAVE子句UNTIL SQL_BEFORE_GTIDS和UNTIL SQL_AFTER_GTIDS需要使用GTID SET。其中,前者用于指定從庫重放事務到GTID SET中的第一個GTID即停止,后者用于指定重放到GTID SET的最后一個GTID之后停止。

? 內置函數GTID_SUBSET()和GTID_SUBTRACT()的輸入參數需要使用GTID SET。

來自同一個實例的一系列GTID可以合并成單個表達式。例如:

4.2.1.2 GTID的存儲

上文提到,從MySQL 5.7開始,在mysql系統庫下提供一張InnoDB引擎的gtid_executed表來持久化存儲GTID。該表中的每一行數據都包含事務的始發實例UUID,以及對應的GTID SET的起始和結束事務ID;對于僅引用單個GTID的行,起始和結束事務ID相同。

安裝或升級MySQL Server時,如果該表不存在,則MySQL Server會自動使用類似如下的CREATE TABLE語句創建mysql.gtid_executed表(注意,請勿自行嘗試創建與修改此表,這里列出建表DDL語句僅僅是為了便于說明):

mysql.gtid_executed表僅供MySQL Server內部使用。當從庫禁用二進制日志功能或關閉系統變量log_slave_updates時,每個事務的GTID都會被實時記錄到該表。另外,在MySQL Server中執行FLUSH LOG語句時,二進制日志會執行切換,上一個二進制日志文件中的GTID將會被記錄到該表中。當二進制日志被丟失時,該表中的GTID記錄不會丟失,例如,在MySQL Server中對二進制日志執行清理時,被清理的二進制日志包含的GTID在該表中仍然會保留,但當執行RESET MASTER語句時,該表中的內容會被重置(清空)。

僅當系統變量gtid_mode被設置為ON或ON_PERMISSIVE時,GTID才存儲在mysql.gtid_executed表中。是否在該表中實時存儲GTID,取決于系統變量log_bin和log_slave_updates的值,詳情如下:

? 如果禁用二進制日志記錄(注意,禁用二進制日志需要注釋掉系統變量log_bin,而不是將其設置為OFF),或者禁用log_slave_updates(設置為OFF或0),則MySQL Server在每個事務提交時將事務的GTID一并記錄到該表。

? 如果啟用了二進制日志記錄(啟用了系統變量log_bin和log_slave_updates。注意,在啟動MySQL Server時,為系統變量log_bin指定了具體值,就表示啟用二進制日志記錄功能,而不是通過將其設置為“ON”字符串來啟用二進制日志記錄功能,如果這樣做,最終會讓所有的二進制日志文件的前綴都變成“ON”字符串),則只在切換二進制日志或關閉MySQL Server時,將先前二進制日志的所有事務的GTID寫入mysql.gtid_executed表。這種情況適用于主庫或啟用了二進制日志記錄的從庫。如果MySQL Server意外停止,則當前二進制日志文件中的GTID SET不會保存在mysql.gtid_executed表中。在MySQL Server重新啟動期間,將掃描二進制文件并將這些GTID記錄到表中(注意,如果MySQL Server重新啟動時禁用了二進制日志記錄功能,則在重新啟動期間不會掃描二進制日志中的GTID,也就是說二進制日志中的GTID無法被記錄下來,也就無法啟動復制),但不會記錄所有已執行事務的GTID,最后一個二進制日志文件中的GTID不會被記錄。GTID的完整記錄由系統變量gtid_executed的全局值提供,始終使用全局變量@@global.gtid_executed(該變量在事務每次提交后更新)來表示MySQL Server的最新GTID狀態,并且在查詢該全局變量的值時不會查詢mysql.gtid_executed表中的數據。

以下是一個mysql.gtid_executed表壓縮示例。

通過設置系統變量gtid_executed_compression_period,可以在每次執行壓縮表之前控制表中允許記錄的事務數,即每隔多少個事務壓縮一次,從而控制壓縮率。此變量的默認值為1000,意味著在默認情況下每1000個事務之后執行表的壓縮。將gtid_executed_ compression_period設置為0可以防止執行壓縮,如果要關閉壓縮功能,請留意磁盤空間是否充足。

啟用二進制日志記錄時,不會使用gtid_executed_compression_period的值,即不根據該變量定義的事務數量來執行壓縮,而是在每次執行二進制日志切換時壓縮mysql.gtid_ executed表。

mysql.gtid_executed表的壓縮由名為thread/sql/compress_gtid_table的專用前臺線程執行。此線程未在SHOW PROCESSLIST的輸出中列出,但可以通過查詢performance_schema. threads表來查看,類似如下內容:

4.2.2 GTID的生命周期

GTID的生命周期包括以下幾個階段:

(1)在主庫上執行事務并提交。事務在提交時會被分配一個GTID,該GTID由主庫的UUID和主庫上尚未使用的最小非零事務序列號組成。隨后,此GTID被寫入主庫的二進制日志(在二進制日志的GTID事件中記錄,該事件排在事務的binlog event group的最前面)。如果未將事務寫入二進制日志(例如,因為主庫中過濾了對某個數據庫操作的事務,即不寫入二進制日志;或者在主庫中某個事務是只讀的),則不會為其分配GTID。

(2)如果為事務分配了GTID,則在提交事務時,通過二進制日志中的Gtid_log_event將GTID寫入二進制日志做原子保留。如果二進制日志執行了切換或Server關閉,則會將二進制日志文件中涉及的所有事務的GTID寫入mysql.gtid_executed表中保存。

(3)如果為事務分配了GTID,則在提交事務之后不久通過非原子方式將GTID添加到系統變量gtid_executed(@@global.gtid_executed)的GTID SET中,系統變量gtid_executed的GTID SET值在復制中用來標記已提交數據的狀態,即表示當前數據庫中的數據對應著哪些事務。當啟用二進制日志記錄(主庫必須啟用)后,系統變量gtid_executed中的GTID SET是已提交事務的完整記錄,但mysql.gtid_executed表中記錄的GTID SET不完整。在啟用系統變量log_bin和log_slave_updates時,該表中只記錄除最后一個正在使用的二進制日志之外(最新的GTID保存在當前活躍的二進制日志文件中,也即這里所說的最后一個二進制日志文件),其他所有更早的二進制日志中所涉及的GTID SET。

(4)將二進制日志數據傳輸到從庫并存儲到中繼日志之后,從庫讀取GTID并將讀取到的GTID設置為其系統變量gtid_next的值,以告訴從庫必須使用此GTID記錄下一個事務。注意,從庫是在會話上下文中設置系統變量gtid_next的值的,而不是在全局級別設置的。

(5)從庫驗證在gtid_next中獲得的GTID,是否已有線程獲得該GTID的所有權,以便處理事務。首先,讀取和檢查復制事務的GTID,在處理被讀取GTID的事務之前,不僅需要保證在從庫上此前該GTID沒有被其他事務應用過,而且還需要保證當前沒有其他會話已經讀取此GTID但尚未提交事務,即持有該GTID且處于活躍狀態的事務。因此,如果多個客戶端嘗試同時應用同一事務,即擁有同一個GTID的事務,則Server只允許其中一個執行,從而解決此問題。從庫的系統變量gtid_owned(@@global.gtid_owned)顯示當前正在使用的每個GTID以及擁有它的線程的ID。因此,如果某個GTID已經被使用,當某個線程再次處理相同GTID的事務時不會引發錯誤,而是會使用自動跳過功能來忽略該事務。

(6)如果GTID尚未被使用,則從庫會應用該事務。由于在重放主庫二進制日志時,二進制日志的GTID EVENT中的語句“SET @@SESSION.GTID_NEXT='...';”會將從庫的系統變量gtid_next設置為該語句指定的GTID,因此從庫不會嘗試為此事務生成新的GTID。

(7)如果在從庫上啟用了二進制日志記錄且啟用了系統變量log_slave_updates,則從庫在將二進制日志回放完之后,也會將這些日志中涉及的GTID寫入自身的二進制日志文件做原子保留。在二進制日志執行切換或關閉Server時,Server會將二進制日志文件中所有事務的GTID寫入mysql.gtid_executed表中保存。

(8)如果在從庫上禁用二進制日志記錄或者禁用了系統變量log_slave_updates,則通過實時將GTID直接寫入mysql.gtid_executed表來原子性地保留GTID。MySQL在每個事務中附加一條語句,將GTID插入mysql.gtid_executed表中。在這種情況下,mysql.gtid_executed表是從庫上應用的事務的完整記錄。請注意,在MySQL 5.7中,將GTID插入mysql.gtid_ executed表中的操作,對于DML語句是原子操作,但對于DDL語句則不是原子操作(因為DDL語句不受事務控制)。因此,如果Server在執行DDL語句時意外退出,則GTID的狀態可能會變得不一致。但從MySQL 8.0開始,DDL語句和DML語句都支持原子操作。

(9)在從庫上提交復制事務后不久,GTID通過非原子化的方式將其添加到從庫的系統變量gtid_executed(@@global.gtid_executed)中。對于主庫,此GTID SET包含所有已提交的事務集。對于從庫,如果禁用二進制日志記錄,就無法使用二進制日志文件來持久化GTID,但會將其實時記錄到mysql.gtid_executed表中。如果啟用了二進制日志記錄,則mysql.gtid_executed表并不會實時記錄事務的GTID,也就是說,這時該表中記錄的GTID并不完整,最新的GTID不在該表中,而是在最后一個二進制日志文件中。但是要注意,系統變量gtid_executed中的GTID SET是完整的,它也是在這種情況下唯一完整記錄GTID的地方。

在主庫上完全過濾掉的客戶端事務(例如,主庫使用復制過濾參數指定過濾某個數據庫)由于未分配GTID,因此不會被添加到系統變量gtid_executed中,也不會被添加到mysql.gtid_executed表中。但是,在從庫上為了保證主從庫數據的一致性,即使使用復制過濾參數過濾了某些事務,這些被過濾的事務對應的GTID也必須被持久化(需要確保在從庫上啟用了二進制日志記錄且啟用了系統變量log_slave_updates)。從庫在將這些被過濾的事務寫入自身的二進制日志時,通過Gtid_log_event事件寫入僅包含BEGIN和COMMIT語句的空事務,而不包含被過濾的事務對應的數據變更日志。如果禁用二進制日志記錄或禁用系統變量log_slave_updates,則被從庫過濾的事務的GTID將被實時寫入mysql.gtid_executed表。在從庫上為被過濾的事務保留GTID,可以確保與主庫擁有一致的GTID SET。另外,當從庫重新連接到主庫時,還可以確保不會重復拉取被過濾的事務。

在多線程復制的從庫(slave_parallel_workers > 0)上,可以并行應用事務,因此復制的事務可以無序提交,除非設置slave_preserve_commit_order = 1。當發生這種情況時,系統變量gtid_executed中的GTID SET將包含多個GTID范圍,它們之間存在間隙。通常,在主庫或單線程復制的從庫上,GTID的數值是單調遞增的,數值之間沒有間隙。對于多線程復制,從庫上的GTID間隙僅發生在最近應用的事務中,并在復制過程中會填充。當使用STOP SLAVE語句正常停止復制線程時,會先等待應用完成正在執行的事務,然后才會真正停止復制線程,這樣就能夠填補GTID間隙。如果發生異常關閉,例如Server故障或使用KILL語句停止復制線程,則GTID可能會出現間隙。

客戶端可以在執行事務之前將變量@@session.gtid_next設置為有效的GTID值來模擬復制事務。mysqlbinlog解析二進制日志文件時生成的GTID事件中也是使用此技術生成GTID的,這樣客戶端就可以重放該解析內容以保留GTID。通過客戶端提交的模擬復制事務,或者將解析的二進制日志文本內容直接導入某個數據庫實例,完全等同于通過復制線程提交的復制事務,并且事后也無法區分它們。

系統變量gtid_purged(@@global.gtid_purged)中的GTID SET包含已在Server上提交,但在Server上的任何二進制日志文件中都不存在的所有事務的GTID。

? 在從庫上禁用二進制日志記錄時,該系統變量的值表示從庫上所提交的所有復制事務的GTID。

? 啟用二進制日志記錄時,該系統變量的值表示已寫入二進制日志且已被清除的二進制日志文件中包含的事務的GTID。

? 通過語句SET @@global.gtid_purged可以為系統變量@@global.gtid_purged明確設置一個GTID SET。

Server在啟動時,將對系統變量gtid_purged中的GTID SET進行初始化。每個二進制日志文件中的內容都以事件Previous_gtids_log_event開頭,該事件包含先前二進制日志文件中的所有GTID SET,由前一個文件的Previous_gtids_log_event事件中的GTID與前一個文件中每個Gtid_log_event事件的GTID組成。最舊和最新的二進制日志文件的Previous_gtids_log_event事件的內容用于計算Server啟動時系統變量gtid_purged對應的GTID SET。

4.2.3 GTID自動定位

GTID自動定位功能替代了在傳統復制中手工指定用于確定主從庫之間數據流的起始點、停止點和恢復點的文件偏移位置的工作。使用GTID時,從庫需要與主庫同步的所有信息(這里主要指的是主庫中數據變更產生的二進制日志記錄)都直接從復制數據流中自動獲取。

要使用GTID復制啟動從庫,請不要在CHANGE MASTER TO語句中包含MASTER_LOG_FILE或MASTER_LOG_POS選項,這些選項指定二進制日志文件的名稱和文件中的起始位置。對于GTID,你需要啟用MASTER_AUTO_POSITION選項。有關GTID復制的配置,以及啟動主庫和從庫的完整說明,詳見第14章“搭建異步復制”。

默認情況下,MASTER_AUTO_POSITION選項被禁用。如果在從庫上啟用了多源復制,則需要為每個復制通道設置該選項。如果將該選項啟用之后再禁用,會使從庫恢復為基于文件的復制。在這種情況下,你必須指定MASTER_LOG_FILE或MASTER_LOG_POS選項中的一個或兩個(從GTID復制模式切換到傳統復制模式時,建議同時指定RELAY LOG相關的選項,否則還未來得及重放的中繼日志會被清理,容易出現復制故障)。

當復制從庫啟用GTID(gtid_mode=on|on_permissive|off_permissive)并啟用MASTER_ AUTO_POSITION選項時,將激活自動定位以連接主庫。主庫必也須設置gtid_mode = on才能使從庫連接成功。在初始握手通信中,從庫發送一個GTID SET,其中包含從庫已經收到、已提交或兩者都已完成的事務。此GTID SET等于系統變量gtid_executed(@@global. gtid_executed)中的GTID SET與接收事務時記錄在performance_schema.replication_connection_ status表中的received_transaction_set字段表示的GTID的并集(received_transaction_set字段值可以使用select received_transaction_set from performance_schema.replication_connection_ status語句來查詢)。

主庫通過發送其二進制日志中記錄的事務來響應從庫,但這些事務的GTID未包含在從庫發送的GTID SET中,即這些GTID未包含在從庫請求連接主庫時注冊的GTID SET中,因為向主庫注冊的這些GTID代表在從庫中已經被應用,或者存在于從庫的中繼日志中,不需要重復發送,以確保主庫只發送從庫中未接收或未提交的GTID對應的事務。如果從庫從多個主庫接收事務,則此時自動跳過事務的功能可確保事務不會被重復應用。

如果主庫應發送給從庫的任何事務已從主庫的二進制日志中清除,則主庫將錯誤信息ER_MASTER_HAS_PURGED_REQUIRED_GTIDS發送給從庫,而且復制線程啟動失敗或報錯中止。此時,從庫無法自動從此錯誤中恢復,需要從另一個數據源恢復丟失的事務或者使用最新的備份(可在主庫上實時備份)來恢復一個新的從庫,替換舊的從庫。然后,可以考慮是否修改主庫上二進制日志文件的保留時長,以避免二進制日志被過早清理。

如果在事務傳輸期間,主庫發現從庫接收或提交了與主庫UUID相同的事務,但主庫本身沒有它們的記錄,則主庫將錯誤信息ER_SLAVE_HAS_MORE_GTIDS_THAN_ MASTER發送給從庫,并且復制線程啟動失敗或報錯終止。如果主庫在沒有設置系統變量sync_binlog = 1的情況下碰到電源故障或操作系統崩潰,而且丟失了尚未在主庫中落盤但已被從庫接收的已提交事務的二進制日志時,就會發生這種情況。這可能導致主從Server具有相同GTID但是記錄的數據卻完全不同(主庫中丟失的GTID被重新分配給客戶端提交新的數據),即產生了主從庫數據不一致。此時,正確的恢復方法是手動檢查主庫和從庫的數據是否出現了不一致。如果確實出現不一致,而且主庫上缺少事務,則可以將主庫設置為從庫,從其他擁有該缺失事務的Server中同步所缺少的事務;或者從復制拓撲中刪除主庫或從庫,重建搭建復制拓撲。當成功恢復主庫之后,根據需要選擇是否將主庫角色切換回去。

使用GTID復制時,關于跳過復制錯誤的步驟詳見第24章“發生數據誤操作之后的處理方案”,關于復制模式的變更步驟詳見第17章“復制模式的切換”。

4.2.4 GTID復制模式的限制

由于GTID復制依賴于事務,因此在使用時不支持MySQL中的某些功能。下面是使用GTID復制時的一些限制。

1. 更新操作涉及非事務引擎

? 在同一個事務中,不能同時操作支持事務(InnoDB)和不支持事務(MyISAM)的引擎。這是由于同時操作這兩類引擎時可能導致將多個GTID被分配給同一個事務。

? 主從數據庫Server中相同的表使用不同的存儲引擎時(其中,一個Server使用事務表,另一個Server使用非事務表),如果在非事務表上定義了觸發器,可能導致事務與GTID之間的一一對應關系被破壞。

2. CREATE TABLE ... SELECT語句

使用GTID復制時,CREATE TABLE ...語句不允許同時使用SELECT語句。當binlog_format設置為statement時,CREATE TABLE ... SELECT語句是作為一個整體且只分配一個GTID的事務形式被記錄在二進制日志中的,但如果使用row格式的二進制日志,則該語句將被記錄為具有兩個GTID的兩個事務。如果主庫使用statement格式的二進制日志,而從庫使用row格式的二進制日志,則從庫將無法正確處理事務。

3. 臨時表

使用GTID時(這里指的是系統變量enforce_gtid_consistency設置為ON時),事務、存儲過程、存儲函數和觸發器內不支持CREATE TEMPORARY TABLE和DROP TEMPORARY TABLE語句,不過可以在這些對象之外執行CREATE TEMPORARY TABLE和DROP TEMPORARY TABLE語句,但需要使用autocommit = 1自動提交。

4. 防止執行不受支持的語句

要防止執行會導致GTID復制失敗的語句,則需要在啟用GTID時,在整個復制拓撲的所有實例中啟用系統變量enforce_gtid_consistency。當啟用此系統變量之后,上述可能會導致復制出現問題的語句將直接報錯,不予執行。

注意:啟用系統變量enforce_gtid_consistency后,僅對需要寫入二進制日志的語句強制執行GTID一致性,如果Server禁用二進制日志,或者復制過濾選項將可能導致GTID復制出問題的語句過濾掉,即最終并沒有記錄到二進制日志中,則不會對未記錄到二進制日志中的語句強制執行GTID一致性。

5. 關于跳過事務

使用GTID時不支持使用系統變量sql_slave_skip_counter來跳過事務。如果需要跳過事務,可以用第24章“發生數據誤操作之后的處理方案”中提到的注入空事務的方法來跳過事務。

6. 忽略Server實例

使用GTID時,不推薦在CHANGE MASTER TO語句中使用IGNORE_SERVER_IDS選項來忽略某個Server實例的二進制日志變更,因為在GTID復制模式下,已經應用的事務會自動被忽略。在啟動GTID復制之前,請檢查并清除該選項的設置,可通過SHOW SLAVE STATUS語句輸出中的Replicate_Ignore_Server_Ids字段檢查,如果未配置該選項,則該字段值為空。

7. GTID復制模式和mysql_upgrade

當Server啟用了GTID復制模式時(gtid_mode = ON),如果需要對Server使用mysql_upgrade進行升級,則不能啟用二進制日志記錄(--write-binlog選項)。

主站蜘蛛池模板: 东明县| 八宿县| 临海市| 九江市| 贞丰县| 洛浦县| 乌兰察布市| 彩票| 武乡县| 万年县| 防城港市| 应用必备| 兴安盟| 讷河市| 宁陕县| 宁南县| 洛川县| 西充县| 陆河县| 昌邑市| 德安县| 鸡泽县| 景宁| 保亭| 白银市| 富川| 澜沧| 拉萨市| 宜良县| 延安市| 通城县| 阳江市| 西吉县| 德州市| 融水| 法库县| 嵩明县| 门源| 上杭县| 赤水市| 娱乐|