天天看點

大廠都在用的MySQL主從複制、讀寫分離及高可用方案(上)1 單機 =》叢集2 MySQL主從複制

1 單機 =》叢集

根據雲廠商Benchmark結果,4核8G機器運作 MySQL 5.7 時,可支撐TPS 500,QPS 10000。

但随着資料量的增大,讀寫并發的增加,系統可用性要求的提升,單機 MySQL 出現危機:

  • 容量問題,難以擴容,考慮資料庫拆分、分庫分表
  • 讀寫壓力,QPS 過大,特别是分析類需求會影響到業務事務,考慮多機叢集、主從複制
  • 高可用性不足,易當機,考慮故障轉移、MHA/MGR/Orchestrator
  • 高峰時資料庫連接配接數經常超過上限
  • 一緻性問題

    考慮分布式事務,X/A 柔性事務

讀寫分離的實作是基于主從複制架構:一主多從,隻寫主庫,主庫會自動将資料同步到從庫。

主從複制的意義

高并發場景下MySQL的一種優化方案,依靠主從複制使得MySQL實作了資料複制為多份,增強了抵抗高并發讀請求的能力,提升了MySQL查詢性能同時,也提升了資料的安全性。當某一個MySQL節點,無論是主庫還是從庫故障時,還有其他的節點中存儲着全量資料,保證資料不會丢失。

2 MySQL主從複制

2.1 發展史

2000年,MySQL 3.23.15版本引入了複制

2002年,MySQL 4.0.2版本分離 IO 和 SQL 線程,引入了 relay log

2010年,MySQL 5.5版本引入半同步複制

2016年,MySQL 在5.7.17中引入 InnoDB Group Replication

2.2 核心

  • 主庫寫 binlog
  • 從庫 relay log

主從複制的過程

大廠都在用的MySQL主從複制、讀寫分離及高可用方案(上)1 單機 =》叢集2 MySQL主從複制
  • 主庫将變更寫binlog日志,然後從庫連接配接到主庫後,從庫有個I/O線程,将主庫的binlog日志拷貝到本地,寫入一個中繼日志
  • 接着從庫中有個SQL線程會從中繼日志讀取binlog,然後執行binlog日志中的内容。即在本地再次執行一遍SQL,確定跟主庫資料相同

binlog格式

  • ROW

    記錄詳細,但日志量較大

  • Statement

    記錄簡單,隻記錄SQL,無查詢語句

  • Mixed
# 檢視binlog
mysqlbinlog -vv mysql-bin.000005
      

異步複制

異步複制:經典的主從複制,Primary-Secondary Replication,2000年MySQL 3.23.15版本引入 Replication。

傳統的MySQL複制提供了一種簡單的主從複制方案。有一個主(source)并且有一或多個從(replicas)。主資料庫execute事務,将其commit,然後将它們異步發給從庫,以re-executed(在基于語句的複制中)或apply(在基于行的複制中)。它是一個無共享系統,預設情況下所有伺服器都具有資料的完整副本。

MySQL 異步複制

大廠都在用的MySQL主從複制、讀寫分離及高可用方案(上)1 單機 =》叢集2 MySQL主從複制
大廠都在用的MySQL主從複制、讀寫分離及高可用方案(上)1 單機 =》叢集2 MySQL主從複制

優點

簡單

缺點

  • 網絡或機器故障,會造成資料不一緻

SQL的每個增删改的會改變資料的操作,除了會更新資料外,對這個增删改操作還會寫入一個日志檔案,記錄這個操作的日志,即binlog。

MySQL 5.7新版本的并行複制,多個SQL線程,每個線程從relay日志裡讀一個庫的日志,重放。

從庫同步主庫資料的過程是串行化的,即主庫上并行的操作,在從庫會串行執行。

由于【從庫】從【主庫】拷貝日志及串行執行SQL的特點,在高并發下就有延時,從庫資料一定比主庫慢。

是以經常出現,剛寫入主庫的資料讀不到,要過幾十甚至幾百ms才能讀到。

從庫串行化過程:

  1. 讀取binlog日志
  2. 寫relay日志、應用日志變更到自己本地資料

從庫的I/O線程,讀取主庫的binlog日志時,老版本是單線程,5.6.x之後的新版本改為多線程讀取。

若主庫當機時,恰好資料還沒同步到從庫,則有些資料可能在從庫上沒有,可能就這麼丢失了。

是以MySQL實際上在這有兩個機制:

半同步複制

它向協定添加了一個同步步驟。這意味着主庫在送出時,等待從庫确認已接收到事務。隻有這樣,主庫才會恢複送出操作。

