MySQL主備模式的數據一致性解決方案

  根據阿里交易型業務的特色,以及在雙十一這樣業內罕有的需求推進下,咱們在官方的MySQL基礎上增長了很是多實用的功能、性能補丁。而在使用MySQL的過程當中,數據一致性是繞不開的話題之一。本文主要從阿里巴巴「去IOE」的後時代講起,向你們簡單介紹下咱們過去幾年在MySQL數據一致性上的努力和實踐,以及目前的解決方案。html

一.MySQL單機的數據一致性

  MySQL做爲一個可插拔的數據庫系統,支持插件式的存儲引擎,在設計上分爲Server層和Storage Engine層。
  在Server層,MySQL以events的形式記錄數據庫各類操做的Binlog二進制日誌,其基本核心做用有:複製和備份。除此以外,咱們結合多樣化的業務場景需求,基於Binlog的特性構建了強大的MySQL生態,如:DTS、單元化、異構系統之間實時同步等等,Binlog早已成爲MySQL生態中不可缺乏的模塊。而在Storage Engine層,InnoDB做爲比較通用的存儲引擎,其在高可用和高性能兩方面做了較好的平衡,早已經成爲使用MySQL的首選(PS:官方從MySQL 5.5.5開始,將InnoDB做爲了MySQL的默認存儲引擎 )。和大多數關係型數據庫同樣,InnoDB採用WAL技術,即InnoDB Redo Log記錄了對數據文件的物理更改,並保證老是日誌先行,在持久化數據文件前,保證以前的redo日誌已經寫到磁盤。Binlog和InnoDB Redo Log是否落盤將直接影響實例在異常宕機後數據能恢復到什麼程度。InnoDB提供了相應的參數來控制事務提交時,寫日誌的方式和策略,例如:
mysql

innodb_flush_method:控制innodb數據文件、日誌文件的打開和刷寫的方式,建議取值:fsync、O_DIRECT。 innodb_flush_log_at_trx_commit:控制每次事務提交時,重作日誌的寫盤和落盤策略,可取值:012。 當innodb_flush_log_at_trx_commit=1時,每次事務提交,日誌寫到InnoDB Log Buffer後,會等待Log Buffer中的日誌寫到Innodb日誌文件並刷新到磁盤上才返回成功。 sync_binlog:控制每次事務提交時,Binlog日誌多久刷新到磁盤上,可取值:0或者n(N爲正整數)。 不一樣取值會影響MySQL的性能和異常crash後數據能恢復的程度。當sync_binlog=1時,MySQL每次事務提交都會將binlog_cache中的數據強制寫入磁盤。 innodb_doublewrite:控制是否打開double writer功能,取值ON或者OFF。 當Innodb的page size默認16K,磁盤單次寫的page大小一般爲4K或者遠小於Innodb的page大小時,發生了系統斷電/os crash ,恰好只有一部分寫是成功的,則會遇到partial page write問題,從而可能致使crash後因爲部分寫失敗的page影響數據的恢復。InnoDB爲此提供了Double Writer技術來避免partial page write的發生。 innodb_support_xa:控制是否開啓InnoDB的兩階段事務提交.默認狀況下,innodb_support_xa=true,支持xa兩段式事務提交。

  以上參數不一樣的取值分別影響着MySQL異常crash後數據能恢復的程度和寫入性能,實際使用過程當中,須要結合業務的特性和實際需求,來設置合理的配置。好比:sql

MySQL單實例,Binlog關閉場景: innodb_flush_log_at_trx_commit=1,innodb_doublewrite=ON時,可以保證不管是MySQL Crash 仍是OS Crash 或者是主機斷電重啓都不會丟失數據。 MySQL單實例,Binlog開啓場景: 默認innodb_support_xa=ON,開啓binlog後事務提交流程會變成兩階段提交,這裏的兩階段提交併不涉及分佈式事務,mysql把它稱之爲內部xa事務。 當innodb_flush_log_at_trx_commit=1,sync_binlog=1,innodb_doublewrite=ON,innodb_support_xa=ON時,一樣可以保證不管是MySQL Crash 仍是OS Crash 或者是主機斷電重啓都不會丟失數據。

  可是,當因爲主機硬件故障等緣由致使主機徹底沒法啓動時,則MySQL單實例面臨着單點故障致使數據丟失的風險,故MySQL單實例一般不適用於生產環境。數據庫

二.MySQL集羣的數據一致性

  MySQL集羣一般指MySQL的主從複製架構。一般使用MySQL主從複製來解決MySQL的單點故障問題,其經過邏輯複製的方式把主庫的變動同步到從庫,主備之間沒法保證嚴格一致的模式,因而,MySQL的主從複製帶來了主從「數據一致性」的問題。
  MySQL的複製分爲:異步複製、半同步複製、全同步複製。
網絡

異步複製

  主庫在執行完客戶端提交的事務後會當即將結果返給給客戶端,並不關心從庫是否已經接收並處理,這樣就會有一個問題,主若是crash掉了,此時主上已經提交的事務可能並無傳到從庫上,若是此時,強行將從提高爲主,可能致使「數據不一致」。早期MySQL僅僅支持異步複製。架構

半同步複製

  MySQL在5.5中引入了半同步複製,主庫在應答客戶端提交的事務前須要保證至少一個從庫接收並寫到relay log中,半同步複製經過rpl_semi_sync_master_wait_point參數來控制master在哪一個環節接收 slave ack,master 接收到 ack 後返回狀態給客戶端,此參數一共有兩個選項 AFTER_SYNC & AFTER_COMMIT。less

配置爲WAIT_AFTER_COMMIT運維


