自 ClickHouse Inc 宣布其重要新功能僅在 ClickHouse Cloud 上開放以來,一些關(guān)注 ByConity 開源的社區(qū)小伙伴也來詢問 ByConity 后續(xù)開源規(guī)劃。為回答社區(qū)疑問,我們將之前分享的關(guān)于 ByConity 與 ClickHouse 相關(guān)功能對比的 webinar 整理為文章,并更新 ByConity 0.2.0 所發(fā)布比較新功能與 ClickHouse 對比內(nèi)容,幫助社區(qū)小伙伴了解 ByConity 開源社區(qū)規(guī)劃與進展。
ByConity & ClickHouse 使用視角對比
我們整理了一些從實用角度看 ClickHouse & ByConity 的異同點,與大家分享:
- 技術(shù)架構(gòu)和核心組件看兩者各自特點
- 數(shù)據(jù)庫的基本操作差異:庫表創(chuàng)建、數(shù)據(jù)導(dǎo)入、數(shù)據(jù)查詢等方面兩者有什么異同
- ByConity 的分布式事務(wù)
- ByConity 特殊的表引擎及其優(yōu)勢
架構(gòu)和組件
ClickHouse 的架構(gòu)及組件
ClickHouse 是典型的 MPP 架構(gòu),節(jié)點對等,所有的功能都被放在 ClickHouse server 組件中。當部署 ClickHouse 集群時,主要是把 ClickHouse server 部署在一組物理機上。
分布式表 & 本地表
ClickHouse 提出了分布式表的概念,當 Client 做查詢時,首先連接節(jié)點找到分布式表,通過 sharding key 的定義以及集群的配置知道分布式表對應(yīng)的本地表及分布節(jié)點。再通過兩階段的執(zhí)行,先到節(jié)點上做本地表的查詢,再把查詢結(jié)果匯聚到分布式表,然后再返回給客戶端。
Replicas
ClickHouse 提供數(shù)據(jù)復(fù)制的能力,通過對每一個本地表配置 Replica 進行數(shù)據(jù)復(fù)制。不管是分布式的執(zhí)行,還是數(shù)據(jù)的復(fù)制,都需要 Coordinator 進行節(jié)點之間的通信,包括任務(wù)的分發(fā)等。
Zookeeper & ClickHouse Keeper
ClickHouse 之前通過 Zookeeper 提供 Coordinator 能力,部署一個 ClickHouse 集群需要同時部署一個 Zookeeper 集群來承擔對應(yīng)的工作。后來發(fā)現(xiàn) Zookeeper 集群存在很多局限性,在大規(guī)模分析型數(shù)據(jù)查詢中會碰到很多性能瓶頸和使用問題,因此進行了一定改進,用 C++ 和 raft 協(xié)議實現(xiàn)了 ClickHouse Keeper 組件。ClickHouse Keeper 提供兩種部署方式,既可以像 Zookeeper 一樣作為單獨的集群去部署,也可以放在 ClickHouse server 里跟 ClickHouse server 一同部署。
ByConity 的架構(gòu)及組件
ByConity 是存算分離的架構(gòu),整體架構(gòu)主要分為三層:服務(wù)接入層、計算層和云存儲層。
服務(wù)接入層
由一組 server 和共享的服務(wù)組件組成,包括 TSO、Daemon Manager、Resource Manager。
- Server
- 服務(wù)接入層的 server 是做所有查詢的入口,當 Client 連接 server 時,server 會先做查詢的前處理,包括 SQL 解析、查詢優(yōu)化,生成 Query Plan。每個 Query Plan 由多個 PlanSegment 組成,server 負責把 PlanSegment 下發(fā)給 worker 做具體計算。
- 查詢過程中會涉及到元數(shù)據(jù)的管理,比如需要知道庫表、字段的定義及統(tǒng)計信息,如 Part 的信息等等,server 就會跟元數(shù)據(jù)的存儲交互。元數(shù)據(jù)在 ByConity 目前采用 Foundation DB 來實現(xiàn)。
- TSO:TSO(Timestamp oracle)是提供全局僅有單調(diào)遞增的時間戳。在分布式事務(wù)的時候非常有用。在后面的事務(wù)部分將會介紹。
- Daemon Manager:用來調(diào)度和管理任務(wù)。ByConity 的分層架構(gòu)涉及到管理節(jié)點,對應(yīng)提出了后臺任務(wù)的概念,如 merge、實時數(shù)據(jù)導(dǎo)入時 Kafka 的 consumer 等,都作為后臺任務(wù)來進行。后臺任務(wù)的集中管理和調(diào)度都由 Daemon Manager 來實現(xiàn)。
- Resource Manager :顧名思義用來管理資源。計算層的 Virtual Warehouse 以及 worker 都由 Resource Manager 管理,分配查詢和數(shù)據(jù)寫入應(yīng)該由哪個 worker 執(zhí)行;Resource Manager 同時做一定的服務(wù)發(fā)現(xiàn),如有新的 worker 加入或新的 Virtual Warehouse 創(chuàng)建時,Resource Manager 能夠發(fā)現(xiàn)。
計算層
- 計算層由一個或者多個 Virtual Warehouse (計算組)構(gòu)成,執(zhí)行具體的計算任務(wù)。一個 Virtual Warehouse 由多個 worker 構(gòu)成。
- 計算層為無狀態(tài)的一層,為了查詢的某些性能,這里會有 Disk 的參與,把一些數(shù)據(jù)緩存在 worker 本地做 disk_cache。在 ByConity 的查詢中有冷查(首先次查詢)和熱查的區(qū)別,冷查需要從遠端的云存儲把數(shù)據(jù)拉到 disk_cache,后續(xù)查詢可以直接重用 disk_cache 的數(shù)據(jù),查詢速度更快。
云存儲層
- 采用 HDFS 或 S3 等云存儲服務(wù)作為數(shù)據(jù)存儲層,用來存儲實際數(shù)據(jù)、索引等內(nèi)容。
ByConity 的部署要求
在部署 ByConity 時,不同的組件有不同的硬件要求。對一些共享服務(wù),如 TSO、Daemon Manager 和 Resource Manager,其資源需求相對較低且比較固定;server 和 worker 所需資源相對較多,尤其是 worker,需要根據(jù)不同的查詢場景部署到不同的硬件規(guī)格上。
ByConity 社區(qū)推薦使用 Kubernetes 來部署,可通過官方提供的工具和腳本來實現(xiàn)自動化操作,集群后期的運維管理也更方便。具體的部署方式可在文檔中查看:https://byconity.github.io/zh-cn/docs/deployment/deploy-k8s
由于部署 ByConity 也包括元數(shù)據(jù)以及遠端的存儲,即使部署測試環(huán)境也有前置要求,即 HDFS 和 Foundation DB。如本身已有環(huán)境,可直接進行配置使用。如果沒有,可參考對應(yīng)的部署文檔進行設(shè)置。
ByConity 的架構(gòu)特性
ByConity 的架構(gòu)演進源于字節(jié)在使用 ClickHouse 過程中所遇到的痛點。ByConity 的組件雖然比較復(fù)雜,但設(shè)計這些組件有其對應(yīng)的優(yōu)勢。
資源隔離
資源隔離是一個業(yè)務(wù)高速發(fā)展中集群環(huán)境變復(fù)雜的過程中不可避免的問題。資源隔離有多個層面。
- 租戶隔離,在 ToB 的業(yè)務(wù)上指多租戶;在企業(yè)內(nèi)部一般指各個業(yè)務(wù)線之間在共享集群上的業(yè)務(wù)隔離。不同的業(yè)務(wù)線之間通常希望獨占部分系統(tǒng)資源,在進行分析、查詢這些工作時可以相互不影響。這里必然也伴隨著計算資源的隔離。
- 讀寫分離,由于讀操作和寫操作對硬件的要求、發(fā)生的時間以及熱點都不一樣,通常希望讀寫之間也不要互相影響,能夠分開用不同規(guī)格的資源去跑。
- 冷熱分離,一般指冷數(shù)據(jù)和熱數(shù)據(jù)的存儲能夠用不同的硬件資源分離,一方面可以減少成本,另一方面也可以讓冷熱不同的查詢之間不受影響。比如說如果有緩存的話,冷查詢不會沖掉熱查詢的緩存,進而對熱查詢造成性能影響。
ClickHouse 的資源隔離
ClickHouse 沒有在架構(gòu)層面對資源隔離做專門的設(shè)計,因此 ClickHouse 在做上述這些資源隔離時需要單獨的方案。
讀寫分離可以通過準確配置 replica(部分專門負責讀,部分專門負責寫),結(jié)合 load balance 策略以及集群的部署方式做一定的區(qū)分。但此方案有一定局限性,一是運維成本較高,需要手動準確控制。二是讀寫分離的資源不方便重用,專門用來負責寫的 replica,在讀請求高峰時無法 serve 讀請求。
冷熱分離可以通過 TTL,TO DISK,TO VOLUME 的功能,把冷數(shù)據(jù)和熱數(shù)據(jù)分別指定不同的存儲介質(zhì)去存儲。存儲方面能夠帶來成本節(jié)約的好處,但是在計算層面依然使用同樣的資源,無法做到分離。
ByConity 的資源隔離
ByConity 可以通過 Virtial Warehouse 部署和使用實現(xiàn)多級資源隔離。由于 Virtial Warehouse 是無狀態(tài)的,可以針對不同業(yè)務(wù)、不同場景按需創(chuàng)建。Virtial Warehouse 的創(chuàng)建操作是無感的,所包含的 worker 的創(chuàng)建也比較靈活。不同的 Virtial Warehouse 之間資源獨占,可以比較輕松地實現(xiàn)上述隔離。
- 租戶隔離:不同的業(yè)務(wù)線可以根據(jù)各自需求創(chuàng)建不同的 Virtial Warehouse,對計算資源可以天然做到物理隔離。計算資源也可以在計算熱點不同時做調(diào)整,實現(xiàn)成本控制和節(jié)省。
- 讀寫分離:ByConity 的設(shè)計要求用戶在部署時指定好讀和寫操作分別使用哪個 Virtial Warehouse,系統(tǒng)會自動地根據(jù)不同的讀寫請求把計算轉(zhuǎn)發(fā)到不同的 Virtial Warehouse 中,其天然具備讀寫分離的能力。
- 冷熱分離:從存儲上來講,因為 ByConity 存算分離,所有的數(shù)據(jù)都會落在遠端存儲中,不需要做數(shù)據(jù)冷存介質(zhì)和熱存介質(zhì)之間的區(qū)分,所有的數(shù)據(jù)都會有完整的一份在遠端存儲中。由于 disk_cache 的存在,熱數(shù)據(jù)有緩存加速,且所有熱數(shù)據(jù)的載入不需要用戶介入,都是自動計算的過程,可以根據(jù)查詢把所需要的熱數(shù)據(jù)載入到 worker 本地。
集群擴縮容
擴縮容是在業(yè)務(wù)不斷增長的場景中必須要考慮的話題。業(yè)務(wù)在爆發(fā)式增長的過程中,可能每兩周就需要對集群進行一次擴容,每次擴容都需要伴隨很多操作,帶來很多的成本。因此擴縮容不得不考慮。
ClickHouse 的擴縮容
ClickHouse 架構(gòu)層面未專門考慮擴縮容。ClickHouse 的擴縮容需要通過一定手段來實現(xiàn):
- 擴容副本,通過使用新的節(jié)點來部署新的 ClickHouse server,并把副本轉(zhuǎn)移到新的節(jié)點上。但是副本擴容之后需要一定的時間進行復(fù)制,并且需要對復(fù)制的成功率及結(jié)果進行校驗。這些操作都需要運維手動去做,沒有專門的功能支持。
- 擴容分片,通過增加 Shard 把新的分片部署到新的節(jié)點。這種方式會導(dǎo)致數(shù)據(jù)無法再均衡,即老的數(shù)據(jù)依然落在老的分片上,在進行具體查詢時不同節(jié)點上的數(shù)據(jù)分布不均,需要進行數(shù)據(jù)再均衡。而數(shù)據(jù)再均衡的過程在 ClickHouse 中無法自動實現(xiàn)。
ByConity 的擴縮容
ByConity 是基于存算分離的無感彈性擴縮容,通過 Virtial Warehouse 和 worker 來實現(xiàn)。
- 業(yè)務(wù)隔離:Virtial Warehouse 可以根據(jù)不同的業(yè)務(wù)線去創(chuàng)建,其創(chuàng)建和銷毀均無感。
- 負載隔離:每個 Virtial Warehouse 可以根據(jù)業(yè)務(wù)量的變化調(diào)整 worker 的數(shù)量。具體來說:一些組件如 Resource Manager 可以自動發(fā)現(xiàn)新增加到集群中的 worker,并自動實現(xiàn)數(shù)據(jù)再均衡。
數(shù)據(jù)庫的基本操作
庫表創(chuàng)建
ClickHouse
- SQL 標準:ClickHouse 的 SQL 標準為 ClickHouse SQL,它從 ANSI SQL 演化而來,但有很多項不符合 ANSI SQL 標準,如果從其他的數(shù)據(jù)庫遷移到 ClickHouse 需要有較多修改。
- 支持協(xié)議:ClickHouse 支持的協(xié)議主要是 TCP 和 HTTP,client 和 driver 使用 TCP 協(xié)議,也有一些工具和專門的 driver 使用 HTTP。
- 客戶端:ClickHouse 本身就有 ClickHouse client,同時對于不同的語言也會有驅(qū)動性,比如 clickhouse-jdbc,clickhouse-go。
- 表引擎:在創(chuàng)建庫表的時候,ClickHouse 有 MergeTree 家族表引擎,要為每一個表去指定所用的表引擎,用得最多是 MergeTree 以及 MergeTree 衍生出來的 MergeTree 家族,如 replacing MergeTree,aggregated MergeTree 等。
ByConity
- SQL 標準:ByConity 能夠兼容 ClickHouse 原生的 SQL 標準,在 SQL 標準上提供了 dialect 的配置。除了可以使用 ClickHouse 原生的 SQL,ByConity 還提供了 ANSI SQL 的方式。ANSI SQL 不是嚴格意義上完全符合 ANSI 標準的 SQL,考慮到 ClickHouse SQL 與 ANSI 有比較多的 gap,ByConity 會把一些不符合標準的地方盡量做到符合 ANSI SQL 標準。ANSI 的 dialect 可以看作是比 ClickHouse SQL 更加符合標準的 SQL 方式。
- 支持協(xié)議:ByConity 原生支持 ClickHouse 的 TCP 和 HTTP 協(xié)議。
- 客戶端:除了 ClickHouse 支持的客戶端以及驅(qū)動器,ByConity 有專門的客戶端用于支持自己的配置和參數(shù)。
- 表引擎:ByConity 提供了合一的表引擎 CnchMergeTree,分布式的執(zhí)行過程都封裝在里面,可以替代 ClickHouse 原生 MergeTree 家族多個 MergeTree 的能力,如 by default 的 MergeTree、replacing MergeTree,包括支持僅有鍵也在 CnchMergeTree 中封裝。
- Virtial Warehouse 及計算組配置:創(chuàng)建 ByConity 庫表有專門的設(shè)置,可以通過 DDL 為庫表的讀和寫指定默認的 Virtial Warehouse。讀寫分離也是通過此操作實現(xiàn)的。
數(shù)據(jù)導(dǎo)入
ClickHouse
ClickHouse 的數(shù)據(jù)導(dǎo)入包括基礎(chǔ)的 insert 操作,外部文件的導(dǎo)入 insert into … infile… 。 另外 ClickHouse 提供了很多的外表引擎,可以利用這些外表引擎創(chuàng)建外表,通過 insert select 從外表把數(shù)據(jù)導(dǎo)入 ClickHouse。ClickHouse 多用在實時數(shù)倉場景,在 ClickHouse 的數(shù)據(jù)導(dǎo)入中,實時數(shù)據(jù)導(dǎo)入是一個比較重要的話題。ClickHouse 專門的表引擎—— ClickHouse Kafka 在 ClickHouse 中用得非常多。
ByConity
ByConity 對于基礎(chǔ) insert、外部文件導(dǎo)入以及外表數(shù)據(jù)導(dǎo)入與 ClickHouse 相同,語法上也一樣。此外,ByConity 提供了更多的數(shù)據(jù)導(dǎo)入方式,包括一個數(shù)據(jù)導(dǎo)入工具,PartWriter。
PartWriter
可以集成在 Spark 的流程處理中,不通過 ByConity 的表引擎,直接將數(shù)據(jù)文件轉(zhuǎn)換為 ByConity 能夠識別的的 parts 文件。
后臺任務(wù)
在數(shù)據(jù)導(dǎo)入時有很多后臺任務(wù)需要管理,如數(shù)據(jù)導(dǎo)入之后的 merge 和 mutate 任務(wù),Kafka 表引擎實時消費任務(wù)等。通過操作語句跟后臺任務(wù)進行交互,監(jiān)控后臺任務(wù)的執(zhí)行情況及系統(tǒng)表的性能指標,能夠?qū)崿F(xiàn)對后臺任務(wù)的準確控制。
實時數(shù)據(jù)消費
ClickHouse 的 Kafka 表引擎
ClickHouse 做 Kafka 的數(shù)據(jù)導(dǎo)入會創(chuàng)建以下幾個部分:
- 用 Kafka 表引擎創(chuàng)建 Kafka 外表,指定從哪個 Kafka 的集群消費數(shù)據(jù),整個 consumer 如何配置
- 定義一個 ClickHouse 的 MergeTree 表,作為數(shù)據(jù)真正寫入的表
- 定義一個 Materialized View,把上述兩個部分連接起來
Kafka 的數(shù)據(jù)導(dǎo)入在創(chuàng)建以上三個部分之后會在后臺運行,之后不停地把數(shù)據(jù)從 Kafka 消費出來寫入到目標表。
ByConity 的 Kafka 表引擎
ByConity 從基本用法跟 ClickHouse 一致,從 Kafka 消費數(shù)據(jù)也是創(chuàng)建外表、CNCH MergeTree,并創(chuàng)建一個 Materialized View 把兩部分連接起來。但是 ByConity 在具體操作中跟 ClickHouse 存在差異。
Kafka 消費模式方面的差異:
- ClickHouse 在 Kafka 消費時使用 High Level 的消費方式。這是一種自動化程度更高的消費方式,可以動態(tài)分配 Kafka 的 Partition 到 Consumer 的 instance。當發(fā)現(xiàn)有 Consumer 掛掉或有新的 Consumer 加入時,可以自動 Rebalance,把 Partition 進行重分配。ClickHouse其 MPP 的架構(gòu)更加適合 High Level 消費方式,可利用 Kafka 進行 Rebalance。但是這種方式很難保證 Exactly Once,因為在 Rebalance 過程當中會由失敗引起數(shù)據(jù)的重復(fù)消費,如果這些重復(fù)消費在目標表中沒有去重手段,肯定會造成數(shù)據(jù)重復(fù),無法保證 Exactly Once。
- 在此消費方式下,Partition 經(jīng)常 Rebalance 到不同的 Consumer 節(jié)點,在 ClickHouse 中則會 Rebalance 到不同的 ClickHouse shard,一方面運維排查比較困難,另一方面很難控制 Partition 具體會落到哪些 shard 上。
如何保證 Exactly Once
ByConity 采用 Low Level 的消費模式:Kafka 消費當中的 assign 靜態(tài)地分配 Partition 到具體的 consumer instance,這也是 ByConity 多層架構(gòu)的便利性,可以由 server 控制 Partition 的分發(fā),由worker 執(zhí)行真正的 consumer instance 的消費操作。
本身具有調(diào)度能力的產(chǎn)品更傾向于用 Low Level 的消費方式,如 Flink 和 Spark streaming。此方式的一個比較大的好處是不會造成數(shù)據(jù)重復(fù),盡量保證 Exactly Once,準確控制哪個 Partition 由哪個 consumer 消費。同時在提交 offset 時,也會讓數(shù)據(jù)寫入和 offset 的提交有事務(wù)保證。在線上運維排查及數(shù)據(jù)審計時也更加方便,Partition 不會亂飄,如發(fā)現(xiàn) Partition 有比較大的 LAG 也有跡可循,直接從 server 上找到具體的 worker,進而找到具體失敗的原因。
數(shù)據(jù)查詢
ClickHouse
ClickHouse 對復(fù)雜查詢的支持并不完整,它采用兩階段聚合的方式,即分布式表和本地表。在分布式表把查詢分發(fā)到本地表,在本地表做首先個階段的聚合之后再聚合到分布式表做第二階段的聚合,也稱為scatter/gather 的模式。
ClickHouse 提供了 GLOBAL JOIN 和 GLOBAL IN,類似于 Broadcast Join 的方式。在一個大表去 join 小表的時候,可以讓小表的數(shù)據(jù)先一步被計算出來,然后分發(fā)到大表去做 local 的 join。ClickHouse 對復(fù)雜查詢支持有限,多表 join 一直是 ClickHouse 的痛點。使用 ClickHouse 需要在前期盡量把數(shù)據(jù)打平成大寬表。
ByConity
ByConity 的復(fù)雜查詢通過優(yōu)化器來實現(xiàn),優(yōu)化器對復(fù)雜查詢有非常大的性能提升,推薦默認打開。ByConity 引入了多階段的查詢,首先由優(yōu)化器生成執(zhí)行計劃并分派到各個 worker,進而支持比較復(fù)雜的查詢,如節(jié)點之間有數(shù)據(jù)的消費能力的查詢。
優(yōu)化器的工作需要統(tǒng)計信息支撐,因為它里面有 CBO,需要去手動地維護統(tǒng)計信息。ByConity 提供了對統(tǒng)計信息操作的手段,包括 create Stats,drop stats,以及去查看統(tǒng)計信息的手段。具體內(nèi)容可以參考優(yōu)化器的分享:ByConity Monthly Webinar-20230321-優(yōu)化器原理解析與性能差異_嗶哩嗶哩_bilibili
分布式事務(wù)
為什么要支持事務(wù)
在分布式系統(tǒng)中,不同的系統(tǒng)對事務(wù)支持程度不同,一般考慮 ACID 四個特性。OLTP 數(shù)據(jù)庫對事務(wù)的要求較高,一般支持多種事務(wù)的隔離級別,且會支持比較高的級別,如 Serializable。但是一些 NO SQL 的數(shù)據(jù)庫,為了達到較好的性能,會把 ACID 的部分特性做得相對較弱。
OLAP 的環(huán)境中很多時候并不特別強調(diào)事務(wù)的重要性。但在真正的業(yè)務(wù)中,即使對 OLAP 系統(tǒng),事務(wù)也是非常重要的。其中一個關(guān)鍵是保證數(shù)據(jù)的準確性,有些系統(tǒng)雖然能夠保證最終的一致性,但在過程中會出現(xiàn)數(shù)據(jù)不準確的情況。對實時性要求比較高的系統(tǒng),數(shù)據(jù)不準確會帶來不好的用戶體驗。
此外在使用 OLAP 系統(tǒng)時,因為數(shù)據(jù)不都是一次性導(dǎo)入的,經(jīng)常會有數(shù)據(jù)的增量更新,在這種需求里面也需要事務(wù)操作。
ClickHouse
ClickHouse 雖然有分布式的查詢,但是并不支持分布式事務(wù),本地事務(wù)支持目前僅針對單次寫入在 max_insert_block_size 以內(nèi)的數(shù)據(jù)有事務(wù)保證。
此種事務(wù)保證對于大部分在 ClickHouse 里面真正跑的查詢是不夠的,ClickHouse 社區(qū)目前正在實現(xiàn)事務(wù)增強,如提供 MVCC 和 RC 的隔離級別,支持多 insert 和多 select 組成的交互性事務(wù)。此功能還目前還在 experimental 階段,需要特殊配制才能使用。即使最終完全實現(xiàn)也還是一個 local 的事務(wù),只針對本地表有事務(wù)保證,無分布式事務(wù)的規(guī)劃。
ByConity
ByConity 進行了比較完整的分布式事務(wù)實現(xiàn),其 ACID 的特性保證如下:
- 原子性(Atomicity):ByConity 在各種情況下都會保證原子性,包括掉電,錯誤和宕機等各種異常情況。
- 一致性(Consistency ):保證數(shù)據(jù)庫只會從一個有效的狀態(tài)變成另外一個有效的狀態(tài),不會有中間狀態(tài)被看到,任何數(shù)據(jù)的寫入必須遵循已經(jīng)定義好的規(guī)則。
- 隔離性(Isolation ):ByConity 為用戶提供的是 read committed(rc)隔離級別的支持。未完成的事務(wù)寫入對于其他事務(wù)是不可?的
- 持久性(Durability ):ByConity 采取的存儲計算分離結(jié)構(gòu),利用了成熟的高可用分布式文件系統(tǒng)或者對象存儲,保證成功事務(wù)所提交數(shù)據(jù)的高可用。
另外,ByConity 通過兩個比較重要的組件來進行事務(wù)保證。
- Foundation DB:通過 Foundation DB 的能力做事務(wù)中的必要操作。Foundation DB 本身具有的原子性操作及CAS的操作在事務(wù)的執(zhí)行過程中有幫助。
- Timestamp Oracle(TSO):通過 Timestamp Oracle 提供全局僅有時間戳,時間戳是單調(diào)遞增的,可以用來做事務(wù)的 ID。
在事務(wù)的具體實現(xiàn)中,這是一個典型的兩階段提交的實現(xiàn)。首先個階段寫入事務(wù)記錄,包括寫 undo buffer,遠端存儲,提交元信息等。第二個階段真正提交事務(wù),并更新事務(wù)記錄的提交時間。在事務(wù)成功和失敗的時候,用 undo buffer 去做一些清理。
特殊的表引擎
Unique 表引擎
很多分析型數(shù)據(jù)庫有 Upsert 的需求,如果表中存在已有數(shù)據(jù),希望覆蓋掉前面的重復(fù)數(shù)據(jù),因此需要僅有鍵的保證來進行判讀。ClickHouse 很難保證數(shù)據(jù)插入的僅有性。ClickHouse 提供的 replacing MergeTree 可以在一定程度上達到此效果,但 replace MergeTree 不保證鍵一定是僅有的,因為它是異步,要在 merge 時才能做數(shù)據(jù)的覆蓋。如果 merge 一直不做或者做得比較晚則會出現(xiàn)重復(fù)數(shù)據(jù)的狀態(tài),而這種狀態(tài)在很多場景下不允許出現(xiàn)。因此需要一個能夠保證鍵的僅有性的場景來做 Upsert 的支持。
ByConity 的實現(xiàn)方式
ByConity 對 Upsert 支持中,行級的 update 操作被轉(zhuǎn)換成 delete + insert。行級 delete 通過 DeleteBitmap 實現(xiàn),DeleteBitmap 存放了該 part 中所有被刪除的行的行號。具體的增刪改查都會圍繞 DeleteBitmap 操作,比如 insert 時修改 Bitmap 對比版本信息;在 select 之后,根據(jù) DeleteBitmap 當中的標識去 filter 數(shù)據(jù)。
為了加速執(zhí)行,ByConity 對 Unique Key 創(chuàng)建了 index。因為在 Bitmap 中放的是行號,從 key 到行號需要索引,通過 Unique Key Index 可以實現(xiàn) Key 到行號的快速定位。
僅有性的保證也需要控制寫沖突的發(fā)生。在并發(fā)的情況下,如果有不同的寫請求過來,需要加鎖去保證寫沖突不會發(fā)生。從上可知,Unique 表引擎需要一定代價,是在真正需要此場景的表里才會需要用到的表引擎。
Bucket 表
Snowflake 提出了 cluster table 的概念,即當一個表的數(shù)據(jù)量比較大時能夠?qū)Ρ淼臄?shù)據(jù)進行再分片。即使是同一個 Partition 中的數(shù)據(jù),也希望能夠再分片,增加整個系統(tǒng)的并行度,并利用分片的 key 做性能優(yōu)化。
Bucket 表在 ByConity 中需要以下語句來實現(xiàn):
- 在 DDL 指定 cluster key,以及把表建成多少個 Bucket
CREATE TABLE t(...)
CLUSTER BY (column, expression, ...) INTO 32 BucketS
- Bucket 后期可通過 ALTER TABLE修改
ALTER TABLE t CLUSTER BY (column, expression, ...) INTO 64 BucketS
- 也可以把 Bucket 表整個 drop 掉
ALTER TABLE t DROP CLUSTER
需要使用 Bucket 表的場景
首先表的數(shù)據(jù)要足夠大,一個 Partition 的數(shù)據(jù)要產(chǎn)生足夠多且比較大的 Parts,?少需要顯著多于 worker 的數(shù)量,不至于產(chǎn)生很多的小文件。另外要有一些性能優(yōu)化的場景,有助于查詢中性能的提升。
使用Bucket 表的收益
- 針對 cluster key 的點查可以過濾掉大部分數(shù)據(jù),降低 ΙΟ 量以獲得更短的執(zhí)?時間和更?的并發(fā)QPS
- 針對 cluster key 聚合計算,計算節(jié)點可以在數(shù)據(jù)子集進行預(yù)計算,實現(xiàn)更小的內(nèi)存占用和更短的執(zhí)行時間
- 在兩張表或多張表 join 時,針對 cluster key 可以獲得 co-located join 的優(yōu)化,極大程度上降低 shuffle 的數(shù)據(jù)量并得到更短的執(zhí)行時間,提升查詢效率。
Cluster key 的選擇
用 Bucket 表的時候,需要注意 cluster key 的選擇,選擇的時候要盡量去選在查詢條件中經(jīng)常會用到的組合的 column、經(jīng)常需要聚合的 column,以及 join 時的一些 join key。
分桶數(shù)量的選擇
分桶數(shù)量可以參考 worker 的數(shù)量。做 Bucket 表一定程度上的目的是能夠盡量發(fā)揮多個 worker 的計算能力去進行并行計算。所以在分桶數(shù)量選擇上可以盡量地去選 worker 的倍數(shù),比如 1 倍或者 2 倍。
Recluster
分桶指定好了可以改變,但是改變需要一定的代價,需要數(shù)據(jù)的重新分配。因此建議盡量在必要的時候才進行 recluster 的操作。
數(shù)據(jù)湖支持
ClickHouse 支持以外表的形式讀取 Hive 以及 Hudi/Iceberg 等格式。這些外表都是以本地單機表的形式存在,因此性能并不能令人滿意。且實現(xiàn)上較為割裂,使用起來較為不便。目前 Hive 僅能支持讀取 HDFS 上數(shù)據(jù),Hudi/Iceberg 僅能支持讀取S3 上的數(shù)據(jù)。
ByConity 通過統(tǒng)一的 Multi-catalog 的架構(gòu),極大增強了使用外表的便捷性。
ByConity Multi-Catalog
Multi-Catalog 的設(shè)計允許用戶在同一個 Hive 實例中同時連接多個不同的存儲和元數(shù)據(jù)服務(wù),而不必為每個存儲創(chuàng)建單獨的 Hive 實例。這簡化了數(shù)據(jù)管理和查詢的復(fù)雜性,使組織能夠更好地管理和利用其多樣化的數(shù)據(jù)資源。目前已經(jīng)支持的外部 Catalog 有:Hive,Apache Hudi,AWS Glue。
用戶可以使用創(chuàng)建一個基于 Hive 和 S3 存儲的 Catalog
create external catalog hive_s3properties type='hive', hive.metastore.uri = 'thrift://localhost:9083';
然后使用三段式的命名來直接訪問 Hive 外表
select * from hive_s3.tpcds.call_center;
也可以使用 query 來查看 external catalog 相關(guān)的信息
-- display information releated to hive_s3show create external catalog hive_s3;-- show databases in hive_s3show databases from hive_s3;-- show tables in tpcds database in hive.show tables from hive_s3.tpcds;
ByConity Hive 外表
ByConity CnchHive 可以充分使用 Virtual Warehouse 的計算資源執(zhí)行查詢。支持 HDFS 和 S3 文件系統(tǒng)。為了優(yōu)化性能,ByConity Hive 外表支持統(tǒng)計信息集成優(yōu)化器,它可以根據(jù)數(shù)據(jù)的統(tǒng)計信息自動選擇理想的執(zhí)行計劃。統(tǒng)計信息集成優(yōu)化器可以在 benchmark 中顯著提高查詢性能。目前ByConity Hive 外表不僅能完整跑通 TPC-DS 基準測試,同時在性能方面表現(xiàn)出色。
CREATE TABLE tpcds_100g_parquet_s3.call_centerENGINE = CnchHive('thrift://localhost:9083', 'tpcds', 'call_center')SETTINGS vw_default = 'vw_default';
ByConity Hudi 外表
ByConity 實現(xiàn)了對 Apache Hudi Copy-On-Write 表的進行快照查詢。在開啟 JNI Reader 后可以支持 Merge-On-Read 表的讀取。Hudi 支持同步 HiveMetastore,因此 ByConity 可以通過 HiveMetastore 感知 Hudi 表。
CREATE TABLE hudi_tableENGINE = CnchHudi('thrift://localhost:9083', 'hudi', 'trips_cow')SETTINGS vw_default = 'vw_default';
總結(jié)
下表總結(jié)了 ClickHouse 和 ByConity 之間的一些不同點,幫助大家有一個比較清晰的了解。除此之外,ByConity 還有很多特性。歡迎關(guān)注更多相關(guān)的內(nèi)容分享。
加入社區(qū)
對于一個開源項目,引入更多參與者、讓社區(qū)往多元化方向發(fā)展往往是重要目標之一,ByConity 也不例外。我們積極與社區(qū)成員共同探討和解決大家在試用過程中遇到的問題,團隊有耐心、也有信心,更是非常期待未來能夠與更多開發(fā)者和合作伙伴一起共建共享,激發(fā)更多創(chuàng)造力。歡迎加入 ByConity 社區(qū),與我們共建~
(舉報)