1. 程式人生 > >談談PhxSQL的設計和實現哲學(上)

談談PhxSQL的設計和實現哲學(上)

開源地址

摘要

PhxSQL是一個提供Zookeeper級別強一致和高可用的MySQL叢集。PhxSQL完全相容MySQL,建立在簡單可邏輯證明的一致性模型之上,架構、部署、運維簡單。文章還討論了PhxSQL與相關技術方案的區別,並比較了各自的優缺點。

文章比較長,正文分成上下兩章。上章主要討論why,即我們為什麼要做PhxSQL以及為什麼這樣做。下章著重探討why not,即我們為什麼不支援若干特性,例如多主多寫和分庫分表,及與Galera和MySQL Group Replication的比較等。

正文

PhxSQL[22]釋出以來,受到很多關注。作為熱愛技術的碼農,我們感謝大家的關心和支援,歡迎一切基於技術出發點的討論。“Show you the code”之後,我們在這裡談談PhxSQL的設計和實現哲學,也同時回答大家提出的一些疑問。

1. PhxSQL是什麼?

PhxSQL是一個通過Paxos保證強一致和高可用的的MySQL叢集。PhxSQL建立在Paxos的一致性和MySQL的binlog流水基礎上。主要原理簡單來說:

  1. Paxos選出主機
  2. 主機把本機MySQL設定成可寫的MySQL主機,在MySQL寫binlog流程中攔截binlog流水、傳送到Paxos,形成全域性的binlog流水
  3. 備機把本機的MySQL設定成只讀的MySQL備機,MySQL備機從全域性binlog中拉取流水,重放和執行,從而主備MySQL一致
  4. 針對常見的業務場景,PhxSQL提供兩個服務埠:強一致讀寫埠(ReadWritePort)和只讀埠(ReadonlyPort);對資料要求強一致的業務,通過ReadWritePort來讀寫;只要求能讀取但不要求最新資料的讀請求(比如一些定時對賬業務),可以通過ReadonlyPort來讀取

只要有多於一半機器工作和互聯,PhxSQL就可以正常工作。

PhxSQL設計

2. PhxSQL的”強一致“和”高可用“是什麼級別?

很多MySQL叢集方案都宣稱強一致和高可用。PhxSQL這方面有什麼不同?

大家熟知的Zookeeper提供強一致和高可用。一致性有很多級別,從強到弱分別是:Strict(嚴格一致性),Linearizable(線性一致性)[1],Sequential(序列一致性)[2],Causal(因果一致性),Eventual等。具體定義請參見參考文獻。嚴格一致性只是一個理論模型。根據相對論,由於資訊傳播的速度不可能高於光速,嚴格一致性在實際中幾乎無法實現。線性一致性的理論定義很複雜,不太嚴謹直觀地講,就是任何一個客戶端都可以讀到別的客戶端寫入的最新內容。這也是大家通常理解的強一致。

Zookeeper的強一致指“線性一致性”[3]。高可用是說只要多於一半機器工作和互聯即可在保證線性一致性的質量下正常工作。PhxSQL的強一致是指“線性一致性”,高可用是指只要多於一半機器工作和互聯即可在保證線性一致性質量下工作。即,

PhxSQL提供和Zookeeper相同的強一致性和高可用性!

PhxSQL提供和Zookeeper相同的強一致性和高可用性!

PhxSQL提供和Zookeeper相同的強一致性和高可用性!

重要事情說三遍:)。大家可以把PhxSQL當Zookeeper使用,例如用來選主!

在資料庫事務隔離方面,PhxSQL支援最高級別的serializable。在效能方面,PhxSQL提供明顯優於MySQL半同步的寫效能和幾乎相同的讀效能[22]。

細心的讀者可能注意到,和通常的“高可用、強一致”說法順序相反,這個小節的標題中,“強一致”有意放在了“高可用”的前面。在這裡需要澄清一個誤區。當談到高可用時,有時會有意無意忽略或者降低一致性。嚴格意義上來講,可用性和一致性必須一塊討論,滿足一致性要求前提下的可用性才有意義。打個不嚴謹的比方,一致性就像汽車的“安全性”,可用性就是汽車的“可用性”。如果一輛車號稱“可用性”很好,可以連續工作10年,但從來不提“安全性”,那麼這輛車的品質是值得懷疑的。

