基於MySQL InnoDB Cluster的MySQL高可用方案

導讀:本文介紹了一套基於MySQL Router、Cluster和MySQLShell的InnoDB Cluster高可用方案,以同時實現跨機房的高可用、自動Failover、高一致性、讀寫分離、讀庫高可用、讀請求負載均衡。

全文約4500字,可參閱下面的大綱閱讀。

  • 1. 背景和目標
  • 2. 方案
  • 2.1 基於MySQL GroupReplication的同步方案
  • 2.1.1 組**的同步
  • 2.1.2 組**的failover
  • 2.1.3 組**的配置與啟用
  • 2.2 MySQL Router、Cluster和MySQLShell構成的InnoDB Cluster高可用方案
  • 2.2.1 MySQL Cluster 簡介
  • 2.2.2 MySQL Router簡介
  • 2.2.3 使用MySQL Shell配置MySQL Cluster
  • 2.2.4 初始化MySQL Router
  • 2.3 通過LVS解決router的單點問題
  • 3. 壓測結果
  • 4. 總結

1.背景和目標

數據庫的技術水平總是與業務發展緊密相連。

3年來,洋碼頭的業務增長了上百倍,數據庫也從數臺物理機擴展到了上百臺,從原來單一的SQLServer發展到目前的Mysql為主,外加SQL Server、Mongo、Redis、InfluxDB的多元化的技術路線。每年黑五、雙十一等重大活動節點,數據庫總是會迎來前所未有的流量高峰,2017年的黑五更是比同期增長了7倍之多,新一輪的改造勢在必行。

洋碼頭早期的核心業務數據庫使用的是基於Alwayson的mssql的高可用架構,可以實現單機房高可用、自動Failover、高一致性、讀寫分離、讀請求負載均衡,但在重大運營活動的峰值壓力下,單機性能已經達到了極限,為了應對更高的流量,分庫分表是常規的快速解決方案之一,但分庫分表會導致數據庫實例的大量增加,考慮到眾所周知的成本問題以及將來的擴展性,我們決心把核心的訂單、支付業務也遷移至MYSQL。我們的目標是:同時實現雙機房高可用、自動Failover、強一致性、讀寫分離、讀庫高可用、讀請求負載均衡。

2.技術方案

通過嚴謹的技術測試和分析研究,我們認為傳統的基於半同步+MHA的主從模式仍然存在數據丟失的風險,網絡波動可能導致腦裂,無法實現跨機房高可用、讀庫高可用以及讀請求負載均衡。在多方對比後,我們選擇了2016年底推出的MYSQL InnoDB Cluster作為高可用、高擴展性的分佈式架構,配合LVS,能夠完美的實現以上所有的需求。

介紹具體的方案之前,我們先介紹一下MySQL Innodb Cluster高可用架構的基礎:MySQLGroup Replication。

2.1 基於MySQL Group Replication的同步方案

MySQL Group Replication,簡稱組**,是MySQLInnodb Cluster高可用架構的基礎,是官方2016年底發佈的高可用、高擴展性的集群服務。它基於原生GTID**和Paxos協議[1],自動化的一致性保障,日誌順序分發、多數投票機制確保了主從數據的強一致性(之前的半同步**極端情況是會出現不一致的情況),同時動態成員關係管理、錯誤節點監測確保了組內節點對外的可用性,各節點間在組信息上能夠實時保持一致。採用插件的方式安裝,對原有的數據庫表基本沒有影響(表必須具有主鍵),只是需要把MySQL升級到5.7.17以上,下面的介紹完全基於5.7的組**,8.0的剛剛推出,還有待觀察。

2.1.1 組**的同步

MySQL傳統的同步**一直被詬病的是其糟糕的一致性控制和從庫可寫導致的衝突問題,由於從庫可讀寫,同步時並不強制binlog的連續性,同步異常問題時有發生,組**很好的解決了這個問題。

基於MySQL InnoDB Cluster的MySQL高可用方案

MySQL Group Replication Protocol

組**的同步仍然是基於原生的**,不同的是組**的每個RW事務在commit時都需要組內超過半數的成員確認該事務的全局順序,即共同確認一個全局的順序ID,順序ID中包含了修改行的唯一標識,最終所有的成員都能夠通過相同的順序執行所有的RW事務,從而保證了數據的強一致性[2]。

因為這個特性,組**也能夠支持多主模式,並有一套完善的衝突解決方案。當不同節點同時對同一條記錄發起修改事務時,因為transaction_write_set有行的唯一標識,基於Paxos的衝突檢測機制會提交先獲得多數選票的事務,而另一個申請中的、順序ID小於已提交事務的事務會因此而無法獲得多數選票從而最終回滾,從而達到最終一致。

那麼多主模式是否提升整體寫負載呢?我們使用sysbench做了壓力測試,3個寫節點,5000000條記錄隨機更新,40個併發,大約8000TPS,就會產生大量的衝突,而單節點時可以達到11000TPS,多節點寫TPS降低了近30%,平均響應時間也基本翻番。這是因為熱點數據衝突的緣故,所以多節點同時寫同一個庫的設置是不**的。但如果多主的模式是應用在寫請求按庫隔離分佈在各個節點的模式下,那麼由於日誌同步的開銷要少於原本的事務執行,此時是可以提升整體寫負載能力的。

