嚴格的來講,微信開源的phxsql不是數據庫,而是一個數據庫的插件;前端
傳統的互聯網數據庫結構通常是這樣的:mysql
服務訪問數據庫是經過分片來的:算法
除了這種基於hash的分片,還有一種基於range的分片方式sql
一般,基於range的分片場景下會引入一個新的服務來保存range分片的元信息,列如etcd:數據庫
數據庫鏈接是這樣進行的:後端
第1步, 先監控etcd服務上的range信息變化;微信
第2步, 讀取etcd服務上的range信息;插件
第3步, 接收到sql請求,解析sql語句,根據分片信息決定鏈接哪一個數據庫進行操做;日誌
著名的開源數據庫TiDB就是range來作數據庫的水平拆分;blog
基於hash的數據庫分片如今已經不多用了,由於擴容時很是麻煩;你能夠自行腦補一下,1000臺數據庫的記錄擴展到1500臺,在不中斷業務的狀況下的操做;
上面的內容有點跑題,咱們接下來看看主從複製:
爲了防止某個庫掛掉以後,記錄丟失,有了主從複製
固然,主從複製還能夠知足讀寫分離,減低主庫的負擔
數據庫鏈接的邏輯:
第1步, 解析sql;
第2步, 判斷sql是讀(insert, update, delete)仍是寫(select);
第3步, 落到相應的庫上;
因爲從庫獲取主庫的記錄有延時,因此讀可能會失敗,好比你剛發佈了個帖子,卻不能立刻查到;
或者還有更壞的狀況,你剛發了個帖子,主庫掛了,這條記錄還沒同步到從庫;這樣帖子就丟了;
若是隻是丟了帖子,狀況還不算糟,從新發個帖子就是了;若是是在金融場景下,問題可能就麻煩了,好比下面的場景:
mysql主從複製可能會致使數據不一致,這是問題1;
再看下面的場景,若是數據庫鏈接是基於故障自動切換的,則有可能會產生主庫和從庫同時被寫的問題;
這種場景下,主從庫的數據也會不一致,這是第二個問題;
爲了解決第一個問題,phxsql引入了第一個插件BinLogSvr:
phxsql增長了一個進程BinLogSvr,用來管理mysql日誌;
主庫的邏輯變成了這樣:
第1步, 收到sql請求;
第2步, 準備sql執行;
第3步, 寫入BinLogSvr;
BinLogSvr用paxos協議,將這條日誌複製到mysql集羣中的其餘機器上;
BinLogSvr返回成功;
第4步, Commit數據,返回成功;
從庫的邏輯變成這樣:
取消從主庫獲取binlog;
改爲從本機的BinLogSvr獲取binlog;
因爲BinLogSvr基於paxos協議,binlog到BinLogSvr成功即代表mysql集羣中半數以上的機器已經獲取到最新的日誌,除非半數以上的機器掛掉,纔有可能產生數據不一致;
爲了解決上述的第二個問題,phxsql引入了另外一個插件PhxSqlProxy:
實際上, PhxSqlProxy也是一個進程,對前端,模仿了mysql服務端,對後端,模仿了mysql客戶端,將數據庫鏈接請求平等的對應到後端的mysql服務上;
mysql的主庫由BinLogSvr來選舉,基於paxos算法;
若是有sql請求到來,PhxSqlProxy會向BinLogSvr來查詢當前是否爲主庫,若是是主庫,則將請求傳給本機的mysql服務;若是是從庫,則將請求轉給主庫;
結束;
主庫掛了或者是租約過時,新的主庫選舉是由BinlogSvr來完成的;