3. 為什麼要做PhxSQL?

雖然有很多NoSQL、NewSQL系統、以及多主多寫MySQL叢集、支援分庫分表的MySQL叢集,MySQL傳統主備同步方案仍然具備很多新系統難以企及的優點。MySQL主備在主機上支援完整SQL、全域性事務、以repeatable read和serializable級別的事務隔離,在金融、帳號等關鍵業務中有巨大的價值。同時,現有複雜MySQL應用遷移到新的非相容系統成本也很高。

但是MySQL傳統主備方案也有其缺點。最明顯的就是主機故障後的自動換主和新舊主資料一致性(以及衍生的換主後主備一致性、各個備機之間一致性,這裡就不詳加討論了),即所謂的一致性和可用性。

為了解決這個問題,有傳統流派:用Zookeeper、etcd、或者其它第三方來檢測心跳、選主、和切換。改造MySQL client讓其能感知新的主機。或者為了能讓傳統MySQL client不加修改就能感知新的主機,部署MySQL代理伺服器,讓其將連到自身的MySQL client請求透明轉發給新的主機。為了減少主備間資料的落後,從而降低舊主機故障、某臺備機被提升成新主機時,新舊主機之間、新主機和其它備機之間的差異,很多方案在主備同步機制上做了很多有益的工作。例如semi-sync等待多數派備機應答,通過優化執行緒和網路、主備多通道、備機並行執行binlog流水等儘量減少主備之間差異。如果主備間任何時刻都完全一致,那麼任何時刻換主都是強一致的。這句話的另外一個意思是,如果無法保證主備間任何時刻完全一致,那麼當有持續不斷的更新時,任何時刻的換主都是無法保證強一致的。

傳統流派另外一個分支就是將MySQL本地磁碟換成更高可靠性的SAN,當MySQL主機故障時,將SAN掛接到備機上提供服務。而當SAN故障時怎麼辦?當需要跨機房部署時怎麼辦?

意識到傳統流派的侷限性,新出了Galera和MySQL Group Replication等。除了宣稱提供強一致性和高可用性外,還支援master-master多點寫入等誘人新特性。

世界上目前已知的經過理論證明和實際檢驗的一致性演算法屈指可數:兩階段提交two-phase commit (2PC)、Paxos[4]、Raft[5]、Zookeeper Atomic Broadcast (ZAB)[3]、Viewstamped Replication[5]等。2PC雖然可以保證一致性,但在主機故障時無法工作,存在可用性問題。目前被工業界廣泛認可和應用的是Paxos和Raft,2PC一般在前兩者幫助選主下使用。這裡的一個小建議就是:如果一個分散式系統宣稱支援線性一致性級別的強一致和高可用,請先檢查它使用的一致性演算法。如果是新演算法,請檢查它的形式化證明或者邏輯證明。

因此,為支援線性一致性和高可用,同時完全相容MySQL,我們在MySQL的基礎上應用Paxos,設計和開發了PhxSQL。

4. PhxSQL的設計原則是什麼?

從實際需求出發,除了前述強一致、高可用、完全相容MySQL這3個明顯、必須的設計原則,我們還提出以下3原則。

4.1. 簡單可邏輯證明的一致性模型

這可能是明顯區別PhxSQL和其它方案的一個特點。一個經過邏輯證明的模型才是可靠的,一個建立在可靠模型基礎上的系統也才是可信賴的。PhxSQL一致性模型建立在兩個前提上:

  1. Paxos保證一致性。這個大家都可以接受。
  2. 各個MySQL的binlog流水一致,則各個MySQL機器之間資料“一致”。這個假設小有爭議。例如即使binlog流水一致,由於不同的binlog格式、備機重放流水的不同配置,也會導致主備之間、不同備機之間的資料產生不同級別的“不同”,例如一條和當前時間相關的insert操作。這種不一致有些應用可以容忍,有些則不能。在這裡,PhxSQL保證流水一致,而把格式和配置的自由留給應用和DBA根據具體場景確定。在最嚴格的配置下,binlog一致,則資料一致。