在單主模式下的組**,除了主節點以外的成員,會自動開啟read_only和super_read_only,以確保同一時刻只有一個節點能夠產生事務日誌,進一步增強一致性,降低了腦裂的可能。

目前一個組**集群最多支持9個節點。

2.1.2 組**的failover

組**成員之間會通過一個特定的端口相互進行心跳檢測,這個端口在配置文件中配置,該端口不同於對外提供數據庫連接的端口。

Failover在不同的場景下會有不同的響應方式,當主節點關閉組**,或者關閉實例時,組**會認為該節點是正常退出**集群,此時退出行為會被廣播到所有的剩餘成員(errorlog 會有相應的view change 記錄),並且剩餘成員會發起選舉,根據權重參數選舉出新的主節點,如果權重參數相同,則選擇UUID最小的實例為主節點。如果主節點是異常連接中斷,比如網絡斷開,服務器斷電等,其他成員因為沒有收到主節點的退出消息,這時會檢查剩餘節點是否大於半數,如果大於半數,則認為主節點異常,會從集群組中踢出主節點,併發起選舉,選出新的主節點,如果剩餘節點小於或等於半數,即只剩最後一個節點,為了避免腦裂,那麼該從節點狀態不變,沒有新的主節點產生,唯一的從節點依然處於只讀狀態,直到我們手動指定新的主節點或者原主節點恢復連接。根據Paxos協議,任何節點成為主節點前都必須獲取所有事務日誌,並且relay完成,該機制保證了failover過程中事務不會丟失。整個failover過程是完全自動的。

2.1.3 組**的配置與啟用

下列是與組**相關的配置項,基本都是必須配置的項目。

基於MySQL InnoDB Cluster的MySQL高可用方案

創建同步賬號

基於MySQL InnoDB Cluster的MySQL高可用方案

初始化集群

對於第一個加入集群的實例,需要開啟該選項(group_replication_bootstrap_group)才能啟動組**,但如果組內已經有Primary,再加入開啟了該選項的新成員,會導致腦裂和同步異常。當整個集群所有實例同時關閉再啟動時,需要手動指定一個新的Primary,也需要開啟該參數。

基於MySQL InnoDB Cluster的MySQL高可用方案

集群成員之間需要能夠相互ping通hostname,可以通過DNS或者hosts文件實現。

組**提供了一套完善的容錯功能,保障了數據的強一致性,自動failover功能則提供了數據庫層面的高可用和快速的恢復服務能力,並且具有橫向彈性擴展的特性。但是組**並不能實現讀請求的負載均衡、讀寫分離以及對應用層的高可用,要實現這些就需要Cluster、MySQLRouter、MySQLShell。

2.2 MySQL Router、Cluster和MySQL Shell構成的Mysql InnoDB Cluster高可用方案

基於MySQL InnoDB Cluster的MySQL高可用方案

InnoDB cluster overview

注:上圖來自官方網站:https://dev.mysql.com/doc/refman ... er-i**oduction.html

2.2.1 MySQL Cluster簡介

Cluster是這個高可用方案中的一個虛擬節點,它會在組**的所有成員上創建一個名為MySQL_innodb_cluster_metadata的數據庫,存儲集群的元數據信息,包括集群信息、集群成員、組**信息、連接的MySQL Router等信息,以提供MySQL Router查詢。它相當於對組**上的成員做了一層邏輯上的封裝,以一個集群的模式展現出來,各節點的狀態與對應實例在組**中成員的狀態實時同步,但是集群的節點與組**的成員只在創建集群時同步,後期組**的成員變更並不自動同步到集群中,可以在集群中做手動的節點增減,這樣使得面向應用端的具體實例實現了更可控更靈活的高可用。

2.2.2 MySQL Router 簡介

MySQL Router可以說是MySQL Proxy的升級產品,是介於Client與MySQL實例之間的**程序。MySQL Router會週期性的訪問Cluster創建的MySQL_innodb_cluster_metadata庫中的元數據獲取集群成員信息,再通過performance_schema的系統表獲取可連接實例及其狀態,啟動後會產生2個端口,分別對應集群的讀寫節點和只讀節點,它使應用能夠透明的連接InnodbCluster下的數據庫,即使集群發生failover或者增減成員也不用修改應用配置。這裡我們實現了讀寫分離和讀請求的負載均衡。

注意,Router需要能夠ping通集群成員的hostname,可以通過DNS或者hosts文件實現。在2.1.3及之前的版本,單個MySQL Router實例只支持上限500個連接數,需要根據實際連接數情況,部署足夠數量的Router節點。

2.2.3 使用MySQL Shell配置MySQL Cluster

MySQL Shell是新的MySQL客戶端工具,支持JavaScript、Python和MySQL腳本,用作搭建InnodbCluster。

MySQL Shell搭建Cluster的一些常用命令

基於MySQL InnoDB Cluster的MySQL高可用方案

2.2.4 初始化MySQL Router

