節點
Citus
是一種 PostgreSQL
擴展,它允許數據庫服務器(稱為節點)在“無共享(shared nothing)”
架構中相互協調。這些節點形成一個集群,允許 PostgreSQL
保存比單台計算機上更多的數據和使用更多的 CPU
內核。 這種架構還允許通過簡單地向集群添加更多節點來擴展數據庫。
Coordinator 與 Worker
每個 cluster
都有一個稱為 coordinator(協調器)
的特殊節點(其他節點稱為 worker
節點)。應用程序將它們的查詢發送到 coordinator
節點,coordinator
節點將其轉發給相關的 worker
並累積結果。
對於每個查詢,coordinator
要么將其路由到單個 worker
節點,要么將其並行化到多個節點,具體取決於所需數據是位於單個節點上還是多個節點上。coordinator
通過查閱其元數據表知道如何做到這一點。這些 Citus
特定表跟蹤 worker
節點的 DNS
名稱和運行狀況,以及跨節點數據的分布情況。
分布式數據
表類型
Citus
集群中有三種類型的表,每種表都以不同方式存儲在節點中,並且用於不同的目的。
類型 1:分布式表
第一種類型,也是最常見的,是分布式表
。對於 SQL
語句而言,它們看似是普通的表,但在 worker
節點之間水平分區。
這里 table
的行存儲在 worker
的表 table_1001
、table_1002
等中。 組件 worker
表稱為分片(shards)
。
分布列
Citus
使用使用分片算法將行分配到分片。基於表列(稱為分布列(distribution column)
)的值執行分配,此分配具有確定性。集群管理員在分布表時必須指定此列。做出正確的選擇,這一點對於性能和功能有重要影響。
類型 2:引用表
引用表
是一種分布式表,其全部內容都集中到單個分片中,並在每個 worker
上復制。因此,對任何 worker
的查詢都可以在本地訪問 引用
信息,無需從另一個節點請求行,因此也不會產生此類網絡開銷。引用表
沒有分布列
,因為無需區分每行的各個分片。
引用表
通常很小,用於存儲與在任何工作節點上運行的查詢相關的數據。例如,訂單狀態或產品類別等枚舉值。
當與 引用表
交互時,我們會自動對事務執行兩階段提交 (2PC
)。 這意味着 Citus
確保您的數據始終處於一致狀態,無論您是在寫入
、修改
還是刪除
它。
類型 3:本地表
當您使用 Citus
時,您連接並與之交互的 coordinator
節點是安裝了 Citus
擴展的常規 PostgreSQL
數據庫。 因此,您可以創建普通表並選擇不對其進行分片。 這對於不參與連接查詢的小型管理表很有用。 一個示例是用於應用程序登錄和身份驗證的用戶表。
創建標准 PostgreSQL
表很容易,因為它是默認值。這是你運行 CREATE TABLE
時得到的。在幾乎每個 Citus
部署中,我們都會看到標准 PostgreSQL
表與 distributed
和 reference
表共存。事實上,如前所述,Citus
本身使用本地表來保存集群元數據。
Shards
上一節將分片描述為在 worker
節點內的較小表中包含分布式表的行的子集。本節詳細介紹了技術細節。
協調器
上的 pg_dist_shard
元數據表包含系統中每個分布式表的每個分片的行。該行與分片 ID
相匹配,分片 ID
的范圍是一組哈希整數 (shardminvalue
, shardmaxvalue
)。
SELECT * from pg_dist_shard;
logicalrelid | shardid | shardstorage | shardminvalue | shardmaxvalue
---------------+---------+--------------+---------------+---------------
github_events | 102026 | t | 268435456 | 402653183
github_events | 102027 | t | 402653184 | 536870911
github_events | 102028 | t | 536870912 | 671088639
github_events | 102029 | t | 671088640 | 805306367
(4 rows)
如果 coordinator
節點要確定哪個分片包含 github_events
行,它將對行中分布列的值執行哈希算法。然后此節點檢查哪個分片的范圍包含此哈希值。 定義范圍后,哈希函數的image(圖像)
就是兩者的並查。
分片放置
假設分片 102027
與相應的行關聯。在某個 worker
中的 github_events_102027
表中讀取或寫入此行。是哪個 worker
?這完全由元數據表確定。分片映射到 worker
的過程稱為分片放置(shard placement)
。
coordinator
節點將查詢重寫為引用特定表(例如 github_events_102027
)的片段,並對相應 worker
運行這些片段。 下面的查詢示例在后台運行,旨在查找分片 ID
為 102027
的節點。
SELECT
shardid,
node.nodename,
node.nodeport
FROM pg_dist_placement placement
JOIN pg_dist_node node
ON placement.groupid = node.groupid
AND node.noderole = 'primary'::noderole
WHERE shardid = 102027;
┌─────────┬───────────┬──────────┐
│ shardid │ nodename │ nodeport │
├─────────┼───────────┼──────────┤
│ 102027 │ localhost │ 5433 │
└─────────┴───────────┴──────────┘
在 github_events
示例中,有四個分片。每個表的分片數量在其在集群中分布時是可配置的。
最后請注意,Citus
允許復制分片以防止數據丟失。有兩種復制“模式”:Citus
復制和流復制。前者創建額外的備份分片放置並針對所有更新它們的所有它們運行查詢。后者效率更高,利用 PostgreSQL
的流式復制將每個節點的整個數據庫備份到一個 follower
數據庫。這是透明的,不需要 Citus
元數據表的參與。
共置
由於可以根據需要將分片及其副本放置在節點上,因此將包含相關表的相關行的分片放在同一節點上是有意義的。 這樣,它們之間的連接查詢可以避免通過網絡發送盡可能多的信息,並且可以在單個 Citus
節點內執行。
一個示例是包含商店、產品和購買的數據庫。如果所有三個表都包含 - 並且由 - store_id
列分布,那么限制在單個存儲中的所有查詢都可以在單個工作節點上高效運行。即使查詢涉及這些表的任意組合也是如此。
並行性
跨多台機器分散查詢允許一次運行更多查詢,並允許通過向集群添加新機器來擴展處理速度。此外,如上一節所述,將單個查詢拆分為片段可以提高專用於它的處理能力。 后一種情況實現了最大的並行性,這意味着 CPU
內核的利用率。
讀取或影響均勻分布在多個節點上的分片的查詢能夠以“實時”
速度運行。 請注意,查詢的結果仍然需要通過協調器節點傳回,因此當最終結果緊湊時(例如計數和描述性統計等聚合函數),加速效果最為明顯。
查詢執行
在執行多分片查詢時,Citus
必須平衡並行性的收益與數據庫連接的開銷(網絡延遲和工作節點資源使用)。要配置 Citus
的查詢執行以獲得最佳的數據庫工作負載結果,它有助於了解 Citus
如何管理和保存協調節點和工作節點之間的數據庫連接。
Citus
將每個傳入的多分片查詢會話轉換為稱為任務的每個分片查詢。 它將任務排隊,並在能夠獲得與相關工作節點的連接時運行它們。對於分布式表 foo
和 bar
的查詢,下面是連接管理圖:
coordinator
節點為每個會話都有一個連接池。每個查詢(例如圖中的 SELECT * FROM foo
)僅限於為每個 worker
的任務打開最多 citus.max_adaptive_executor_pool_size
(整數)個同時連接。 該設置可在會話級別進行配置,以進行優先級管理。
在同一連接上按順序執行短任務比為它們並行建立新連接更快。 另一方面,長時間運行的任務受益於更直接的並行性。
為了平衡短任務
和長任務
的需求,Citus
使用 citus.executor_slow_start_interval
(整數)。 該設置指定多分片查詢中任務的連接嘗試之間的延遲。 當查詢首先對任務進行排隊時,這些任務只能獲取一個連接。 在每個有待處理連接的時間間隔結束時,Citus
會增加它將打開的同時連接數。通過將 GUC
設置為 0
,可以完全禁用慢啟動行為。
當任務完成使用連接時,會話池將保持連接打開以供以后使用。緩存連接避免了 coordinator
和 worker
之間重新建立連接的開銷。但是,每個池一次打開的空閑連接不超過 citus.max_cached_conns_per_worker
(整數)個,以限制 worker
中空閑連接資源的使用。
最后,設置 citus.max_shared_pool_size (integer)
充當故障保險。它限制了所有任務之間每個 worker
的總連接數。