rpl_semi_sync_master_wait_point爲WAIT_AFTER_COMMIT時,commitTrx的調用在engine層commit以後,如上圖所示。即在等待Slave ACK時候,雖然沒有返回當前客戶端,但事務已經提交,其餘客戶端會讀取到已提交事務。若是Slave端尚未讀到該事務的events,同時主庫發生了crash,而後切換到備庫。那麼以前讀到的事務就不見了,出現了數據不一致的問題,以下圖所示。圖片引自Loss-less Semi-Synchronous Replication on MySQL 5.7.2
​​

若是主庫永遠啓動不了,那麼實際上在主庫已經成功提交的事務,在從庫上是找不到的,也就是數據丟失了。
PS:早在11年先後,阿里巴巴數據庫就創新實現了在engine層commit以前等待Slave ACK的方式來解決此問題。
異步

配置爲WAIT_AFTER_SYNC分佈式

  MySQL官方針對上述問題,在5.7.2引入了Loss-less Semi-Synchronous,在調用binlog sync以後,engine層commit以前等待Slave ACK。這樣只有在確認Slave收到事務events後,事務纔會提交。以下圖所示,圖片引自Loss-less Semi-Synchronous Replication on MySQL 5.7.2 

  在after_sync模式下解決了after_commit模式帶來的數據不一致的問題,由於主庫沒有提交事務。但也會有個問題,當主庫在binlog flush而且binlog同步到了備庫以後,binlog sync以前發生了abort,那麼很明顯這個事務在主庫上是未提交成功的(因爲abort以前binlog未sync完成,主庫恢復後事務會被回滾掉),但因爲從庫已經收到了這些Binlog,而且執行成功,至關於在從庫上多出了數據,從而可能形成「數據不一致」。
  此外,MySQL半同步複製架構中,主庫在等待備庫ack時候,若是超時會退化爲異步後,也可能致使「數據不一致」。

三.MySQL主備的「數據一致性」方案

下面簡單介紹下阿里巴巴早期在MySQL數據一致性問題的一些思考和實踐。

1.單元化架構下的「數據一致性」

  背景:受機架位限制,單機房或地域總會出現容量瓶頸,業務發展受限;以及跨地域容災的需求,阿里巴巴在早期經過單元化的方案來解決。

  由上圖看到中心和各單元之間經過DTS進行實時數據同步,爲了保證中心和單元的數據一致性,咱們早期搭建了數據校驗和訂正平臺。主要包括:TCP(terminal compare platform)全量數據校驗訂正平臺(支持表級,庫級,實例級,集羣級別的數據校驗)和AMG(Alibaba Magic Glass)實時的增量數據校驗訂正平臺。
  TCP和AMG早已成爲阿里巴巴數據庫生態中的核心組件,被普遍用於衆多場景中保障數據一致性,如:主從複製、單元化同步、邏輯遷移、數據庫拆分、字符集升級等。

2.ADHA的回滾和回補

  ADHA(Alibaba Database High Availability)是阿里巴巴集團數據庫高可用體系。ADHA的回滾回補功能幫助咱們在發生切換過程當中儘可能保證數據質量,將老主庫還沒傳到老備庫的數據回滾掉rollback,將回滾掉的數據回補到新主庫中replay。


ADHA的回滾和回補的目的是儘可能保證HA切換過程當中的數據一致性。

3.主從一致性保障措施

  複製衝突自動處理:MySQL 5.5/5.6/5.7的參數slave_exec_mode用於解決主從複製衝突和錯誤。默認值是STRICT適合於全部模式(不解決衝突),值IDEMPOTENT 會忽略duplicate-key和no-key-found錯誤,也不適合解決上面主從不一致問題。咱們從5.6開始給slave_exec_mode增長了一個值smart,用於自動修復一些場景(包括PK衝突及UK衝突引發的HA_ERR_KEY_NOT_FOUND/HA_ERR_FOUND_DUPP_KEY/HA_ERR_END_OF_FILE),具體處理策略以下圖

  從庫複製開啓SMART模式,能夠修復主從複製中斷錯誤,但不能嚴格保證主備一致,所以當使用smart模式修復複製問題後,須要儘快對主從庫作一個全量數據校驗(這裏包括TCP全量校驗+AMG增量校驗),以識別有差別的數據。

4.最大保護邏輯 Max Protection

  爲了保證主從強一致,咱們增長了MySQL最大保護(maximum protection)模式功能,簡稱MP模式(這個是參照ORACLE數據庫的最大保護模式(maximum protection))設計作的,具體由參數 maximum_protection 控制,取值爲 ON和OFF )。當配置半同步時,一旦判斷主從鏈接斷開了,會讓主庫中止對外服務,主庫全部當前鏈接會被KILL,並拒絕接受普通賬號新的鏈接請求。此刻若是有事務在等待從庫迴應binlog的同步信息這一步,鏈接是沒法被kill,該事務在等待超時後會繼續走完(Engine Commit),而後返回網絡錯誤給客戶端。即該筆事務被提交了,須要ADHA介入回滾掉。MySQL的MP機制是須要ADHA一塊兒實現的。
  引入最大保護邏輯,知足了對數據一致性要求很是高的業務場景,如金融業務。也給MySQL的高可用解決方案提出更大挑戰。
  以上都是咱們早期在MySQL主備時代關於「數據一致性」問題的部分對策,其目的都是爲了儘量的保證「數據一致性」,並無完全解決「數據一致性」問題。然而咱們相信技術的發展能帶來更大的運維便利性以及更好的用戶體驗,以Google Spanner以及Amazon Aruora 爲表明的NewSQL系統爲數據庫的「數據一致性」給出了與以往不一樣的思路: 基於一致性協議!基於一致性協議咱們構建了高性能強一致MySQL數據庫,RDS三節點企業版。關於一致性協議和RDS三節點企業版相關知識下面的章節會給你們詳細介紹,敬請關注!


原文連接 本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索