在這兩個前提下,PhxSQL的一致性模型通過Paxos,使得主機寫入Paxos的binlog流水與備機從Paxos里拉取的binlog流水一致,從而保證MySQL資料的一致性。詳細證明過程我們將另外提供。模型和證明過程都很簡單,大家在讀完原始碼後也可以嘗試:)。

但即使模型正確,PhxSQL正確實現了這個模型嗎?用通俗的話講,沒有bug。碼農都知道這是個巨大的挑戰。從一個演算法和模型到正確的實現之間差距是巨大的。例如,正確實現Paxos挑戰就很大[7]。為了儘量減少bug,我們選擇了簡單和易理解同時應用廣泛的Paxos作為一致性協議。為了實現一個“生產”級別的Paxos,三位主要碼農各自獨立實現了Paxos,在各自測試完正確性後,三套Paxos之間作為一組Paxos的獨立節點互操作檢驗正確性,最後再集體實現一個發行版本PhxPaxos[21]!除了單元測試、系統測試外,測試環境還隨機高頻率獨立重啟機器、對網路包進行亂序、延遲、重複等以對系統進行充分測試。

有讀者可能問,Paxos慢且網路延遲大,PhxSQL為什麼不實現一個“優化”版?Paxos有各種版本,例如Fast Paxos[19]、EPaxos[20]。但這些都是Paxos,遵循Paxos的基本操作,所作的改變,都做了嚴格的形式化或者邏輯證明。PhxPaxos嚴格遵照Paxos演算法[4]實現,沒有做任何改變或者“優化”。PhxPaxos的正常寫操作的網路延遲是一個網路RTT,已經是任何演算法理論上能達到的最快速度。

現在,對於PhxSQL來說,切換主機是一件很平常和容易的操作,就像往MySQL裡插入一條資料一樣平常和容易。

4.2. 最小侵入MySQL原則

MySQL是個巨大的快速演進的生態系統,保證PhxSQL中的MySQL與官方MySQL的相容性與可升級性是必須的。這使得MySQL應用可以快速遷移到和執行在PhxSQL上。這也使得PhxSQL可以迅速響應官方MySQL的升級,將PhxSQL中的舊版本MySQL升級到新的官方MySQL,從而獲得新的特性、效能、穩定性、和安全性提升。

這就要求PhxSQL中的MySQL對官方MySQL改動儘量少。實際上,PhxSQL版MySQL只更改了三個小地方:修改了binlog外掛介面中一個函式的引數;在MySQL啟動時新增了一個外掛函式用於檢查MySQL本地的binlog檔案,在MySQL協議中透傳了真正的客戶端IP以相容授權功能(如果應用不需要可以不修改)。這幾個改動是如此小,且涉及的是幾乎穩定不變的流程,使得PhxSQL中MySQL跟隨官方MySQL升級可以無縫完成。實際上,我們正和MySQL社群溝通,希望把這幾處修改併入官方版本,從而使得PhxSQL以後可以完全使用官方版本MySQL,也使得更多人可以方便採用PhxSQL。

PhxSQL

(a)
MySQL

(b)

圖 2:PhxSQL對MySQL的關鍵修改。(a)是MySQL。(b)是PhxSQL中的MySQL。PhxSQL修改了after_flush這個函式的引數,新增了在MySQL啟動時呼叫的before_recovery這個函式。

也正是因為這個原因,我們沒有因為可以減少模組個數而把PhxSQLProxy、PhxBinlogSvr放到MySQL程序內。為了保證和應用最廣泛的MySQL單機版相容,也沒有在事務層和儲存層介入或修改。

4.3. 簡單的架構、部署、和運維

在滿足要求的前提下,簡單的架構有很多好處,例如開發、維護、診斷、維護、可靠性等等都變得容易。PhxSQL只有3+1個模組。PhxSQL中的MySQL是必須的。PhxBinlogSvr負責全域性binlog儲存和同步、選主、叢集成員管理等關鍵功能。在很多MySQL主備叢集方案中,使用Zookeeper、etcd、心跳檢測、Agent等承擔選主的功能。PhxSQLProxy則作為傳統MySQL client訪問PhxSQL中MySQL服務的代理,使得PhxSQL的換主操作對於傳統MySQL client透明。在其它叢集方案中,一般也是通過代理MySQL proxy、或者虛擬閘道器VIP,向傳統MySQL client遮蔽叢集的換主操作,提供透明訪問。可選模組是PhxSQL client lib,它修改了MySQL client庫中的連線初始化函式,允許傳入一個叢集的PhxSQLProxy列表,從而在一個PhxSQLProxy沒有響應時、自動訪問其它可用PhxSQLProxy,進一步提高可用性。開發人員可以直接連結PhxSQL client lib。

