如何設計好分佈式數據庫,這個策略很重要

數據庫是應用和計算機的核心組成,試想,如果沒有數據庫,就像人的大腦沒有了記憶一樣,信息也得不到共享,那麼,對開發者來說,如何設計一款高效易用的數據庫至關重要。

GaussDB(for openGauss) 是企業級分佈式數據庫,具備分佈式強一致、有效降低容災成本、支持 PB 級海量數據、智能診斷等優點,是當下炙手可熱的主流數據庫,那麼如何更好的設計分佈式數據庫的數據分佈策略呢?首先介紹一下 GaussDB(for openGauss) 的基本架構,便於理解後面的分析。

邏輯架構

這個是一個典型的基於數據分片的分佈式架構 (share nothing),底層數據通過一定的規則比如 hash、list 或者 range 等讓數據打散分佈到不同的數據節點上,計算時底層多個節點共同參與計算。同時數據節點可以擴展,上層由協調節點進行 SQL 解析和轉發。

從圖中可以看到,主要包括三類節點:協調節點、數據節點、集羣類節點(最重要的是全局事務管理器)。協調節點負責 SQL 解析轉發,充當的是類似 proxy 的角色,數據節點負責計算和數據存儲,全局事務管理器負責全局事務讀一致性的保證。

關鍵角色

分佈式 SQL 執行過程

大致執行過程:

  1. 業務應用下發 SQL 給 Coordinator ,SQL 可以包含對數據的 CRUD 操作;

  2. Coordinator 利用數據庫的優化器生成執行計劃,每個 DN 會按照執行計劃的要求去處理數據;

  3. 數據基於一致性 Hash 算法分佈在每個 DN,因此 DN 在處理數據的過程中,可能需要從其他 DN 獲取數據,GaussDB 提供三種 stream 流(廣播流、聚合流和重分佈流)實現數據在 DN 間的流動;

  4. DN 將結果集返回給 Coordinate 進行彙總;

  5. Coordinator 將彙總後的結果返回給業務應用。

數據分佈策略場景實踐

拿電子商城來舉例,一個完整的商城會包括很多信息,例如用戶、產品、訂單、倉庫、物流、支付等等很多信息。以下用訂單、支付方式、快遞公司這 3 個信息爲例,這 3 個信息也只列出少量關鍵屬性來舉例。

step1、數據庫邏輯模型設計

step2、功能設計

常用場景一、查看子訂單列表

Select sn, status, money, product_id, product_mount from order t1, suborder t2 where t1.id = t2.order_id and t1.sn=’xxx’;

常用場景二、查看子訂單詳情

Select product_id, product_mount, t2.name as shipping_name, t3.name as pay_type_name from suborder t1, shipping_com t2, pay_type t3 where t1.id=’xx’ and t1.shipping_id=t2.id and t1.pay_type_id=t3.id;

step3、物理數據模型設計

電子商城每天的訂單量非常巨大,使用傳統的主備庫模式顯然無法滿足如此大數據量的請求和存儲需要。而跨節點、可橫向擴展的分佈式數據庫可以很好解決大規模海量數據的計算存儲問題。GaussDB(for openGauss) 分佈式模式最大可以支持 1000 + 節點,PB 級存儲,分佈式事務強一致等特性可以很好地滿足政府、交通、金融、能源等行業的互聯網 + 的訴求。

這個場景中,訂單表和支付方式表代表着兩類數據,前者同客戶數、時間正相關,一箇中型的商城每天的數據可能就達到了百萬條記錄,暫記爲 A 類數據;後者數據變化較小,往往是配置類的數據,暫記爲 B 類數據。功能模塊中存在 A 類數據之間的相互關聯以及 A 與 B 類數據的關聯。那麼在分佈式數據庫下,當數據分佈在不同的節點上,以上能否直接關聯呢?如果能夠關聯的話,怎麼樣設計才能更好的達到性能上的要求呢?

對於分佈式數據庫而言,如何使得以上的場景能夠得到更好的性能,關鍵的是把表的數據分佈策略選擇好,而像分區、索引等設計同傳統的單機差別不大。因此要回答這個問題,我們需要先了解 GaussDB (for openGauss) 的數據分佈策略。

數據分佈策略

GaussDB 支持的數據分佈策略

