全部產品
Search
文件中心

PolarDB:一致性層級

更新時間:Nov 19, 2024

PolarDB提供了最終一致性和會話讀一致性兩種一致性層級,滿足您在不同情境下對一致性層級的要求。

PolarDB架構

PolarDB是一個由多個節點構成的資料庫叢集,一個主節點,多個讀節點。對外預設提供兩個地址,一個是叢集地址,一個是主地址,推薦使用叢集地址,因為它具備讀寫分離功能可以把所有節點的資源整合到一起對外提供服務。

PostgreSQL讀寫分離解決和引入

PostgreSQL具有主從複製簡單易用的特點,通過把主庫的WAL非同步地傳輸到備庫並即時應用,一方面可以實現高可用,另一方面備庫也可以提供查詢,來減輕對主庫的壓力。

雖然備庫可以提供查詢,但存在兩個問題:

  • 問題1:主庫和備庫一般提供兩個不同的訪問地址,應用程式端需要選擇使用哪一個,對應用有侵入。

  • 問題2:PostgreSQL的複製是非同步。用戶端提交commit並且成功之後,資料可能還沒有同步到唯讀節點。因此備庫的資料並不是最新的,無法保證查詢的一致性。

為瞭解決問題1,PolarDB引入了讀寫分離代理。代理會偽造成PostgreSQL與應用程式建立串連,解析發送進來的每一條SQL,如果是UPDATE、DELETE、INSERT、CREATE等寫操作則直接發往主節點,如果是SELECT則發送到唯讀節點。

PolarDB PG讀寫分離WAL

但是問題2,延遲導致的查詢不一致還是沒有解決,使用時就不可避免遇到備庫SELECT查詢資料不一致的現象(因為主備有延遲)。PostgreSQL負載低的時候延遲可以控制在5秒內,但當負載很高時,尤其是對大表做DDL(比如加欄位)或者大批量插入的時候,延遲會非常嚴重。

PolarDB最終一致性和會話一致性

  • 最終一致性:PolarDB採用非同步物理複製方式在主庫和唯讀庫間做資料同步, 在主庫更新後,相關的更新會apply到唯讀庫,具體的延遲時間與寫入壓力有關, 一般在ms層級, 通過非同步複製的方式實現主庫和唯讀庫之間的最終資料一致。

  • 會話一致性:為瞭解決最終一致性會出現的查詢不一致,PolarDB利用自身物理複製速度快的優點,將查詢發給已經更新了資料的唯讀節點,詳細原理請參見實現原理

PolarDB讀寫分離的會話一致性

PolarDB是讀寫分離的架構,傳統的讀寫分離都只提供最終一致性的保證,主從複寫延遲會導致從不同節點查詢到的結果不同,比如一個會話內連續執行以下QUERY:

INSERT INTO t1(id, price) VALUES(111, 96);
UPDATE t1 SET price = 100 WHERE id=111;
SELECT price FROM t1;

在讀寫分離的情況下,最後一個查詢的結果是不確定的,因為讀會發到唯讀庫,在執行SELECT時之前的更新是否同步到了唯讀庫是不確定的,因此結果也是不確定的。因為存在查詢結果不確定的問題,所以就要求應用程式去適應最終一致性,而一般的解決方案是:將業務做拆分,有高一致性要求的請求直連到主庫,可以接受最終一致性的部分走讀寫分離。這樣會增加應用開發的負擔,還會增大主庫的壓力,影響讀寫分離的效果。

為瞭解決這個問題,PolarDB提供了會話一致性或者說因果一致性的保證,會話一致性即保證同一個會話內,後面的請求一定能夠看到此前更新所產生版本的資料或者比這個版本更新的資料,保證單調性,就很好的解決了上面這個例子裡的問題。

實現原理

實現原理

PolarDB鏈路的中介層做讀寫分離的同時,中介層會跟蹤各個節點已經apply了的redolog位點併產生LSN,同時每次更新時會記錄此次更新的位點為Session LSN,當有新請求到來時PolarDB會比較Session LSN 和當前各個節點的LSN,僅將請求發往LSN >= Session LSN的節點,從而保證了會話一致性;表面上看該方案可能導致主庫壓力大,但是因為PolarDB是物理複製,速度極快,在上述情境中,當更新完成後,返回用戶端結果時複製就同步在進行,而當下一個讀請求到來時主從極有可能已經完成,然後大多數應用情境都是讀多寫少,所以經驗證在該機制下既保證了會話一致性,也保證了讀寫分離負載平衡的效果。

一致性層級選擇最佳實務

PolarDB會話一致性,該層級對效能影響很小而且能滿足絕大多數應用情境的需求。

如果您有不同會話間一致性需求的可以選擇以下方案:

使用Hint將特定查詢強制發到主庫。

/*FORCE_MASTER*/ select * from user;