閱讀751 返回首頁    go 阿裏雲 go 技術社區[雲棲]


數據庫高可用和分區解決方案-MySQL 篇

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1
許春植(Luocs)

(阿裏巴巴高級數據庫管理員,7年以上數據庫運維管理經驗,擅長MySQL、Oracle及MongoDB數據庫,目前主要研究並建設MongoDB一套完整的運維體係)

編輯手記:感謝許春植授權獨家轉載其精華文章,這是係列文章之一,與大家分享其個人學習與經驗總結,編輯時略有修訂與節略。也歡迎讀者朋友向我們投稿。


首先我們看一下數據庫以及常看到的 HA 以及分布式架構方案:

數據庫類型

架構方案

架構類型

MySQL

Keepalived+MySQL Replication

HA


MHA+MySQL Replication

HA


Febric

HA/Sharding


Other

HA/Sharding

Oracle

MAA / Sharding (12.2)

HA / Sharding

MongoDB

Replica Set

HA


Sharding

Sharding

Redis

keepalivied + MS

HA


Sentinel + MS

HA


Twemproxy

Sharding


# 本次主要討論這些架構的實現原理,可以挖掘這些架構不足的地方在哪裏,如何去改善等等。首先,我們推薦先閱讀何登成的《數據一致性-分區可用性-性能——多副本強同步數據庫係統實現之我見》一文。文章前麵就有我們所關心的四個問題:

問題一:數據一致性。在不使用共享存儲的情況下,傳統 RDBMS(例如:Oracle/MySQL/PostgreSQL 等),能否做到在主庫出問題時的數據零丟失。

問題二:分區可用性。有多個副本的數據庫,怎麼在出現各種問題時保證係統的持續可用?

問題三:性能。不使用共享存儲的 RDBMS,為了保證多個副本間的數據一致性,是否會損失性能?如何將性能的損失降到最低?

問題四:一個極端場景的分析。

在這裏,我們基本結合著第一和第二個問題來討論本次的話題,數據庫的高可用和分區解決方案。


數據一致性分為強一致性和弱一致性,其中弱一致性裏包含我們在 NoSQL 中常聽到的最終一致性。選擇強一致性或者弱一致性,很大程度上取決於業務類型和數據庫類型,比如:阿裏淘係電商大量使用 MySQL 數據庫保證數據強一致,比如阿裏螞蟻係金融通過 Oceanbase 數據庫保證數據強一致,而像新浪微博則選用 Redis 數據庫無需保證數據強一致。


從上麵數據庫中關係型數據庫 MySQL 和 Oracle 都是基於 ACID 的,並且采用WAL(Write-Ahead-Logging)技術,保證事務日誌先刷磁盤。MySQL 有 binlog 日誌,Oracle 則有 Read Log,MongoDB 雖是 NoSQL,但比較特殊,其同步有核心依賴 Oplog。在主備複製關係中,MySQL 有半同步複製,Oracle 則擁有最大保護模式的 DataGuard 都能保證數據的強一致,MongoDB 可以通過 getLastError 命令來保證寫入的安全,但其畢竟不是事務操作,無法做到數據的強一致。


下麵來看看上麵列出的架構,首先看 MySQL 的方案,我們逐個討論。

1Keepalived+MySQL Replication

簡單畫出來如下圖所示,我們通過開源 HA 軟件 Keepalived 來實現高可用,DB 的話可以選擇 MySQL MM 或者 MS 架構,個人更建議使用 MM架構,因為 MS 架構在一次切換之後需要重做同步,而 MM 則大部分情況下不用重做,除非出現數據不一致現象。這種架構讀寫壓力都在 VIP 所在的一端,當然我們完全靈活地將部分讀壓力放到另一端,比如手動查詢或者可用性不太敏感的讀程序,大家要考慮清楚備機是沒有高可用的保護的。


640?wx_fmt=png&wxfrom=5&wx_lazy=1


一般在如下情況下將會觸發 Keepalived 進行一次 HA 切換:

①  當前主服務器宕機;

②  當前主服務器 Keepalived 本身出現故障;

③  當前主庫出現故障;


640?wx_fmt=png&wxfrom=5&wx_lazy=1


Keepalived 進行 HA 切換,VIP 將會漂移到備機上,應用連接都是通過 VIP 接口來進行,所以可以說對業務是透明的操作。


