咱們知道,POLARDB是一個由多個節點構成的數據庫集羣,一個主節點,多個讀節點。對外默認提供兩個地址,一個是集羣地址,一個是主地址,推薦使用集羣地址,由於它具有讀寫分離功能能夠把全部節點的資源整合到一塊兒對外提供服務。數據庫
用過MySQL的都知道,MySQL的主從複製簡單易用,很是流行,經過把主庫的Binlog異步地傳輸到備庫並實時應用,一方面能夠實現高可用,另外一方面備庫也能夠提供查詢,來減輕對主庫的壓力。架構
雖然備庫能夠提供查詢,但存在兩個問題,一是主庫和備庫通常提供兩個不一樣的訪問地址,應用程序端須要選擇使用哪個,對應用有侵入。二來MySQL的複製是異步的,即便是半同步也沒辦法作到100%強同步,所以備庫的數據並非最新的,有延遲,沒法保證查詢的一致性。app
爲了解決第一個問題,咱們引入了讀寫分離代理,以下圖,對應用程序很是友好。通常的實現是,代理會僞形成MySQL與應用程序創建好鏈接,解析發送進來的每一條SQL,若是是UPDATE、DELETE、INSERT、CREATE等寫操做則直接發往主庫,若是是SELECT則發送到備庫。負載均衡
可是第二個問題——延遲致使的查詢不一致——仍是沒有解決,使用時,就不可避免地會遇到備庫SELECT查詢數據不一致的現象(由於主備有延遲)。MySQL負載低的時候延遲能夠控制在5秒內,但當負載很高時,尤爲是對大表作DDL(好比加字段)或者大批量插入的時候,延遲會很是嚴重。異步
POLARDB是讀寫分離的架構,傳統的讀寫分離都只提供最終一致性的保證,主從複製延遲會致使從不一樣節點查詢到的結果不一樣,好比一個會話內連續執行如下QUERY:spa
INSERT INTO t1(id, price) VALUES(111, 96);
UPDATE t1 SET price = 100 WHERE id=111;
SELECT price FROM t1;
代理
在讀寫分離的下,最後一個查詢的結果是不肯定的,由於讀會發到只讀庫,在執行SELECT時以前的更新是否同步到了只讀庫時不肯定的,所以結果也是不肯定的;由於有這個問題,因此就要求應用程序去適應最終一致性,而通常的解決方法是: 將業務作拆分,有高一致性要求的請求直連到主庫,能夠接受最終一致性的部分走讀寫分離;顯然這樣會增長應用開發的負擔,還會增大主庫的壓力,影響讀寫分離的效果;code
爲了解決這個問題,在POLARDB中咱們提供了會話一致性或者說因果一致性的保證,會話一致性即保證同一個會話內,後面的請求必定可以看到此前更新所產生版本的數據或者比這個版本更新的數據,保證單調性,就很好的解決了上面這個例子裏的問題;blog
在POLARDB的鏈路中間層作讀寫分離的同時,中間層會track各個節點已經apply了的redolog位點即LSN,同時每次更新時會記錄這次更新的位點爲Session LSN, 當有新請求到來時咱們會比較Session LSN 和當前各個節點的LSN,僅將請求發往LSN >= Session LSN的節點,從而保證了會話一致性;表面上看該方案可能致使主庫壓力大,可是由於POLARDB是物理複製,上一篇已詳細介紹過,速度極快,在上述場景中,當更新完成後,返回客戶端結果時複製就同步在進行,而當下一個讀請求到來時主從極有可能已經完成,而後大多數應用場景都是讀多寫少,因此經驗證在該機制下即保證了會話一致性,也保證了讀寫分離負載均衡的效果;資源