PhxSQL的部署和運維都很簡單。在部署時,只要在目標機各自裝好PhxSQL,在配置中指定叢集的機器的IP列表,PhxSQL即可執行。換主這個操作已經從運維層面轉移到PhxSQL正常的工作流程。通常MySQL叢集中換主後可能需要人肉檢查資料一致性、人肉“閃回”(這可能違反一致性保證,導致“幻讀”);無法”閃回“導致必須清除某臺MySQL,重新拉取資料備份,和追流水等。這些耗時、繁重、易錯的操作在PhxSQL中已經完全不需要。

至於熱升級和熱變更叢集成員更簡單。PhxSQL支援rolling-update,可以逐步升級每臺機器。變更叢集成員是指往叢集新增機器、撤出機器、和替換機器(原子操作)。在保證強一致和高可用前提下,熱變更(不停服變更)是非常困難的。PhxSQL通過在Paxos中實現成員變更解決了這個難題。PhxSQL提供了一個變更操作命令。當在新機器安裝和啟動PhxSQL後(要求MySQL已經載入一份較新的資料備份),可以在現有叢集中一鍵將新機器引入、剔除一臺舊機器、或者同時做兩者。這三種操作都是原子操作!新機器會自動追流水。想想看,相當於Zookeeper支援熱變更成員,是不是很令人激動的特性?

PhxSQL由於在同步層使用Paxos,天然支援多資料中心、多機房部署,兩地三中心這種部署更是不在話下。對於PhxSQL來說,多資料中心和多機房部署與機房內部署沒有區別。PhxSQL的效能取決於多數派機器之間的網路延遲。

5. 為什麼要開源?

作為熱愛技術的碼農,我們相信開源的技術可以使得這個世界更美好。從我們日常開發使用的Emacs/Vim、GCC、GDB,間接為大眾提供社交、電子商務、資訊服務的Linux、Apache、MySQL、PHP,到大眾每日使用來溝通和娛樂的Android等,開源是整個網際網路的基石,為全世界提供許多關鍵不可或缺的基礎服務。我們充分享受了開源帶來的技術進步、經濟發展、和社會前進,我們也希望開源的PhxSQL可以回饋社群,幫助更多有需要的人。

另外,我們希望通過開源更好地改進PhxSQL。我們歡迎技術性討論和志願者提交修改。我們承諾開源的PhxSQL會一直更新。除了一些和內部運維支撐系統進行整合的功能(PhxSQL把這些功能抽象成外掛,我們針對內部運維支撐系統實現了這些外掛),開源版和內部版本將保持一致。

6. PhxSQL的侷限性

在一個不完美的世界裡,完美是不存在的。我們很坦誠指出PhxSQL存在的兩個侷限:

6.1. MySQL主機在執行SQL DDL命令(例如建庫和建表命令)時可能存在一致性風險。

由於MySQL的innodb引擎不支援DDL回滾,如果主機在innodb已經commit這條DDL命令,但是這條命令的binlog還沒到達PhxSQL的攔截點前宕機,則這條DDL binlog會在全域性binlog中缺失,從而備機也不會收到這條binlog。而為了保證線性一致性、serializable級別事務隔離、及“最小侵入MySQL”原則,我們也不想修改MySQL原始碼,提前截獲DDL命令。考慮到DDL命令頻度較低,我們後續準備在PhxSQLProxy加入檢查和後續審計告警。也歡迎大家提出更好方案。

6.2. 在寫入請求量很大的系統中,MySQL備機流水可能落後較多;如果這個時候主機宕機,備機暫時無法提升成新主機,造成系統在一段時間內不可寫。