2010 年引入Semisynchronous Replication,5.5 可用,解決主庫資料丢失問題,保證主從的最終一緻性。

需啟用插件。

大廠都在用的MySQL主從複制、讀寫分離及高可用方案(上)1 單機 =》叢集2 MySQL主從複制
大廠都在用的MySQL主從複制、讀寫分離及高可用方案(上)1 單機 =》叢集2 MySQL主從複制
  1. 主庫寫入binlog日志後,會強制立即将資料同步到從庫
  2. 從庫将日志寫入自己的relay log後,會傳回ack給主庫
  3. 主庫接收到至少一個從庫的ack後,才認為寫操作完成

上面的圖檔可看到經典的異步MySQL複制協定(及其半同步變量)的示意圖。不同執行個體之間的箭頭表示伺服器之間交換的消息或伺服器與用戶端應用程式之間交換的消息。

組複制

2016年引入,5.7 開始,啟用插件。

大廠都在用的MySQL主從複制、讀寫分離及高可用方案(上)1 單機 =》叢集2 MySQL主從複制

基于 Paxos 協定實作的組複制,保證資料一緻性。

組複制是一種可用于實施容錯系統的技術。複制組是一組伺服器,每個伺服器都有自己的完整資料副本(無共享複制方案),并通過消息傳遞互相互動。通信層提供了一組保證,例如原子消息和總訂單消息傳遞。這些功能非常強大,可以轉化為非常有用的抽象,可以用來建構更進階的資料庫複制解決方案。

MySQL組複制建立在這些屬性和抽象之上,并在所有複制協定中實作多源更新。一個複制組由多個伺服器組成,該組中的每個伺服器可以随時獨立執行事務。但是,所有讀寫事務隻有在組準許後才送出。換句話說,對于任何讀寫事務,組都需要決定是否送出,是以送出操作不是來自原始伺服器的單方面決定。隻讀事務無需組内的任何協調即可立即送出。

當讀寫事務準備好在原始伺服器上送出時,伺服器自動廣播寫值(已更改的行)和相應的寫集(已更新的行的唯一辨別符)。由于事務是通過原子廣播發送的,是以該組中的所有伺服器都将接收該事務,否則将不會。如果他們收到了,那麼相對于之前發送的其他事務,他們都将以相同的順序收到它。是以,所有伺服器都以相同的順序接收相同的交易集,并且為交易建立了全局總訂單。

但是,在不同伺服器上同時執行的事務之間可能存在沖突。通過在稱為認證的過程中檢查并比較兩個不同并發事務的寫集,可以檢測到此類沖突。在認證過程中,沖突檢測是在行級别執行的:如果在不同伺服器上執行的兩個并發事務更新同一行,則存在沖突。沖突解決過程指出,已首先訂購的事務在所有伺服器上送出,而已訂購第二的事務中止,是以在原始伺服器上復原并由組中的其他伺服器丢棄。例如,如果t1和t2在不同的站點上同時執行,都更改了同一行,并且t2在t1之前排序,則t2赢得了沖突,并且t1被復原。這實際上是一個分布式的首次送出勝出規則。請注意,如果兩個事務之間的沖突經常發生,那麼在同一個伺服器上啟動它們是一個好習慣,在那裡,它們有機會在本地鎖管理器上進行同步,而不必由于認證而復原。

對于應用和外部化已認證的交易,如果不破壞一緻性和有效性,組複制允許伺服器偏離交易的約定順序。組複制是最終的一緻性系統,這意味着一旦傳入流量減慢或停止,所有組成員将具有相同的資料内容。當流量在流動時,可以按略有不同的順序對事務進行外部化,或者對某些成員先進行外部化。例如,在多主要模式下,盡管尚未應用全局順序中較早的遠端事務,但是本地事務可能會在認證後立即被外部化。當證明過程确定交易之間沒有沖突時,這是允許的。在單主模式下,在主伺服器上,并發,無沖突的本地事務以與組複制所同意的全局順序不同的順序進行送出和外部化的可能性很小。在不接受來自用戶端的寫操作的輔助伺服器上,事務始終按照約定的順序進行送出和外部化。

下圖描述了MySQL組複制協定,通過将其與MySQL複制(甚至MySQL半同步複制)進行比較,您可以看到一些差別。請注意,為清楚起見,此圖中缺少一些基本的共識和Paxos相關的消息。

大廠都在用的MySQL主從複制、讀寫分離及高可用方案(上)1 單機 =》叢集2 MySQL主從複制