但這裏還是存在一些我們需要考慮的問題,比如發生第二種情況,當前主服務器上 Keepalived 本身出現故障導致 Keepalived 進行 HA 切換,這時候 DB 是正常的,如果有長任務掛在那裏是有問題的,正常我們應該是 kill 掉這些 Thread,應用配合重新在新庫上執行一遍。


另外,如果 MySQL 采用異步同步,那還需要考慮意外宕機時造成數據丟失的問題,通常是後續需要進一步處理,可以手動也可以自動化掉。


我們在看看使用中可能會遇到的場景,業務在這環境上正常運行一段時間,在某一時刻備機上的 Keepalived 本身出現故障而進程退出,但因欠缺監控導致沒人知曉,過一段時間主機也出現問題觸發 HA 切換,但這時候已無心跳關係,VIP 無法進行漂移,直接影響業務。這種問題在監控不到位或者監控疏漏的情況之下經常發生,後果也比較嚴重,所以稱職的 DBA 務必做好監控,而且保持對告警的敏感度


還有一種場景是采用 MySQL MS 架構時,業務正常運行一段時間之後進行了一次 HA 切換,VIP 漂移到備機上,原 MS 同步關係遭到破壞,DBA 在未知情況之下把原主庫的 Keepalived 進程恢複,業務再運行一段時間之後再做了一次 HA 切換,VIP 漂移到最原始的主庫上,這就活脫脫產生了數據丟失,如果該問題發現很晚,那 DBA 就遭罪了,不光影響業務,修補數據都使得 DBA 瘋掉!


最後我們拋出一個問題,因網絡問題導致 HA 的心跳中斷,這時候會是怎樣的情況? 該問題留給大家自己思考。


2MHA+MySQL Replication


640?wx_fmt=png&wxfrom=5&wx_lazy=1


MHA 有個監控管理節點,該節點可管理多套 MySQL 集群,如果 Master 遇到故障,MHA 就觸發一次 Failover,候選的主節點會提升為主庫,其他 slave 節點重新 Change master 到新主庫,其中通過在配置文件裏設置優先級來確定候選主節點。


MHA 進行 Failover 過程:


①  檢測到 Master 異常,進行一係列判斷,最後確定 Master 宕掉;

②  檢查配置信息,羅列出當前架構中各節點的狀態;

③  根據定義的腳本處理故障的 Master,VIP漂移或者關掉mysqld服務;

④  所有 Slave 比較位點,選出位點最新的 Slave,再與 Master 比較並獲得 binlog 的差異,copy 到管理節點;

⑤  從候選節點中選擇新的 Master,新的 Master 會和位點最新的 Slave 進行比較並獲得 relaylog 的差異;

⑥  管理節點把 binlog 的差異 copy 到新 Master,新 Master 應用 binlog 差異和 relaylog 差異,最後獲得位點信息,並接受寫請求(read_only=0);

⑦  其他 Slave 與位點最新的 Slave 進行比較,並獲得 relaylog 的差異,copy 到對應的 Slave;

⑧  管理節點把 binlog 的差異 copy 到每個 Slave,比較 Exec_Master_Log_Pos 和 Read_Master_Log_Pos,獲得差異日誌;

⑨  每個Slave應用所有差異日誌,然後 reset slave 並重新指向新 Master;

⑩  新 Master reset slave 來清除 Slave 信息。


MHA 還支持在線切換,過程簡化如下:


①  核實複製配置並識別出當前的 Master;

②  識別出新的 Master;

③  拒絕當前主寫入;

④  等待所有的 SLAVE 追上數據;

⑤  新的 Master 開啟寫入;

⑥  其他 Slave 全部指向新的 Master。


640?wx_fmt=png&wxfrom=5&wx_lazy=1


MHA 能夠保證主庫出現異常的時候可以正常切換,但它卻不保證 Slave 的問題,如果你的應用直連 Slave 進行隻讀,當 Slave 出現故障的時候業務會受到影響。


我們可以在 Slave 節點之上加一層 SLB 層,也就是做一下負載均衡,如下:


640?wx_fmt=png&wxfrom=5&wx_lazy=1


MySQL 複製選擇異步還是半同步,這個問題在上麵已經討論過,如果想不丟失數據,就選擇半同步複製。


另外,我們思考一個問題,管理節點故障會產生什麼影響?如何保護管理節點?其宕機不可恢複的情況下如何處理?


3Fabric