為了保證線性一致性,對於要求讀取最新資料的請求(通過ReadWritePort發起的讀請求)也將失敗;需要等至少一臺備機追完流水,被提升為主機才能響應讀取最新資料的請求。對於不需要讀取最新資料的請求(通過ReadonlyPort發起的請求),可以從任意備機執行,但不保證線性一致性。(注意:PhxSQL保證無論MySQL主機流水領先MySQL備機多少,MySQL主機binlog流水和全域性binlog流水是一致的,不會導致資料丟失和破壞線性一致性。)

MySQL備機追流水落後是基於binlog複製這種模式的一個潛在問題。事實上,不僅MySQL主備,任何一個多副本系統,只要每個寫操作不等待所有副本返回,都會出現類似的有些副本落後的問題;而那些等待所有副本返回的模式,在耗時和可用性方面又存在問題。可喜的是MySQL 5.7版本實現了並行複製機制,顯著地提高了備機追流水的效能。PhxSQL將很快支援MySQL 5.7,對於寫入請求量很大的場景也可以很大程度上避免備機追流水落後的情況。

談完why,敬請期待《PhxSQL設計和實現哲學》的下章:why not,即我們為什麼不支援若干特性,例如多主多寫和分庫分表,及與Galera和MySQL Group Replication的比較等。

謝謝閱讀!

參考

1. M.P. Herlihy and J. M. Wing. Linearizability: a correctness condition for concurrent objects. ACM Transactions on Programming Languages and Systems (TOPLAS), Volume 12 Issue 3, July 1990, Pages 463-492.

2. L. Lamport. How to make a multiprocessor computer that correctly executes multiprocess programs. IEEE Trans. Computer. C-28,9 (Sept. 1979), 690-691.

3. P. Hunt, M. Konar, F. P. Junqueira, and B. Reed. ZooKeeper: wait-free coordination for Internet-scale systems. USENIXATC’10, 2010.

4. L. Lamport. Paxos Made Simple. ACM SIGACT News (Distributed Computing Column) 32, 4 (Whole Number 121, December 2001) 51-58.

5. D. Ongaro and J. Ousterhout. In search of an understandable consensus algorithm. USENIX ATC ’14, 2014.

6. B. M. Oki and B.H. Liskov. Viewstamped replication: a New primary copy method to support highly-available distributed systems. PODC’88, 8-17, 1988.

7. T. Chandra, R. Griesemer, and J. Redstone. Paxos made live – an engineering perspective. PODC’07, 2007.

8. J. C. Corbett, J. Dean, M. Epstein, and etc. Spanner: Google’s Globally-Distributed Database. OSDI’12, 2012.

9. F. Pedone, R. Guerraoui, and A. Schiper. The database state machine approach. Journal of Distributed and Parallel Databases and Technology, 14:71–98, 2002

10. V. Zuikeviciute and F. Pedone. Revisiting the database state machine approach. VLDB Workshop on Design, Implementation, and Deployment of Database Replication. 2005.

11. http://galeracluster.com/documentation-webpages/certificationbasedreplication.html. Visited at 2016/9/5.

12. https://en.wikipedia.org/wiki/Snapshot_isolation. Visited at 2016/9/5.

13. Y. Amir, L. E. Moser, P. M. Melliar-smith, D. A. Agarwal, and P. Ciarfella. The totem single ring ordering and membership protocol. ACM Transactions on Computer Systems. 13 (4): 311–342.

14. http://downloads.mysql.com/presentations/innovation-day-2016/Session_7_MySQL_Group_Replication_for_High_Availability.pdf. Visited at 2016/9/5.

15. http://galeracluster.com/documentation-webpages/architecture.html. Visited at 2016/9/5.

16. http://corosync.github.io/corosync/. Visited at 2016/9/5.

17. http://www.spread.org/. Visited at 2016/9/5.

18. http://galeracluster.com/documentation-webpages/isolationlevels.html. Visited at 2016/9/5

19. L. Lamport. Fast Paxos. Technical Report, MSR-TR-2005-112.

20. I. Moraru, D. G. Andersen, and M. Kaminsky. There is more consensus in egalitarian parliaments. SOSP’13, 2013.

21. https://github.com/tencent-wechat/phxpaxos.

22. http://mp.weixin.qq.com/s?__biz=MzI4NDMyNTU2Mw==&mid=2247483783&idx=1&sn=a2d6e589f1f591ded7703eb74aefccbe. Visited at 2016/9/5.

文:mingchen

文章出處:微信後臺團隊