微信開源PhxSQL:高可用、強一致的MySQL叢集
作者: 陳俊超(junechen@tencent.com),微信後臺高階工程師,主要負責微信後臺核心模組的分散式架構設計和開發。早期負責微信附近的人,搖一搖,朋友圈,群聊等基礎架構。現專注於PhxSQL等開源專案。PhxSQL作者之一。
責編:錢曙光
PhxSQL開源地址:https://github.com/tencent-wechat/phxsql
PhxSQL是一個相容MySQL、服務高可用、資料強一致的關係型資料庫叢集。PhxSQL以單Master多Slave方式部署,在叢集內超過一半機器存活的情況下,可自身實現自動Master切換,且保證資料一致性。
PhxSQL基於Percona 5.6開發。Percona是MySQL的一個分支,功能和實現與MySQL基本一致。因此本文後續直接把MySQL作為討論物件。
MySQL半同步複製存在缺陷,在Master進行切換的場景下,資料難以保證一致。
- 當舊Master複製失敗時,舊Master和Updated Slave(已收到Binlog的Slave)需要回滾資料。
- 當Master進行切換時,舊Master仍有部分Client進行讀寫。
關於MySQL半同步複製的資料一致性問題可檢視微信後臺團隊公眾號文章MySQL半同步複製的資料一致性探討。
PhxSQL的設計是為了解決MySQL半同步複製的不足,使MySQL叢集在Master切換過程中保證資料的一致。
PhxSQL架構
為了解決MySQL的兩個問題(Binlog複製和Master切換),PhxSQL設計了兩個模組(Phxbinlogsvr、Phxsqlproxy)和一個MySQL外掛(Phxsync)。Phxbinlogsvr負責處理MySQL的Binlog複製和Master管理;Phxsqlproxy負責透傳Client請求到Master;Phxsync外掛負責MySQL和Phxbinlogsvr的互動。 一臺部署了Phxsqlproxy,MySQL和Phxbinlogsvr的機器稱為PhxSQL Node。如圖1。
PhxSQL複製流程
在PhxSQL中,Phxbinlogsvr負責管理MySQL的角色和儲存MySQL的Binlog、Phxbinlogsvr和其管理的MySQL部署在同一臺物理機上。
MySQL Master在Send Event階段不再把Binlog複製給Slave,而是通過Phxsync外掛,把資料複製到Phxbinlogsvr叢集。
MySQL Slave也不再從Master獲取Binlog,而是從本機的Phxbinlogsvr獲取。
Phxbinlogsvr叢集使用Paxos協議進行資料複製。
PhxSQL使用PhxPaxos庫,詳情請檢視微信後臺團隊公眾號文章微信自研生產級paxos類庫PhxPaxos實現原理介紹。
從邏輯上來看,利用Paxos協議進行復制,使Phxbinlogsvr形成一個可靠的日誌儲存。PhxSQL可以看成是為MySQL增加了一個用Paxos實現的可靠Binlog儲存,只要叢集中多數派機器存活,就可以解決半同步複製的回滾問題。如圖3。
分別從Master和Slave的角度來解釋:
1. Master重啟時,通過詢問Phxbinlogsvr(多數派)Pending Binlog是否存在來決定是否需要回滾。如圖4。
2. Slave從本機Phxbinlogsvr能拉取到的Binlog都已經經過Paxos協議成功複製到多數派機器,因此對於Slave來說不存在回滾的問題。
Phxbinlogsvr通過Paxos協議複製資料,很好的解決了MySQL中需要手動回滾Binlog和在大叢集時同時需要回滾Updated Slave上的Binlog的問題。
PhxSQL的Master管理
MySQL多Master同時寫入會導致資料的不一致。如圖5,機器A是舊Master,在收到機器B成為了新Master的訊息之前提交了Transaction 3;而同時機器B已成為新Master,Transaction 3則會留在機器A而未複製到機器B,最終兩機的資料不一致。
MySQL多Master問題的產生,源於機器間無法得知當前Master的狀態,最後導致兩臺機器的資料不一致。
即使使用外部服務(例如zookeeper)也無法解根本問題。
1. 對Master查詢和查詢之後的操作不是原子操作,無法保證操作時的準確狀態(例如機器A向外部服務查詢得知自己是Master,然後執行復制Binlog操作。但期間出現故障導致兩個操作之間停頓了很長時間(譬如1天)。在該期間內Master被切換,使得機器A在執行復制Binlog時,已不再是Master,導致了多Master的情況發生。)
2. Master管理依賴外部服務的穩定性。
多Master問題由於細節太多,暫不在此討論。
PhxSQL自身進行了Master管理,具有以下特點:
1. Master通過Paxos協議投票選出。
2. Master帶有租約,並定時續租。租約過期後,需重新選舉新的Master。
3. 全域性只有1個Master,或者沒有Master存在。
4. 有效拒絕過期Master的非法寫入。
PhxSQL的Master自動切換
PhxSQL實現了舊Master的自動資料回滾和Master管理,使得PhxSQL可以安全地實現Master的自動切換,提供高可用服務。和常見的MySQL切換Master方案不同,PhxSQL在切換Master之後仍然保證叢集內各機資料一致。
PhxSQL自動Master流程如下:
1. Slave機器上的Phxbinlogsvr定期檢查Master是否過期。如果過期轉第2步,否則繼續第1步;
2. Phxbinlogsvr檢查本機MySQL是否已執行完所有Binlog。如果已完成轉第3步,否則繼續第1步;
3. Phxbinlogsvr發起投票選舉新的Master。如果投票成功,提升本機MySQL為Master,關閉readonly開關;否則繼續第1步;
4. 舊Master恢復,本機的Phxbinlogsvr查詢發現已不是Master,切換MySQL角色為Slave,設定從本機Phxbinlogsvr拉取Binlog,並開啟readonly開關。
Phxsqlproxy請求透傳
Phxbinlogsvr解決了多Master同時寫入的問題,使得MySQLClient向舊Master寫入資料會產生失敗。雖然保證了資料的一致性,但仍存在下面2個問題:
1. MySQLClient持續向舊Master寫入資料,從而持續的失敗。(服務不可用)
2. 部分MySQLClient向新Master寫入資料,但其他MySQLClient仍然向舊Master讀取資料,導致讀不到最新的資料。
上述兩個問題都是由於MySQLClient的Master資訊更新不及時;部分Client沒有及時更新,使得有可能產生PhantomRead(兩次讀的結果不一致)。
若Slave機器被訪問,Phxsqlproxy則會把請求透傳到Master機器的Phxsqlproxy。由於PhxSQL Master的全域性唯一性,保證了只存在一臺MySQL被訪問。從而解決了多臺機器同時被讀寫的問題。
PhxSQL效能
使用sysbench工具對PhxSQL和MySQL的半同步複製進行了效能對比。PhxSQL因為增加了Phxsqlproxy,導致讀效能比原生MySQL略低;但由於PhxPaxos的實現比MySQL的半同步更加高效,讓PhxSQL的寫效能比半同步複製更好。
PhxSQL比MySQL讀效能比原生MySQL略低,但寫效能比MySQL半同步複製更好。
讀效能 | 寫效能 | |||
---|---|---|---|---|
Client執行緒數 | QPS | 耗時 | QPS | 耗時 |
200 | 約降低3% | 耗時約增加2% | 約增高25% | 約降低20% |
500 | 約降低13% | 約增加10% | 約增高16% | 約降低10% |
測試環境和結果如下:
機型資訊
CPU : Intel(R) Xeon(R) CPU E5-2420 0 @ 1.90GHz * 24
記憶體 : 32G
磁碟 : SSD Raid10
網路互Ping耗時
Master -> Slave : 3 ~ 4ms
Client -> Master : 4ms
壓測工具和引數
sysbench –oltp-tables-count=10 –oltp-table-size=1000000 –num-threads=500 –max-requests=100000 –report-interval=1 –max-time=200
壓測內容
PhxSQL和半同步複製在Client執行緒200和500的環境下進行下面方式的壓測:
- insert.lua (100%寫)
- select.lua (0%寫)
- OLTP.lua (20%寫)
壓測結果
Client執行緒數:200
insert.lua (100%寫) | ||
---|---|---|
QPS | 耗時 | |
PhxSQL | 5076 | 39.34/56.93 |
MySQL半同步 | 4055 | 49.27/66.64 |
select.lua (0%寫) | ||
---|---|---|
QPS | 耗時 | |
PhxSQL | 46334 | 4.21/5.12 |
MySQL半同步 | 47528 | 4.10/5.00 |
OLTP.lua (20%寫) | ||
---|---|---|
QPS | 耗時 | |
PhxSQL | 25657 | 140.16/186.39 |
MySQL半同步 | 20391 | 176.39/226.76 |
Client執行緒數:500
insert.lua (100%寫) | ||
---|---|---|
QPS | 耗時 | |
PhxSQL | 8260 | 60.41/83.14 |
MySQL半同步 | 7072 | 70.60/91.72 |
select.lua (0%寫) | ||
---|---|---|
QPS | 耗時 | |
PhxSQL | 105928 | 4.58/5.81 |
MySQL半同步 | 121535 | 4.17/5.08 |
OLTP.lua (20%寫) | ||
---|---|---|
QPS | 耗時 | |
PhxSQL | 46543 | 192.93/242.85 |
MySQL半同步 | 33229 | 270.38/345.84 |
注:耗時分別為測試結果的平均耗時/95%分位數耗時,單位ms
總結
PhxSQL解決了MySQL半同步複製中資料回滾和多Master的問題,使其能實現自動Master切換且保證資料一致。PhxSQL因為增加了Phxsqlproxy,導致讀效能比原生MySQL略低;但由於PhxPaxos的實現比MySQL的半同步更加高效,讓PhxSQL的寫效能比半同步複製更好。
附錄:
相關文章
- mysql高可用叢集之MMMMySql
- 超詳細乾貨!Docker+PXC+Haproxy搭建高可用強一致性的MySQL叢集DockerMySql
- redis高可用強擴充套件的叢集方案Redis套件
- 搭建 MySQL 高可用高效能叢集MySql
- 淺談MySQL叢集高可用架構MySql架構
- CoroSync + Drbd + MySQL 實現MySQL的高可用叢集薦ROSMySql
- 高可用的MongoDB叢集MongoDB
- PostgreSQL repmgr高可用叢集+keepalived高可用SQL
- PostgreSQL patroni高可用叢集SQL
- MongoDB高可用叢集搭建MongoDB
- zookeeper 高可用叢集搭建
- Redis叢集與高可用Redis
- MySQL叢集搭建(6)-雙主+keepalived高可用MySql
- MySQL主主複製+Keepalived打造高可用MySQL叢集MySql
- Redis快取高可用叢集Redis快取
- 10、redis哨兵叢集高可用Redis
- 高可用mongodb叢集(分片+副本)MongoDB
- WEB叢集- 高可用服務Web
- 構建MHA實現MySQL高可用叢集架構MySql架構
- mysql主主複製+keepalived 打造高可用mysql叢集薦MySql
- RabbitMQ和Kafka的高可用叢集原理MQKafka
- Oracle的三種高可用叢集方案Oracle
- 高可用的MongoDB叢集-實戰篇MongoDB
- Oracle 的三種高可用叢集方案Oracle
- 高可用Mysql架構_Haproxy+keepalived+mycat叢集的配置MySql架構
- RabbitMQ從零到叢集高可用(.NetCore5.0) -高可用叢集構建落地MQNetCore
- Heartbeat_2.0.3配置MySQL5.0.18為高可用叢集MySql
- 搭建 Kubernetes 高可用叢集
- Redis高可用-主從,哨兵,叢集Redis
- 高可用叢集之corosync+pacemakerROS
- Rabbitmq叢集高可用部署詳細MQ
- [Open Source] RabbitMQ 高可用叢集方案MQ
- 搭建高可用MongoDB叢集(四):分片MongoDB
- 使用pgpool搭建高可用PostgreSQL叢集SQL
- CentOS 7下搭建高可用叢集CentOS
- CentOS 7 下搭建高可用叢集CentOS
- 使用nginx搭建高可用,高併發的wcf叢集Nginx
- MySQL叢集架構:MHA+MySQL-PROXY+LVS實現MySQL叢集架構高可用/高效能MySql架構