分佈存儲和併發查詢是 MPP 架構數據庫的主要優勢所在。將一個大數據量表中的數據,按合適分佈策略分散存儲在多個 DN 實例內,可極大提升數據庫性能。

GaussDB V5 支持如下表所示的數據分佈策略:

下面這張圖可以幫忙我們清晰地理解複製表和分佈表,前者每個 DN 上都是一個完整的表,而後者每個 DN 上只是一個分片。

分佈策略

語法:

創建複製表
create table region1(ctid_value int) distribute by replication;
創建分佈表
create table region2(ctid_value int) distribute by hash(ctid_value);
說明:當不指定分佈方式,創建表默認爲(第一個可以作爲分佈列的列爲分佈鍵)分佈表

看到這裏這裏,很多人馬上就會明白,訂單表和子訂單表適合用分佈表,支付方式表和快遞公司表適合用複製表,那麼是爲什麼呢?讓我們先了解下分佈表及複製表的關聯過程。

分佈表及複製表關聯過程

(1)分佈表和複製表的關聯查詢

  1. T1 爲 hash 表,T2 爲複製表。

  2. T1 表的每一部分在各 DN 上分別與 T2 表進行連接。

  3. 各 DN 上的連接結果集在 CN 上進行匯聚,產生最終輸出的結果集。

(2)分佈表與分佈表關聯查詢

  1. T1 表和 T3 表都爲分佈表。

  2. 在 DN1 實例上,T1 表的 p1 部分與 T3 表的 T1 部分進行關聯。

  3. T3 表的 p2、p3、p4 複製到 DN1 上,與 T1 的 p1 部分進行關聯。

  4. DN2、DN3、DN4 實例操作與 DN1 類似。

  5. CN 節點對各 DN 生成的結果集進行匯聚,生成最終數據結果集。

注:細心的朋友可能看到,不同的 DN 之間可能會進行數據同步,在這種情況下,執行效率會就變差,如何避免這種情況,下面會講到。

分佈鍵的選擇

避免數據廣播

在分佈表關聯分佈時,分佈列不同時,存在 Streaming(type: BROADCAST)廣播,不同 DN 節點之間數據存在交互,會增加網絡開銷,而分佈列相同或關聯複製表數據時,不存在 DN 節點間數據交互。下面我們進行下實際測試:

例如對於表 t1,t2,我們使用不同的分片列進行關聯:select * from t1, t2 where t1.a = t2.b;

**方式 1:**t1、t2 都選擇 a 做分佈列

create table t1 (a int, b int) distribute by hash (a);
create table t2 (a int, b int) distribute by hash (a);

其執行計劃如下:

**方式 2:**將 a 作爲 t1 的分佈列,將 b 作爲 t2 的分佈列:

create table t1 (a int, b int) distribute by hash (a);
create table t2 (a int, b int) distribute by hash (b);

重新查看執行計劃如下:

分析:方式 1 由於存在 “Streaming”,導致 Datanode 之間存在較大通信數據量。

避免數據傾斜

SELECT a.count,b.node_name FROM (SELECT count(*) AS count,xc_node_id FROM tablename GROUP BY xc_node_id) a, pgxc_node b WHERE a.xc_node_id=b.node_id ORDER BY a.count DESC;

如果各 DN 內元組數目相差較大(如相差數倍、數十倍),則表明已發生數據傾斜現象,請按照下面原則調整分佈列。

當前不支持通過 ALTER TABLE 語句調整分佈列,因此,調整分佈列時需要重新建表。

選擇原則如下:分佈列的列值應比較離散,以便數據能夠均分佈到各個 DN。

例如,考慮選擇表的主鍵爲分佈列,如在人員信息表中選擇身份證號碼爲分佈列。在滿足上面原則的情況下,考慮選擇查詢中的連接條件爲分佈列,以便 Join 任務能夠下推到 DN 中執行,且減少 DN 之間的通信數據量。

總結

GaussDB(for openGauss) 是分佈式架構,數據分佈在各個 DN 上,設計好的數據分佈策略是分佈式數據庫設計中最關鍵的環節。本文結合電子商城場景講述了支持的數據分佈策略、分佈鍵的選擇以及關聯過程,還講述了應該規避的問題。理解了以上這些內容後,相信你可以結合自己的業務場景,設計出最佳的數據分佈策略。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/LdU16g1VYt9_GPhlHdWv7A