初始化Router時如果不用默認端口可以指定寫端口,讀端口會自動設置為寫端口+1,Router的name會記錄在MySQL_innodb_cluster_metadata中,每臺Router必須使用不同的name。初始化完成後在指定目錄下產生一個配置文件,其中包含了初始化時關聯集群的成員信息,這些信息只在啟動Router後做連接用,啟動期間集群成員的變化會實時被Router接收,但是並不會固化到配置文件中,如果需要修改配置文件可以重新初始化或者手動更新。

基於MySQL InnoDB Cluster的MySQL高可用方案

到這裡,MySQLRouter、Cluster、MySQLGroup replication都配置完成,應用通過連接Router的讀寫端口能夠透明連接數據庫主從節點,單實例異常或failover的影響都可以控制在十多秒的窗口內。但此時Router本身仍是一個單點,官方文檔中**將MySQLRouter安裝在應用端來解決其單點問題,優點是減少網絡傳輸帶來的延遲、可使用Socket連接、容易擴展,與應用一對一綁定。但實際情況下需要考慮應用部署、發佈、健康監測以及集群節點變更後更新Router配置文件等問題,這些問題會大大增加運維的複雜度,需要對原有的應用和發佈系統做升級改造,成本較高。因此最終我們選擇了集中部署加上LVS的模式,既方便維護,又具有靈活的擴展性。

2.3 通過LVS解決router的單點問題

基於MySQL InnoDB Cluster的MySQL高可用方案

基於MySQLInnodb Cluster和LVS的三機房高可用網絡拓撲圖

上圖是基於三機房的完整性方案,數據庫一主多從,每個機房各至少一個數據庫實例,兩組Router群集,一組映射出與數據庫端口相同的讀寫端口,一組映射出與數據庫端口相同的只讀端口,每組Router集群的成員數量可動態擴展,每個機房配置1套LVS,每套LVS映射2個本機房網段的VIP,這樣讀寫端口與只讀端口都與數據庫端口一致,並通過2個VIP分別綁定2個域名,這樣就有隻讀和讀寫兩個域名綁定相同的端口嚮應用分別提供服務。這樣做的目的是,一旦中間層LVS、Router、Cluster出現異常或者有大規模調整需要重建中間層,因為應用配置的讀寫、只讀端口都與數據庫實例端口相同,可以先把2個域名直接指向數據庫實例IP,在中間層調整完成後再指回LVS。同時,每個機房使用獨立的DNS服務,確保本機房的域名指向本機機房的VIP,這樣的架構中,當一整個機房斷電或者單條跨機房光纖發生故障,即使是主機房故障,整個系統也會自動完成failover,快速恢復數據庫服務,同時因為應用服務器訪問的都是本機房的中間層,因此中間層和應用配置也無需變動,能夠真正實現跨機房的高可用。

因為考慮機房容災,所以這個架構的中間層冗餘較多(其實所有數據庫實例可以共用一套中間層,所以也並不算多),如果對機房容災的要求較低,可以只在一個機房部署LVS和Router,而GroupReplication的從庫可縮減為最小配置兩臺,當主機房異常時,備用機房的數據庫從庫手動設置為單點可用,讀寫域名和只讀域名都手動指向該數據庫實例IP即可。

基於MySQL InnoDB Cluster的MySQL高可用方案

基於MySQLInnodbCluster和LVS的雙機房高可用網絡拓撲圖

3. 壓測結果

使用Router+LVS不會影響數據庫服務器本身性能但會影響整體響應時間,下面的壓測會比較各種場景下各節點對響應時間的影響。

基於MySQL InnoDB Cluster的MySQL高可用方案

無跨機房網絡結構

基於MySQL InnoDB Cluster的MySQL高可用方案

最差情況的2次跨機房網路結構

壓測使用的是sysbench,對原生的測試腳本做了一些調整,耗時指單個語句的平均耗時。40個併發、讀寫4:1、每個查詢平均100邏輯讀。壓測期間系統CPU峰值:數據庫CPU:55% Router CPU:4% LVS CPU:0% net send:50MB/s。

基於MySQL InnoDB Cluster的MySQL高可用方案

根據壓測數據,中間節點(Router、LVS)和跨機房連接均會延長響應時間,導致不同程度的TPS下降,單個query的平均響應時間受影響程度很小,如下:

基於MySQL InnoDB Cluster的MySQL高可用方案

由於響應時間增加極少,而TPS在高併發下最終會達到數據庫的上限,因此這些影響在生產環境完全可以接受。

4. 總結

這套架構全面實現了雙機房高可用、自動Failover、強一致性、讀寫分離、讀庫高可用、讀請求負載均衡,且任何單點異常都可以在3-15秒內完全自動恢復,即使主機房整體異常也只需手動指定Mysql主庫即可恢復讀寫,整體架構可以高效可靠的保障超大併發下的業務穩定,目前此架構已經在洋碼頭的數據庫體系中完美運作。

[1]http://mysqlhighavailability.com/the-king-is-dead-long-live-the-king-our-homegrown-paxos-based-consensus/

[2]http://mysqlhighavailability.com/mysql-group-replication-transaction-life-cycle-explained/


分享到:


相關文章: