談談PhxSQL的設計和實現哲學(下)
開源地址
摘要
前面討論了我們為什麼要做PhxSQL和為什麼這樣做PhxSQL。這裡我們主要談談為什麼不做某些特性。捨得捨得,有舍才有得。CAP告訴我們只能三選二,俗話告訴我們天下沒有免費的午餐。每個特性除了自身提供的功能,也有其代價。為了保證強一致的線性一致性、高可用、serializable級別事務隔離、完全相容MySQL、和最小侵入MySQL,PhxSQL放棄了一些特性。
正文
7. Why Not?
7.1. 為什麼不支援多寫?
多寫想想就很誘人。多寫可以充分利用每臺機器寫時需要的資源。例如某些寫操作可能非常耗費CPU,多寫可以把寫操作分散在各臺機器上,充分利用各個機器的CPU資源,極大提高寫入的效能。多寫使得換主沒有存在的必要,也就沒有換主時可能存在的不可寫時間窗問題。多寫還使得客戶端可以就近寫入,減少跨資料中心寫入帶來的網路延遲。
多寫有兩種:大家熟知的分shard或者組,各shard或者組間並行寫入,以Google Spanner[8]為典型代表;在shard或者組內並行,以Galera和MySQL Group Replication為代表。
7.1.1. 組間多寫
組間多寫是把資料分成多個不相交的shard,每個組的機器負責一個shard 。當一個事務涉及的資料(讀集合和或寫集合)都在某個組時,這種事務稱為本地事務。當一個事務涉及的資料分佈在超過一個組時,這種事務稱為分散式事務。
本地事務可以在本組獨立執行,組之間不需要任何通訊。為了減少事務衝突帶來的效能降低,一般都是由組內leader執行本地事務,通過Paxos等一致性協議保證組內機器的資料一致[8]。各個組間並行執行本地事務,可以極大提高本地型事務的寫效能。
組間多寫最大的阻礙是分散式事務,而分散式事務是非常昂貴的。在SQL的模型中,為了實現read repeatable級別的事務隔離,事務管理器需要檢查兩個併發事務的寫資料集是否衝突;為了達到serializable級別的事務隔離,事務管理器需要檢查兩個併發事務的讀資料集和寫事務集是否衝突[10]。這一般通過嚴格兩階段鎖(strict two-phase locking,嚴格2PL)和/或者多版本併發控制MVCC實現。當這些資料集跨組時,就涉及到跨組的機器通訊。
一個組同時遇到本地事務和分散式事務時,在本組需要根據事務的隔離級別,由事務管理器仲裁執行。
以Google Spanner為例,一個涉及兩個機器組(Spanner中的組是指Paxos組)事務就需要在coordinator leader和non-coordinator-participant leader之間兩次通訊,前者組內還涉及一次Paxos寫操作,後者組內再加兩次Paxos寫操作[8,Sec. 4.2.1 Read-Write Transactions]。當跨機房部署時,機器之間的網路延遲使得通訊代價更加高昂。Spanner為了減少這種昂貴的跨組事務,要求所有資料都必須有Primary key,並且其它資料儘量掛接在Primary key下面,使得事務儘量在一個組內、且由組內leader執行。
7.1.2. 組內多主多寫
組內多主多寫時每個機器都有完整的資料,但這份資料分成不相交的邏輯集合,每個機器負責一個集合的寫入。這臺機器稱為這個集合的主機,這個集合稱為這個主機負責的資料,其它機器稱為這個集合的備機。客戶端將寫操作發到所涉及資料的主機,由主機通過atomic broadcast原子廣播將更新請求傳送給組內所有的機器,包括主機本身[9]。Galera和MySQL Group Replication都是採用這種方法。
圖 3:組內多主多寫架構[9]
原子廣播具有3個特性:
- 如果一臺機器執行一條訊息所帶的更新命令,那麼所有的其它機器都執行這條命令(delivered)。這裡“執行”指的是原子廣播層將訊息交給上層,真實的執行時刻由上層決定。在資料庫中,這個上層一般是併發事務管理器,它決定這些訊息的真實執行順序。
- 所有機器以相同的順序執行命令
- 如果一臺機器成功廣播了一條訊息,那麼最終所有機器都將執行這條訊息
使用原子廣播後,事務的生命週期從prepare->committed/aborted改變為prepare->committing->committed/aborted。
圖 4:事務生命週期狀態轉換[9]
當一個事務只涉及到一個集合的資料時,稱為本地事務,由這個集合的主機的本地事務管理器先使用本地嚴格2PL仲裁,然後將committing狀態的事務通過原子廣播發給其它備機。
當一個事務涉及到多於一個集合的資料時,稱為複合事務(complex transaction)。這個事務所涉及的某個資料集合的主機將committing事務狀態,包括讀集合(如果需要serializable級別隔離。這裡的一個小優化是採用dummy row減少可能極其龐大的讀集合[10])、寫集合、以及committing狀態,通過原子廣播發給全組進行仲裁。Galera和MySQL Group Replication都只是校驗寫集合,因此不支援serializable級別事務隔離[18]。
每臺機器都可以通過本地事務狀態和原子廣播收到的訊息,獨立判定committing事務最終是提交還是終止。這種判定由原子廣播的特性保證全域性一致。
圖 5:Deferred Update Replication和Certification-based Replication事務執行時序[11]
強調一下:在機器通過原子廣播進行資料同步時,事務的最終結果不能在廣播前決定,而是在執行這條訊息依賴的前置訊息及這條訊息後才能決定。這稱為Deferred Update Replication[9][14]推遲的更新複製或者Certification-based Replication[11]。這裡有個重要特點需要注意:只有收到一條訊息的所有前置訊息後,這條訊息和所有未執行的前置訊息才能由事務管理器併發執行。因此,這裡引入了一定的序列化。
原子廣播的突出優點是在低延遲區域網有很高的吞吐率。
但同時原子廣播有不小的按機器個數放大的網路延遲,在非低延遲網路會顯著放大網路延遲。MySQL Group Replication使用的Corosync[16]和Galera[15]支援的Spread[17]都是基於Totem[13]這個成員管理和原子廣播協議。
Totem是個為低延遲區域網設計的協議。在Totem中,所有機器組成一個環(ring)。無論一臺機器是否需要廣播,令牌(token)在機器之間都按照環順序傳遞。只有拿到令牌的機器才可以進行廣播,即發出提交事務請求。因此在下一臺機器收到上一臺機器令牌的網路延遲期間,整個系統處於等待狀態。為了保證Safe Order Delivery,訊息(實際是regular token,不是regular message)需要在環中迴圈兩圈,才能知道是否可以執行,因此,訊息延遲是(4f+3)*RTT/2,其中(2f+1)是機器的數目、f表示容錯的機器數。
在一個典型的兩地三中心部署中,這導致一次事務寫操作延遲極其高昂。例如一地兩中心的網路延遲一般可以控制在2ms(單向),上海-深圳間網路延遲一般是15ms(單向),則一次事務寫操作的網路延遲是64ms!在兩地三中心的配置中,PhxSQL的主和一個備一般分別在一地的兩中心,另一個在異地。在通常情況下,master的Paxos一次寫入只需一個accept,並且只等最快的備機返回。這時PhxSQL的寫延遲只有4ms!
相比Paxos這類協議,原子廣播還有一個缺陷。當任意一臺機器宕機或者網路中斷時,Totem此時會超時,在踢掉宕機的機器、重新確定組成員之前,整個叢集的訊息停止執行,即寫操作暫停。
對於read-only事務,只有去資料集合的主機讀取、或者昂貴地讀取原子廣播Quorum臺機器、或者使用類似Spanner的TrueTime[8]技術讀取任一符合資格的機器,才能保證線性一致性。Galera節點間有延遲,並且只讀事務在本地執行,不支援線性一致性[15]。如果MySQL Group Replication支援線性一致性,請不吝告知。
瞭解基於原子廣播的組內多主多寫模式的原理和優缺點後,使用多寫模式還需要根據業務仔細劃分資料集,儘量減少公共資料的使用,同時處理好自增key的細節問題,以減少事務間的跨機衝突。
PhxSQL建立在開源的PhxPaxos基礎上,感興趣的讀者可以用PhxPaxos方便實現原子廣播外掛,載入到MySQL中,從而支援多寫。
如果不要read repeatable或者serializable級別隔離的事務,例如簡單的key-value操作,同時通過lease機制保證線性一致性,是可以做到高效率多寫的。但這就違反了PhxSQL完全相容MySQL和最小侵入MySQL的原則。
7.2. 為什麼不支援分庫分表?
分庫分表也是個誘人的選擇:可以平行無限擴充套件讀寫效能。分庫分表就是分組,上個小節已經討論了分散式事務的高昂成本。另外,為了保證完全相容MySQL、支援全域性事務和serializable級別事務隔離,不大改MySQL就支援sharding是非常困難的。大改又違反了“最小侵入MySQL”原則,並且可能引入新的不相容性。在應用不要求全域性事務和serializable級別事務隔離情況下,感興趣的讀者可以把PhxSQL作為一容錯的MySQL模組,在上層構建支援分庫分表的系統。因為PhxSQL本身的容錯性,這樣做比在MySQL基礎上直接構建要簡單,無需關心每個sharding本身的出錯。如果以後有需求,PhxSQL團隊也可能基於PhxSQL開發一個分庫分表的新產品。當然,這個產品難以提供PhxSQL級別的相容性。
7.3. 為什麼這麼糾結於serializable級別事務隔離性,read repeatable級別很多時候已經夠用了啊?
我們在設計原則中已經提到,為了完全相容MySQL。我們認為一項好的技術是一項簡單方便使用者的技術,提供符合使用者直覺預期、不用看太多注意事項的技術是我們的體貼。我們很誠懇,也是為了方便使用者。我們不想說PhxSQL完全相容MySQL,然後在不起眼的地方blabla列出好幾頁蠅頭小字的例外。事實上,對於關鍵業務來說,serializable是必要的、read repeatable是不足的。read repeatable有個令人討厭的write-skew異常[12]。
舉個例子。小薇在一個銀行有兩張信用卡,分別是A和B。銀行給這兩張卡總的信用額度是2000,即A透支的額度和B透支的額度相加必須不大於2000:A+B<=2000。
兩個賬戶的扣款函式用事務執行分別是:
A賬戶扣款函式:
sub_A(amount_a):
begin transaction
if (A+B+amount_a <= 2000)
{ A += amount_a }
Commit
B賬戶扣款函式:
sub_B(amount_b):
begin transaction
if (A+B+amount_b <= 2000)
{ B += amount_b }
commit
假定現在A==1000,B==500。如果小薇是個黑客,同時用A賬戶消費300和B賬戶消費300,即amount_a == 400,amount_b == 300。那麼這個資料庫會發生什麼事情呢?
如果是read repeatable級別隔離,sub_a和sub_b都會同時成功!最後A和B賬戶的透支額分別是A=1000+400=1400,B=500+300=800,總的透支額A+B=1400+800=2200>2000,超過了銀行授予的額度!如果不是信用卡的兩筆小消費,而是兩筆大額轉賬,那麼銀行怎麼辦?
如果是serializable級別隔離,則sub_a和sub_b只有一個成功。具體分析有興趣的讀者可以自己完成。
7.4. 為什麼不把顯著提升MySQL效能作為一個主要目標?
事實上,PhxSQL已經顯著提升了MySQL主備的寫入效能。與semi-sync比,在測試環境中,PhxSQL的寫入效能比semi-sync高15%到20%以上。讀效能持平。這是在滿足完全相容MySQL和最小侵入MySQL原則下所能獲得的結果。鑑於PhxSQL對MySQL的改動是如此之小,對效能有高要求的讀者,可以方便地把PhxSQL中的MySQL換成其它高效能版本,獲得更高效能。
7.5. 為什麼編譯時不支援C++11以下標準?
作為熱愛新技術的碼農,我們真的很喜歡C++11中期待已久、激動人心的新特性,例如極大增強的模板、lambda表示式、右值和move表示式、多執行緒記憶體模型等,這將C++帶入了一個新的時代,大大提高了碼農搬磚的速度、編碼的正確性、和程式的效能。有了C++11,PhxSQL的開發效率提高了很多。
8. 與Galera及MySQL Group replication的比較
參見7.1.2小節。
結論
PhxSQL是一個完全相容MySQL,提供與Zookeeper相同強一致性和可用性的MySQL叢集。
感謝大家看完這麼長的一篇文章。希望大家多閱讀PhxSQL原始碼,多提技術性意見,甚至成為原始碼貢獻者!
參考
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
文章出處:微信後臺團隊