Fabric 是 Oracle 自己推出的一款產品,可以實現 HA 和 Sharding 解決方案。Fabric 的功能還是蠻吸引人的,它的自動 Failover,讀寫分離以及自動分片等這些特性在數據庫架構中最為關注的特性。但畢竟是一個新興產品,投入生產使用經驗很少,暴漏出的問題也不多,所以在核心業務上使用 Fabric 還是有一定的風險。


640?wx_fmt=png&wxfrom=5&wx_lazy=1


Fabirc 架構裏有幾個組件,

Fabric-aware Connectors

● Python, PHP, and Java(Connector/Python、Connector/PHP、Connector/J)

● Enhanced Connector API

MySQL Fabric Node

● Manage information about farm

● Provide status information

● Execute procedures

MySQL Servers

● Organized in High-Availability Groups

● Handling application data


應用都會請求 Fabric 連接器,然後通過使用 XML-RPC 協議訪問 Fabric 節點, Fabric 節點依賴於備用存儲 (backing store),其實就是 MySQL 實例,存儲整個 HA 集群的元數據信息。連接器讀取 backing store 的信息,然後將元數據緩存到 cache,這樣做的好處就是減少每次建立連接時與管理節點交互所帶來的開銷。


640?wx_fmt=png&wxfrom=5&wx_lazy=1


Fabric 節點可管理多個 HA Group,每個 HA Group 裏有一個 Primary 和多個 Secondary(slave),當 Primary 異常的時候會從 Secondary 中選出最合適的節點提升為新 Primary,其餘 Secondary 都將重新指向新 Primary。這些都是自動操作,對業務是無感知的,HA 切換之後還需要通知連接器更新的元數據信息。Fabirc 的讀寫分離是怎麼做到的?其實還是借助連接器,根據應用的請求類別選擇發送給 Primary 還是 Secondary,如果是寫操作,連接器就路由到 Primary,而如果是讀操作,會以負載均衡方式發送給活躍的 Secondary。


在這裏我們想一個問題,如果 Fabric 節點出現故障會是怎樣的情況? 其實很簡單,如果 HA Group 沒有因故障而產生任何變化,進而元數據信息不變,那麼連接器依然會正確的路由請求,因為連接器已緩存過元數據信息。但一旦 HA Group 裏出現故障,比如 Primary 或者 Secondary 失敗,前者會導致自動 failover 不會產生,進而影響數據庫的寫入,後者則部分讀請求將會失敗。所以監控並管理好 Fabric 節點是非常重要的。


640?wx_fmt=png&wxfrom=5&wx_lazy=1


Fabric 另一個主要特性是分片,Fabric 支持自動分片,目前 Fabric 支持兩種類型的分片 — HASH 和 RANGE,其中 RANGE 方法要求拆分字段屬性為數字型。

應用訪問數據庫還是依賴連接器,並且必須指定片鍵。在分片的場景中,連接器會起路由分發的作用。


為保安全,強烈建議生產環境中每個分片都采用 HA Group。


真實的環境中,並非所有的表都需要拆分,因此 Fabric 還會創建一個全局組 (Global Group),裏麵存放所有全局表 (Global Table),而每個分片都將會存放全局表的副本,這樣做的好處就是方便了拆分表和非拆分表的 JOIN 操作。如果應用對全局表進行更新,連接器將會把請求發到全局組,全局組又將自己的變化同步到各個 HA Group。


640?wx_fmt=png&wxfrom=5&wx_lazy=1


分片的大致工作流我們了解到了,我們還需關心其穩定性以及性能,因為目前還沒在生產環境中真正使用過,這個問題先掛在這裏。


4Other


除了上麵介紹的方案之外,還有非常多的高可用解決方案,比如 MMM、Galera、DRBD+Pacemaker+Corosync、Heartbeat+DRBD 等等,而分庫分表的話可以使用淘寶非常知名的 TDDL。


當然,如果條件允許也完全可以自己開發出一套強大的HA軟件和中間件,或者對上述開源軟件進行二次開發,隻不過我們需要在開發之初就將規模化的成分加入進去,要知道我們開發出來的產品不應該僅限於某幾個場合或者某幾種條件之下,而應充分體現大眾化,就像是可插拔的 API,適應大多數場景,在規模化運維環境之下發揮良好作用。


本文出自數據和雲公眾號,原文鏈接


最後更新:2017-07-17 18:04:20

  上一篇:go  Clouder—構建企業級數據分析平台-墨羽@袋鼠雲
  下一篇:go  細致入微:Oracle RAC DRM引起性能問題案例一則