分布式数据库产品总结
分布式數(shù)據(jù)庫產(chǎn)品總結(jié)
- Pivotal
- Greenplum Database(GPDB)
- 架構(gòu)
- 查詢計劃并執(zhí)行
- 查詢優(yōu)化
- 索引
- blink tree
- 執(zhí)行器
- 數(shù)據(jù)shuffle
- 分布式事務(wù)
- 2PC
- gp實現(xiàn)
- gp優(yōu)化
- MVCC
- 特點
- HTAP
- HAWQ
- Snowflake Elastic Data Warehouse
- 數(shù)據(jù)存儲
- 虛擬數(shù)據(jù)倉庫實例(Virtual Warehouse)
- AnalyticDB
- 系統(tǒng)架構(gòu)
- 保證
- 存儲引擎
- 讀寫過程
- 數(shù)據(jù)合并
- 行列混存
- inverted index
- 元數(shù)據(jù)
- 索引管理
- 索引構(gòu)建
- 優(yōu)化器
- 執(zhí)行引擎
- 總結(jié)
- PolarDB/PolarFS
- 讀寫流程
- ParallelRaft
- PolarFS
- 事務(wù)的數(shù)據(jù)可見性問題
- DDL問題
- Change Buffer問題
- Polar-X
- ClickHouse
- 設(shè)計目標(biāo)
- ClickHouse存儲引擎
- 計算引擎
- ClickHouse總結(jié)
- TiDB
- TiFlash
- C-Store(2005)/Vertica
- Apache ORC
- Dremel (2010) / Apache Parquet
- Impala
- 查詢流程
- Druid
- Pinot
- mongoDB
- 參考鏈接
Pivotal
Greenplum Database(GPDB)
**Greenplum Database(GPDB)**是一款基于開源 PostgreSQL 擴展的 MPP(massively parallel processing),可支持大規(guī)模水平擴展的分布式數(shù)據(jù)庫。 GPDB 采用的是 master-worker 模式,每個 worker process 運行在不同的機器上,擁有各自的存儲和運算資源。**客戶端通過 master 把查詢語句分發(fā)到各個機器上,以達(dá)到并行計算來處理海量數(shù)據(jù)。**集群節(jié)點(無論是master還是segemnt)上的每個實例都是一個物理上獨立的PostgrepSQL數(shù)據(jù)庫。
Greenplum數(shù)據(jù)庫是一種shared nothing的分析型MPP數(shù)據(jù)庫。這種模型與高度規(guī)范化的/事務(wù)型的SMP數(shù)據(jù)庫有顯著區(qū)別。Greenplum數(shù)據(jù)庫使用非規(guī)范化的模式設(shè)計會工作得最好,非規(guī)范化的模式適合于MPP分析型處理,例如帶有大型事實表和較小維度表的星形模式或者雪花模式。
Greenplum 在 PostgreSQL 之上還添加了大量其他功能,例如 Append-Optimized 表、列存表、外部表、多級分區(qū)表、細(xì)粒度資源管理器、ORCA 查詢優(yōu)化器、備份恢復(fù)、高可用、故障檢測和故障恢復(fù)、集群數(shù)據(jù)遷移、擴容、MADlib 機器學(xué)習(xí)算法庫、容器化執(zhí)行 UDF、PostGIS 擴展、GPText 套件、監(jiān)控管理、集成 Kubernetes 等。
架構(gòu)
- master: 保存元數(shù)據(jù)而不保存用戶數(shù)據(jù),有用戶表信息,優(yōu)化器使用這些信息進(jìn)行查詢優(yōu)化和計劃生成
- segment:每個segment保存用戶數(shù)據(jù)表的一部分。在 Greenplum 中,用戶數(shù)據(jù)按照某種策略分散到不同節(jié)點的不同 segment 實例中。
使用標(biāo)準(zhǔn)的 INSERT SQL 語句可以將數(shù)據(jù)自動按照用戶定義的策略分布到合適的節(jié)點,然而 INSERT 性能較低,僅適合插入少量數(shù)據(jù)。Greenplum 提供了專門的并行化數(shù)據(jù)加載工具以實現(xiàn)高效數(shù)據(jù)導(dǎo)入,詳情可以參考 gpfdist 和 gpload 的官方文檔。
在數(shù)據(jù)分布方面,Greenplum 在這方面不單單做到了基本的分布式數(shù)據(jù)存儲,還提供了很多更高級靈活的特性,譬如多級分區(qū)、多態(tài)存儲。Greenplum 6 進(jìn)一步增強了這一領(lǐng)域,實現(xiàn)了一致性哈希和復(fù)制表,并允許用戶根據(jù)應(yīng)用干預(yù)數(shù)據(jù)分布方法。有這么多種手段,可見Greenplum用戶肯定時遇到了很多數(shù)據(jù)傾斜的問題
Greenplum支持的分區(qū)方法有:
范圍分區(qū):根據(jù)某個列的時間范圍或者數(shù)值范圍對數(shù)據(jù)分區(qū)。譬如以下 SQL 將創(chuàng)建一個分區(qū)表,該表按天分區(qū),從 2016-01-01 到 2017-01-01 把全部一年的數(shù)據(jù)按天分成了 366 個分區(qū):
CREATE TABLE sales (id int, date date, amt decimal(10,2)) DISTRIBUTED BY (id) PARTITION BY RANGE (date) ( START (date '2016-01-01') INCLUSIVE END (date '2017-01-01') EXCLUSIVEEVERY (INTERVAL '1 day') );列表分區(qū):按照某個列的數(shù)據(jù)值列表,將數(shù)據(jù)分不到不同的分區(qū)。譬如以下 SQL 根據(jù)性別創(chuàng)建一個分區(qū)表,該表有三個分區(qū):一個分區(qū)存儲女士數(shù)據(jù),一個分區(qū)存儲男士數(shù)據(jù),對于其他值譬如 NULL,則存儲在單獨 other 分區(qū)。
CREATE TABLE rank (id int, rank int, year int, gender char(1), count int ) DISTRIBUTED BY (id) PARTITION BY LIST (gender) ( PARTITION girls VALUES ('F'), PARTITION boys VALUES ('M'), DEFAULT PARTITION other );Greenplum 支持多態(tài)存儲,即單張用戶表,可以根據(jù)訪問模式的不同使用不同的存儲方式存儲不同的分區(qū)。通常不同年齡的數(shù)據(jù)具有不同的訪問模式,不同的訪問模式有不同的優(yōu)化方案。多態(tài)存儲以用戶透明的方式為不同數(shù)據(jù)選擇最佳存儲方式,提供最佳性能。Greenplum 提供以下存儲方式:
- 堆表(Heap Table):堆表是 Greenplum 的默認(rèn)存儲方式,也是 PostgreSQL 的存儲方式。支持高效的更新和刪除操作,訪問多列時速度快,通常用于 OLTP 型查詢。
- Append-Optimized 表:為追加而專門優(yōu)化的表存儲模式,通常用于存儲數(shù)據(jù)倉庫中的事實表。不適合頻繁的更新操作。
- AOCO (Append-Optimized, Column Oriented) 表:AOCO 表為列表,具有較好的壓縮比,支持不同的壓縮算法,適合訪問較少的列的查詢場景。
- 外部表:外部表的數(shù)據(jù)存儲在外部(數(shù)據(jù)不被 Greenplum 管理),Greenplum 中只有外部表的元數(shù)據(jù)信息。Greenplum 支持很多外部數(shù)據(jù)源譬如 S3、HDFS、文件、Gemfire、各種關(guān)系數(shù)據(jù)庫等和多種數(shù)據(jù)格式譬如 Text、CSV、Avro、Parquet 等。
存儲方式和分區(qū)方式相組合,可以對一張表不同的數(shù)據(jù)區(qū)域有不同的存儲方式。
數(shù)據(jù)分布是任何 MPP 數(shù)據(jù)庫的基礎(chǔ),也是 MPP 數(shù)據(jù)庫是否高效的關(guān)鍵之一。通過把海量數(shù)據(jù)分散到多個節(jié)點上,一方面大大降低了單個節(jié)點處理的數(shù)據(jù)量,另一方面也為處理并行化奠定了基礎(chǔ),兩者結(jié)合起來可以極大的提高整個系統(tǒng)的性能。譬如在一百個節(jié)點的集群上,每個節(jié)點僅保存總數(shù)據(jù)量的百分之一,一百個節(jié)點同時并行處理,性能會是單個配置更強節(jié)點的幾十倍。如果數(shù)據(jù)分布不均勻出現(xiàn)數(shù)據(jù)傾斜,受短板效應(yīng)制約,整個系統(tǒng)的性能將會和最慢的節(jié)點相同。因而數(shù)據(jù)分布是否合理對 Greenplum 整體性能影響很大。
Greenplum 6 提供了以下數(shù)據(jù)分布策略。
查詢計劃并執(zhí)行
PostgreSQL 生成的查詢計劃只能在單節(jié)點上執(zhí)行,Greenplum 需要將查詢計劃并行化,以充分發(fā)揮集群的優(yōu)勢。
Greenplum 引入 Motion 算子(操作符)實現(xiàn)查詢計劃的并行化。Motion 算子實現(xiàn)數(shù)據(jù)在不同節(jié)點間的傳輸,它為其他算子隱藏了 MPP 架構(gòu)和單機的不同,使得其他大多數(shù)算子不用關(guān)心是在集群上執(zhí)行還是在單機上執(zhí)行。每個 Motion 算子都有發(fā)送方和接收方。此外 Greenplum 還對某些算子進(jìn)行了分布式優(yōu)化,譬如聚集。
- 開源分布式數(shù)據(jù)庫Greenplum并行執(zhí)行引擎揭秘
- motion:MPP架構(gòu)下必須有motion算子,協(xié)調(diào)數(shù)據(jù)分布,這是執(zhí)行計劃中很重要的一步。
- dispatcher:分配QE資源,配置Slice,分發(fā)任務(wù)(plan+slicetable --> 還可以分發(fā)一些純文本的命令、兩階段提交、CdbDispatchUtilityStatementvectoring中的分發(fā)語法樹(一些語法信息只有QE上有)),協(xié)調(diào)控制(控制、等待下發(fā)的任務(wù)的狀態(tài))
- interconnect:QE之間數(shù)據(jù)傳送的模塊
- 引入udp主要是為了解決OLAP查詢在大集群中使用連接資源過多的問題
- 可靠的UDP (RUDP)
- interconnect主要遇到的問題就是連接數(shù)不夠用和穩(wěn)定性這兩方面的問題,所以考慮:
- QUIC協(xié)議
- Proxy協(xié)議(感覺有點服務(wù)治理的意思了)
- 引入udp主要是為了解決OLAP查詢在大集群中使用連接資源過多的問題
查詢優(yōu)化
索引
- greenplum中的索引都是二級索引(非聚集索引)
- 物理上是存儲在獨立的文件中的(獨立于表的數(shù)據(jù)文件)
- 并且也是按分片存儲在每個segment上,其索引內(nèi)容對應(yīng)segement上的數(shù)據(jù)分片
- 不同于原生blink樹,兄弟節(jié)點之間使用右向指針,greenplum采用雙向指針
- 物理結(jié)構(gòu)上,每個頁包含索引元組(和boltdb差不多),special中存儲了頁面級的元信息:
- 兄弟指針
- 頁面類型
- 等等
- 葉子節(jié)點的填充率最高是90%,內(nèi)部節(jié)點(非葉子節(jié)點)的填充率最高是70%,不填滿是為了方式insert會造成頻繁的頁分裂。
blink tree
要點總結(jié)
執(zhí)行器
- QD(Query Dispatcher、查詢調(diào)度器):Master 節(jié)點上負(fù)責(zé)處理用戶查詢請求的進(jìn)程稱為 QD(PostgreSQL 中稱之為 Backend 進(jìn)程)。 QD 收到用戶發(fā)來的 SQL 請求后,進(jìn)行解析、重寫和優(yōu)化,將優(yōu)化后的并行計劃分發(fā)給每個 segment 上執(zhí)行,并將最終結(jié)果返回給用戶。此外還負(fù)責(zé)整個 SQL 語句涉及到的所有的 QE 進(jìn)程間的通訊控制和協(xié)調(diào),譬如某個 QE 執(zhí)行時出現(xiàn)錯誤時,QD 負(fù)責(zé)收集錯誤詳細(xì)信息,并取消所有其他 QEs;如果 LIMIT n 語句已經(jīng)滿足,則中止所有 QE 的執(zhí)行等。QD 的入口是 exec_simple_query()。主要是火山模型
- QE(Query Executor、查詢執(zhí)行器):Segment 上負(fù)責(zé)執(zhí)行 QD 分發(fā)來的查詢?nèi)蝿?wù)的進(jìn)程稱為 QE。Segment 實例運行的也是一個 PostgreSQL,所以對于 QE 而言,QD 是一個 PostgreSQL 的客戶端,它們之間通過 PostgreSQL 標(biāo)準(zhǔn)的 libpq 協(xié)議進(jìn)行通訊。對于 QD 而言,QE 是負(fù)責(zé)執(zhí)行其查詢請求的 PostgreSQL Backend 進(jìn)程。通常 QE 執(zhí)行整個查詢的一部分(稱為 Slice)。QE 的入口是 exec_mpp_query()。
- Slice:為了提高查詢執(zhí)行并行度和效率,Greenplum 把一個完整的分布式查詢計劃從下到上分成多個 Slice,每個 Slice 負(fù)責(zé)計劃的一部分。劃分 slice 的邊界為 Motion,每遇到 Motion 則一刀將 Motion 切成發(fā)送方和接收方,得到兩顆子樹。每個 slice 由一個 QE 進(jìn)程處理。上面例子中一共有三個 slice。
- Gang:在不同 segments 上執(zhí)行同一個 slice 的所有 QEs 進(jìn)程稱為 Gang。
數(shù)據(jù)shuffle
相鄰 Gang 之間的數(shù)據(jù)傳輸稱為數(shù)據(jù)洗牌(Data Shuffling)。數(shù)據(jù)洗牌和 Slice 的層次相吻合,從下到上一層一層通過網(wǎng)絡(luò)進(jìn)行數(shù)據(jù)傳輸,不能跨層傳輸數(shù)據(jù)。根據(jù) Motion 類型的不同有不同的實現(xiàn)方式,譬如廣播和重分布。
Greenplum 實現(xiàn)數(shù)據(jù)洗牌的技術(shù)稱為 interconnect,它為 QEs 提供高速并行的數(shù)據(jù)傳輸服務(wù),不需要磁盤 IO 操作,是 Greenplum 實現(xiàn)高性能查詢執(zhí)行的重要技術(shù)之一。interconnect 只用來傳輸數(shù)據(jù)(表單的元組),調(diào)度、控制和錯誤處理等信息通過 QD 和 QE 之間的 libpq 連接傳輸。
Interconnect 有 TCP 和 UDP 兩種實現(xiàn)方式,TCP interconnect 在大規(guī)模集群中會占用大量端口資源,因而擴展性較低。Greenplum 默認(rèn)使用 UDP 方式。UDP interconnect 支持流量控制、網(wǎng)絡(luò)包重發(fā)和確認(rèn)等特性。
分布式事務(wù)
Greenplum 使用兩階段提交(2PC)協(xié)議實現(xiàn)分布式事務(wù)。2PC 是數(shù)據(jù)庫經(jīng)典算法,此處不再贅述。本節(jié)概要介紹兩個 Greenplum 分布式事務(wù)的實現(xiàn)細(xì)節(jié):
(更正:應(yīng)該不是2pc,應(yīng)該就是MVCC)
- 分布式事務(wù)快照:實現(xiàn) master 和不同 segment 間一致性
- 共享本地快照:實現(xiàn) segment 內(nèi)不同 QEs
在 QD 開始一個新的事務(wù)(StartTransaction)時,它會創(chuàng)建一個新的分布式事務(wù) id、設(shè)置時間戳及相應(yīng)的狀態(tài)信息;在獲取快照(GetSnapshotData)時,QD 創(chuàng)建分布式快照并保存在當(dāng)前快照中。和單節(jié)點的快照類似,分布式快照記錄了 xmin/xmax/xip 等信息。這些信息被用于確定元組的可見性(HeapTupleSatisfiesMVCC)。
和 PostgreSQL 的提交日志 clog 類似,Greenplum 需要保存全局事務(wù)的提交日志,以判斷某個事務(wù)是否已經(jīng)提交。這些信息保存在共享內(nèi)存中并持久化存儲在 distributedlog 目錄下。
為了提高判斷本地 xid 可見性的效率,避免每次訪問全局事務(wù)提交日志,Greenplum 引入了本地事務(wù)-分布式事務(wù)提交緩存
2PC
greenplum基于PG,雖然PG沒有分布式事務(wù)管理器,但是支持2階段提交2pc
PREPARE TRANSACTION COMMIT PREPARED ROLLBACK PREPAREDprepare之后持有的行鎖不會被釋放,就算宕機,重啟pg節(jié)點之后鎖還是在的(數(shù)據(jù)庫會將prepare寫進(jìn)事務(wù)日志,需要進(jìn)行負(fù)責(zé)恢復(fù)),方便后續(xù)協(xié)調(diào)者cordinator繼續(xù)對該事務(wù)進(jìn)行操作
gp實現(xiàn)
gp在pg的基礎(chǔ)上,實現(xiàn)了:
gp優(yōu)化
理論上,如果參與者只有1個,2pc可以簡化為1pc(Bernstein稱為協(xié)調(diào)權(quán)的轉(zhuǎn)移,因為只有一個參與者的話,就不需要協(xié)調(diào)者了)
- 滿足1pc的條件:
- 有寫操作,但是參與者只有1個
- 只讀事務(wù),也不需要2pc
MVCC
- Greenplum內(nèi)核揭秘之MVCC并發(fā)控制
主流數(shù)據(jù)庫三大并發(fā)控制方法:
事務(wù)的本質(zhì)就是將多個步驟捆綁為原子的步驟,要么都成功,要么都不成功,事務(wù)的中間狀態(tài)不應(yīng)該被其他事務(wù)看到(隔離isolation)。
greenplum只實現(xiàn)了read commited和repeatable read.
MVCC主要為了解決讀寫沖突。
- heaptuple用于整整存儲每行數(shù)據(jù) |t_xmin|t_xmax|t_cid|t_ctid|t_infomaskt2|t_infomask|NULL_bitmap|userdata|
- Xmin:創(chuàng)建tuple的事務(wù)ID
- Xmax:刪除tuple的事務(wù)ID,有時用于行鎖(有事務(wù)在更新該行,通過配合infomask中的HEAP_XMAX_EXCL_LOCK完成)
- cid:事物內(nèi)的查詢命令編號,用戶跟蹤事務(wù)內(nèi)部的可見性,創(chuàng)建cursor(游標(biāo))和更改cursor中的內(nèi)容,這兩步需要保證看到的事務(wù)是一樣的。
- ctid:指向下一個版本tuple的指針,由兩個成員blocknumber和offset組成
- 這個和mysql不同,mysql存儲的是增量信息
- t_infomask用以加速可見性的查詢,標(biāo)記優(yōu)化,比用每次都去看mvcc快照或者pg_clog
- heappage用于存每個heaptuple的偏移量
- greenplum使用mvcc快照,在pg的2pc之上提供隔離級別的保證
- 快照理論上是一個正在運行的事務(wù)列表
- greenplum使用快照判斷一個事務(wù)是否已提交,其中包含如下信息:
- Xmin:所有小于Xmin的事務(wù)都已經(jīng)提交
- Running:正在執(zhí)行的事務(wù)列表,這里面保存的所有事務(wù)都是未提交的,不在這里面,并且處于水位之間的id就是已經(jīng)提交的
- Xmax:所有大于等于Xmax的事務(wù)都未提交
- 該快照中只存儲了事務(wù)commited或running狀態(tài),如果需要查詢abort狀態(tài),需要查詢pg_clog(事務(wù)日志)。(事務(wù)在abort的時候不需要更改行中的t_xmax)
- 在READ COMMITTED隔離級別下,每個查詢開始時生成快照
- 在REPEATABLE READ隔離界別下,在每個事務(wù)開始時生成快照
- 在一眾版本中,某個事務(wù)必然只能看到其中一個,所以事務(wù)需要判斷快照的可見性
- 在視頻22:50講解的很詳細(xì)
- 寫寫沖突情況下,后面的事務(wù)會阻塞直到前面一個事務(wù)完成
一個transaction共有三種狀態(tài), committed,running,abort
特點
HTAP
2021 sigmod論文《Greenplum: A Hybrid Database for Transactional and Analytical Workloads》
HAWQ
針對 Hadoop 存儲的 SQL 執(zhí)行引擎。HAWQ 通過數(shù)據(jù)接口可以直接讀取 Hive 表里的數(shù)據(jù)(也支持原生存儲格式),然后用 SQL 執(zhí)行引擎來計算得到查詢結(jié)果。與 HiveQL 通過把 SQL 解析成一連串的 MapReduce job 的執(zhí)行模式相比,速度要快好幾個量級。HAWQ 雖然在開發(fā)執(zhí)行引擎過程中借鑒了很多 GPDB 的東西,但畢竟是一款不同的數(shù)據(jù)庫引擎,Pivotal 因此希望有一款兼容的優(yōu)化器能夠服務(wù)于它。由此,研發(fā)了開源優(yōu)化器 ORCA。
Snowflake Elastic Data Warehouse
除了使用了 vec-exec(畢竟,聯(lián)合創(chuàng)始人 Marcin 的博士畢業(yè)論文就是關(guān)于 vec-exec 的),Snowflake 也是一款 100%計算和存儲分離,面向云原生的數(shù)據(jù)倉庫系統(tǒng)。本文內(nèi)容主要參考他們發(fā)表于 SIGMOD-16 的 paper: The Snowflake Elastic Data Warehouse。
Snowlake 是 2012 年成立的,2015 年正式推出商用版本。2012 年,正是云服務(wù)起步不久,大數(shù)據(jù)熱火朝天的時候。當(dāng)時,數(shù)據(jù)倉庫的主流趨勢是 SQL On Hadoop。Cloudera, Hontornworks, MapR, Greenplum HAWQ, Facebook 的 Presto,算是百花齊放。但主創(chuàng)團隊認(rèn)為,RDBMS 不會消失,用戶們會因為上云的趨勢,想要一款完全適配云端的數(shù)據(jù)倉庫。
文章簡單介紹了市面上通常的 on-prem 分布式數(shù)據(jù)倉庫的一些缺點。首先就是計算和存儲硬件是耦合的,即每個服務(wù)器同時負(fù)責(zé)存儲數(shù)據(jù),并且執(zhí)行 SQL 語句得到結(jié)果。耦合的劣勢在于,不能針對不同的 workloads 做優(yōu)化。二就是服務(wù)器的 node membership 改變(無論是因為服務(wù)器損壞,或者是因為數(shù)據(jù)量提升需要擴容)對用戶來說都不友善。一,就是要進(jìn)行大量數(shù)據(jù)的 reshuffle。二是,為了做到高可用,可能會保留一部分 node 作為 stand-by replica,當(dāng)主節(jié)點有問題時,馬上接替主節(jié)點,這相當(dāng)于變相提高了數(shù)據(jù)成本。總結(jié)來說,on-prem 的數(shù)據(jù)倉庫要做到同時保持可伸縮性(elasticity)和高可用性(availability)并兼顧成本,是很難魚與熊掌兼得的。三就是對服務(wù)進(jìn)行升級比較麻煩。
由于云服務(wù)的出現(xiàn),很多上述的問題,變得不再是問題了。一就是,云服務(wù)通常會提供多種類型的服務(wù)器來針對特定的 usecase;二,服務(wù)器的下線,上線,擴容在云服務(wù)上都屬于基本操作;三是,云上有高可用,低成本的存儲系統(tǒng);四是,服務(wù)更新非常方便。基于這些原因,Snowflake 選擇了完完全全的計算和存儲分離的架構(gòu)設(shè)計。整個架構(gòu)分成三個大模塊:
數(shù)據(jù)存儲
在設(shè)計存儲系統(tǒng)的時候,Snowflake 有糾結(jié)過,是應(yīng)該使用 AWS 的 S3,還是自行設(shè)計類似于 HDFS 的存儲系統(tǒng)。最終,在經(jīng)過了各種比較,利弊權(quán)衡后,決定使用 S3。雖然,S3 的性能并不是最快;并且,由于是網(wǎng)絡(luò)接入,也不是最穩(wěn)定。但是,勝在高可用性和高可靠性上。團隊決定基于 S3 打造數(shù)據(jù)存儲系統(tǒng),同時,可以把精力放在優(yōu)化 local caching 和數(shù)據(jù)傾斜(skew resilience)上。
相對于本地文件系統(tǒng),S3 的 access latency 會更高,并且,由于是網(wǎng)絡(luò)接入(尤其是用 https),CPU 使用率也更高。而且,S3 本身就是一個簡單的 blob 存儲,支持的主要創(chuàng)建,刪除和讀取文件,即,不能對現(xiàn)有文件進(jìn)行更新,更新相當(dāng)于重新創(chuàng)建一個更新過的文件。但是,S3 的讀取有一大好處在于,可以讀取部分文件。
S3 的這些屬性,對于整個 Snowflake 的數(shù)據(jù)存儲和并行控制設(shè)計有重大的影響。首先,表數(shù)據(jù)被水平(horizontally partitioned)地切分成多個不可變的 blob 文件;每個文件通過列存(column-store)的形式保存數(shù)據(jù),Snowflake 具體使用的存儲格式是 PAX 的 Hybrid-column store(挖個坑,可以單獨講一期這個)。每個數(shù)據(jù)文件包含數(shù)據(jù)頭用來存儲元數(shù)據(jù)。基于 S3 的下載部分文件的 API,對于運行的 SQL 語句,優(yōu)化器會選擇只下載必須用到的數(shù)據(jù) block 即可。這也就意味著所有snowflake的事務(wù)都是基于快照隔離Snapshot Isolation(SI)
值得一提的是,Snowflake 不單單使用 S3 來存儲表數(shù)據(jù)文件,也用 S3 來存儲臨時生成的 intermediate result(語句執(zhí)行中,某個 operator 產(chǎn)生的臨時結(jié)果集)。一旦這些結(jié)果集的大小超過了本地磁盤空間,spill 到磁盤上的文件就會以 S3 的形式存儲。這樣的好處在于,可以讓 Snowflake 真正可以處理巨大的數(shù)據(jù)而不用擔(dān)心內(nèi)存或者本地磁盤空間吃緊。另一個好處在于,這些臨時結(jié)果集也可能被利用作為 cache 使用。
最后文中還提到了數(shù)據(jù)庫的其他元數(shù)據(jù)存儲,包括有哪些 caching 文件,每個表存在了哪些 S3 文件中,等等,都是存儲在一個 transactional 的 key-value store 中,并不在 S3 里。
虛擬數(shù)據(jù)倉庫實例(Virtual Warehouse)
執(zhí)行 SQL 語句:每個語句 instance 都只會運行在一個 VW 上;每個 VW 有多個 WN;每個 WN 只隸屬于一個 VW,不會被共享。(這邊有注解說,WN 變成共享的會是一個未來的工作,因為可以更好地提升使用率并且會進(jìn)一步降低用戶成本)。當(dāng)一個語句被運行時,所有的 WN 在這個 VW 上,(或者也可能是一部分 WN,如果優(yōu)化器認(rèn)為這是一個非常輕量級的語句),都會起一個 worker process,這個進(jìn)程的生命周期就是這句語句的執(zhí)行周期。worker process ,在執(zhí)行的過程中,不會對外部資源造成任何變化,換言之,no side effect,即使是 update 語句。為什么這么說呢,因為所有的表數(shù)據(jù)文件都是 immutable 的。這樣帶來的好處就是,如果 worker process 由于各種原因崩潰了, 通常只是需要 retry 即可,沒有其他善后事宜要做。現(xiàn)在 VW 里還不支持 partial retry,這也在未來計劃的工作中。
由于 VW 的可伸縮性(elasticity),通常情況下,可以通過起一個更大 size 的 VW 來提升語句的性能,但保持一樣的使用成本。例如,**一個復(fù)雜的分析語句在一個 4 節(jié)點 VW 上需要運行 15 個小時,但在一個 32 節(jié)點 VW 上只需要 2 小時。**因為是云原生,用戶只需要支付運行 VW 時的費用即可。因此,在價格不變的情況下,用戶體驗和查詢速度卻大幅度提升。這也是 Snowflake 云原生數(shù)據(jù)倉庫的一大賣點。
- 本地緩存: 每個 WN 都會用本地文件為表數(shù)據(jù)做本地緩存,即已經(jīng)被從 S3 那讀取的數(shù)據(jù)文件。這些文件是包含元數(shù)據(jù)信息和要用到的 column 的數(shù)據(jù)。這些緩存的數(shù)據(jù)文件可以被多個 worker process 共享(如果需要讀取一樣的數(shù)據(jù)),文中提到維護(hù)了一個簡單的 LRU 的 cache replacement 策略,效果非常不錯。為了進(jìn)一步提升 hit rate,同一份數(shù)據(jù)文件被多個 WN 節(jié)點保存,優(yōu)化器會用 consistent hashing 算法,來分配哪些節(jié)點保存哪些數(shù)據(jù)。同時,對于后續(xù)要讀取對應(yīng)數(shù)據(jù)的語句,優(yōu)化器也會根據(jù)這個分配發(fā)送到對應(yīng)節(jié)點。
- 數(shù)據(jù)傾斜處理:一些節(jié)點可能相對于其他節(jié)點,運行更慢,比如硬件問題或者是單純網(wǎng)絡(luò)問題。Snowflake 的優(yōu)化是,每個 WN 在讀取了相應(yīng)的數(shù)據(jù)文件后,當(dāng)它發(fā)現(xiàn)其他 WN 還在讀取,他會發(fā)送請求給其他 WN 要求分擔(dān)更多的數(shù)據(jù),而且這些數(shù)據(jù)直接從 S3 讀取。從而來確保不要把過多的數(shù)據(jù)處理放在速度慢的 WN 上。
- 執(zhí)行引擎:雖說可以通過增加節(jié)點來提升性能,但是 Snowflake 依然希望每一個節(jié)點的單體性能都能做到極致。因此,Snowflake 構(gòu)建了自己的,基于列存,向量執(zhí)行(vec-exec),并且是 push-based(推模式)的執(zhí)行引擎。
- Columnar: 沒啥爭議,對于 OLAP 語句來說,Columnar-store 無論從存儲,讀取效率和執(zhí)行效率來說,都優(yōu)于 row-store。
- Vec-exec:也沒有爭議,Marcin 肯定把 Vec-Exec 這套運行優(yōu)化放到執(zhí)行器上。
- push-based: 相對于 Volcano 的拉模式,是下方的 operator,當(dāng)處理完數(shù)據(jù)后,把數(shù)據(jù) push 到上方的 operator(從執(zhí)行計劃角度來看上下),類似于 code-gen,這樣的好處是提高了 cache 的利用率,因為可以避免不必要的循環(huán)控制語句。
- 另一點就是,一些其他傳統(tǒng)數(shù)據(jù)庫系統(tǒng)在執(zhí)行語句時需要考慮的麻煩,對于 Snowflake 來說沒有。比如,不用 transaction management,因為所有的語句都是沒有 side effect 的。(原因是S3中的文件不可以更改)
AnalyticDB
數(shù)據(jù)庫帶來的新挑戰(zhàn):
Oracle RAC --> Greenplum --> HBase --> AnalyticDB
ADB主要是OLAP系統(tǒng),同時要顧及各種點查詢、優(yōu)化的速度。底層采用盤古,所以數(shù)據(jù)庫主要的創(chuàng)新點在數(shù)據(jù)格式、優(yōu)化器、執(zhí)行器等等
系統(tǒng)架構(gòu)
AnalyticDB主要分為以下幾個部分:
為便于大規(guī)模分析處理,AnalyticDB對數(shù)據(jù)表進(jìn)行分區(qū)。AnalyticDB數(shù)據(jù)表有兩個分區(qū)級別:一級分區(qū)和二級分區(qū)。
選擇具有較高基數(shù)(cardinality)的列作為一級分區(qū)鍵,以保證數(shù)據(jù)行能均勻地分布到每個一級分區(qū),最大化并行。用戶還可以根據(jù)需要定義二級分區(qū),以便進(jìn)行數(shù)據(jù)的自動管理。二級分區(qū)擁有最大分區(qū)數(shù),當(dāng)二級分區(qū)的實際數(shù)目超過了這個最大分區(qū)數(shù)后,最老的二級分區(qū)會被自動刪除。通常,選擇時間列(天、周或月)作為二級分區(qū)列,這樣,包含相同時間序列的數(shù)據(jù)行,會被劃分到同一個二級分區(qū)中。
傳統(tǒng)OLAP系統(tǒng)在同一個鏈路上同時處理讀寫請求,因此,所有的并發(fā)讀寫請求都共享同一個資源池,也會互相影響。但是當(dāng)讀寫并發(fā)同時非常大時,這種設(shè)計會由于過度的資源競爭而導(dǎo)致不好的性能。如圖5所示,為了解決這個問題,同時確保讀和寫的高性能,AnalyticDB采用的架構(gòu)為讀寫分離架構(gòu),即AnalyticDB有獨立的讀寫節(jié)點各自處理讀寫請求,且寫節(jié)點和讀節(jié)點完全互相隔離。
保證
存儲引擎
AnalyticDB存儲層采用Lambda架構(gòu),讀節(jié)點上的數(shù)據(jù)包括基線數(shù)據(jù)和增量數(shù)據(jù)兩部分。增量數(shù)據(jù)又分為Incremental Data和Deleted bitset,按照行列混存的架構(gòu)存放在讀節(jié)點的SSD上。真正讀取是,basline數(shù)據(jù)要和增量數(shù)據(jù)做UNION和MINUS之后,才能輸出有效數(shù)據(jù)。
對于每張表,每k行的數(shù)據(jù)組成一個Row Group。Row Group中的數(shù)據(jù)連續(xù)存放在磁盤中。整個Row Group中,又將數(shù)據(jù)按照列(聚集列)分別順序存放。AnalyticDB會對每列構(gòu)建一份元數(shù)據(jù),用于維護(hù)列數(shù)據(jù)的統(tǒng)計信息(包括Cardinality、Sum和Min/Max等)、字典數(shù)據(jù)(采用字典編碼)以及物理映射等。AnalyticDB默認(rèn)會對每一列數(shù)據(jù)建立索引,索引中的Key是列的值,Value是值出現(xiàn)的所有行號集合,采用后臺異步構(gòu)建模式。由于增量數(shù)據(jù)部分沒有索引,隨著數(shù)據(jù)的不斷實時寫入,增量數(shù)據(jù)的查詢性能會越來越慢。AnalyticDB采用后臺任務(wù)來合并基線數(shù)據(jù)和增量數(shù)據(jù)形成一個新的基線數(shù)據(jù),并基于新的基線數(shù)據(jù)構(gòu)建全量索引。
讀寫過程
使用copy on write技術(shù)(OLAP讀多寫少)來支持MVCC,delete數(shù)據(jù)被轉(zhuǎn)化在Deleted bitset上,而update操作則被分為Incremental Data和Deleted bitset分別存放。每個寫操作都會分配獨立的LSN,從而達(dá)到MVCC
由于建立了全列倒排索引,所以執(zhí)行引擎處理返回結(jié)果的時候用到了多路歸并
數(shù)據(jù)合并
由于沒有全局索引,隨著數(shù)據(jù)的不斷實時寫入,增量數(shù)據(jù)的查詢性能會越來越慢。因此ADB會在后臺通過伏羲啟動一個MapReduce 任務(wù)來合并基線數(shù)據(jù)和增量數(shù)據(jù)(同時去掉標(biāo)記為刪除的數(shù)據(jù))形成一個新的基線數(shù)據(jù),并基于新的基線數(shù)據(jù)構(gòu)建全量索引。
在合并任務(wù)開始時,一部分增量數(shù)據(jù)會標(biāo)記為immutable,并執(zhí)行合并,合并完成之后,之前的baseline data和immutable會被刪除
行列混存
在海量數(shù)據(jù)分析場景下,數(shù)據(jù)分析業(yè)務(wù)主要有以下三類workload:
在ADB的實現(xiàn)中,每K行數(shù)據(jù)實現(xiàn)了Row Group,每個row group中的每個列存放在自己的block中,Row group按照索引排列
inverted index
為了應(yīng)對ad-hoc,ADB對每列建立了倒排索引,從而提高復(fù)雜數(shù)據(jù)的查詢效率。(每列都建立索引,不就是倒排索引了)
元數(shù)據(jù)
為了加速查詢,AnalyticDB對每列構(gòu)建一份元數(shù)據(jù),并保存在一個叫detail_meta的單獨文件中。detail_meta文件通常較小(小于1MB),首次查詢時被加載在內(nèi)存中。如圖8左邊所示,元數(shù)據(jù)主要包括4部分:
- Header。包括版本號,文件長度以及一些統(tǒng)計信息。
- 列統(tǒng)計信息。包括行數(shù),NULL值數(shù),cardinality,SUM,MAX和MIN 值。優(yōu)化器根據(jù)這些信息來生成最佳執(zhí)行計劃。
- 字典。對于cardinality較少(小于1024)的列,AnalyticDB采用字典編碼,數(shù)據(jù)文件里保存字典號碼。字典保存在該字段中。
- 塊地址信息。保存塊號到數(shù)據(jù)文件起始地址和長度的映射關(guān)系。(我猜測是每次合并的時候更新)
索引管理
AnalyticDB設(shè)計和實現(xiàn)了一個新的索引引擎,在不影響寫入性能的情況下,支持結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù)類型索引。它將構(gòu)建過程從寫入鏈路中移除,采用后臺異步構(gòu)建模式,支持對所有列構(gòu)建索引,從而解決了OLAP任意查詢的性能問題。
AnalyticDB默認(rèn)對所有列構(gòu)建索引,并保存在一個單獨的文件中。與傳統(tǒng)的數(shù)據(jù)庫不同,AnalyticDB索引中的key是列的值,value是該值出現(xiàn)的所有行號集合,并支持所有的條件同時走索引查詢。多個列的操作去做union或者intersect
AnalyticDB在索引引擎是實現(xiàn)上也做了大量的優(yōu)化,包括:多路流式歸并、索引選擇CBO和索引結(jié)果緩存。
- 多路流式歸并:傳統(tǒng)數(shù)據(jù)庫大多采用2路歸并策略,在條件數(shù)特別多的場景下,會導(dǎo)致大量中間結(jié)果,計算效率很低。AanlyticDB采用K路流式歸并算法,可以支持多個集合并行歸并,避免產(chǎn)生大量中間結(jié)果集合,提升了整個歸并的速度。
- 索引選擇CBO:當(dāng)where條件中包括多個條件,并不是所有的條件走索引掃描能取得最佳的性能。利用索引中的統(tǒng)計信息,提前估算出各個條件可能的選擇率,對于選擇率很高的條件走索引查詢,其他條件直接在上層進(jìn)行過濾操作。例如對于where id = 1 and 0 < x < 1000000的情況下,id = 1這個條件的選擇率已經(jīng)很高,則0<x<1000000條件不走索引查詢效率會更高。
- 索引結(jié)果緩存:在OLAP分析場景中,多個查詢條件中,可能會出現(xiàn)部分條件固定不變或重復(fù)多次出現(xiàn)。針對這種場景AnalyticDB 實現(xiàn)了一個高效的無鎖緩存,緩存的的key為等值或range條件,value為行號集合。這樣在出現(xiàn)重復(fù)查詢情況下,可以直接讀取緩存,避免索引IO掃描開銷。
索引構(gòu)建
為了支持每秒千萬的實時數(shù)據(jù)寫入,避免同步構(gòu)建索引影響實時寫入的性能,AnalyticDB并沒有采用同步構(gòu)建索引的策略,而是采用異步后臺進(jìn)程構(gòu)建索引的方式。索引引擎會根據(jù)時間或增量數(shù)據(jù)的大小來決定是否啟動后臺進(jìn)程來構(gòu)建索引。該后臺進(jìn)程讀取Pangu上的歷史全量數(shù)據(jù)和新寫入的增量日志數(shù)據(jù),完成數(shù)據(jù)合并形成新的全量數(shù)據(jù),并對該全量數(shù)據(jù)重新構(gòu)建索引。該過程通過伏羲的MapReduce任務(wù)執(zhí)行,選擇負(fù)載較低的機器執(zhí)行,對用戶完全透明。
優(yōu)化器
創(chuàng)新性引入了兩個關(guān)鍵功能:存儲感知的優(yōu)化和高效實時采樣。因為ADB獨特的索引結(jié)構(gòu)和分布式的數(shù)據(jù)存儲
執(zhí)行引擎
在優(yōu)化器之下,AnalyticDB在MPP架構(gòu)基礎(chǔ)上,采用流水線執(zhí)行的DAG架構(gòu),構(gòu)建了一個適用于低延遲和高吞吐量工作負(fù)載的執(zhí)行器。AnalyticDB的列式執(zhí)行引擎能夠充分利用底層的行列混合存儲。與行式執(zhí)行引擎相比,當(dāng)前的向量化執(zhí)行引擎更加緩存友好,能避免將不必要的數(shù)據(jù)加載到內(nèi)存中。
與許多 OLAP 系統(tǒng)一樣,AnalyticDB在運行時利用代碼生成器(CodeGen) 來提高 CPU 密集型計算的性能。AnalyticDB的CodeGen基于 ANTLR ASM來動態(tài)生成表達(dá)式的代碼樹。同時此 CodeGen 引擎還將運行時因素納入考慮,讓AnalyticDB能在Task級別利用異構(gòu)新硬件的能力。例如,如果集群中CPU支持 AVX-512指令集,我們通過生成字節(jié)碼使用SIMD來提高性能。在此之外,通過整合內(nèi)部數(shù)據(jù)表示形式,在存儲層和執(zhí)行引擎之間,AnalyticDB是能夠直接對序列化二進(jìn)制數(shù)據(jù)進(jìn)行操作,而不是Java 對象。這有助于消除序列化和去序列化的開銷,這在大數(shù)據(jù)量shuffle時可能會節(jié)約20%以上的時間。
總結(jié)
得益于流水線處理、全列索引、行列混存、運行時索引路徑選擇、K路歸并、向量化執(zhí)行引擎、CodeGen等優(yōu)化機制,AnalyticDB獲得了最優(yōu)的TCP-H測試運行時間,并比Greenplum快了近2倍。
PolarDB/PolarFS
使用共享存儲解決MySQL主從結(jié)構(gòu)遇到的一系列問題
系統(tǒng)結(jié)構(gòu):
- libpfs是一個用戶空間文件系統(tǒng)庫,負(fù)責(zé)數(shù)據(jù)庫的I/O接入。
- PolarSwitch運行在計算節(jié)點上,用于轉(zhuǎn)發(fā)數(shù)據(jù)庫的I/O請求。每個請求包含了數(shù)據(jù)庫實例所在的Volume ID、起始偏移和長度。PolarSwitch將其劃分為對應(yīng)的一到多個Chunk,并將請求發(fā)往Chunk所屬的ChunkServer完成訪問。
- ChunkServer部署在存儲節(jié)點上,用于處理I/O請求和節(jié)點內(nèi)的存儲資源分布。ChunkServer之間通過所謂的ParallelRaft同步數(shù)據(jù)
- PolarCtrl是系統(tǒng)的控制平面,它包含了一組實現(xiàn)為微服務(wù)的管理者,相應(yīng)地Agent代理被部署到所有的計算和存儲節(jié)點上。主要職責(zé):
- 監(jiān)控ChunkServer的健康狀況,確定哪些ChunkServer有權(quán)屬于PolarFS集群;
- Volume創(chuàng)建及Chunk的布局管理(即Chunk分配到哪些ChunkServer);
- Volume至Chunk的元數(shù)據(jù)信息維護(hù);
- 向PolarSwitch推送元信息緩存更新;
- 監(jiān)控Volume和Chunk的I/O性能;
- 周期性地發(fā)起副本內(nèi)和副本間的CRC數(shù)據(jù)校驗。
存儲資源管理單元:
- Volume:是為每個數(shù)據(jù)庫提供的獨立邏輯存儲空間,其上建立了具體文件系統(tǒng)供此數(shù)據(jù)庫使用,其大小為10GB至100TB,可充分適用于典型云數(shù)據(jù)庫實例的容量要求。
- Chunk:每個Volume內(nèi)部被劃分為多個Chunk,Chunk是數(shù)據(jù)分布的最小粒度,每個Chunk只存放于存儲節(jié)點的單個NVMe SSD盤上,其目的是利于數(shù)據(jù)高可靠和高可用的管理。典型的Chunk大小為10GB,這遠(yuǎn)大于其他類似的系統(tǒng),例如GFS的64MB。雖然chunk很大,但是chunk可以通過在線遷移維持負(fù)載均衡(chunk存儲在固態(tài)盤上、還要在線遷移,這個服務(wù)不可用時間有多長???)
- Block:在ChunkServer內(nèi),Chunk會被進(jìn)一步劃分為多個Block,其典型大小為64KB。Blocks動態(tài)映射到Chunk 中來實現(xiàn)按需分配。Chunk至Block的映射信息由ChunkServer自行管理和保存,除數(shù)據(jù)Block之外,每個Chunk還包含一些額外Block用來實現(xiàn)Write Ahead Log(寫到optane)。
讀寫流程
ParallelRaft
ParallelRaft與Raft最根本的不同在于,當(dāng)某個entry提交成功時,并不意味著之前的所有entry都已成功提交。因此我們需要保證:
有了這兩點,結(jié)合數(shù)據(jù)庫或其他應(yīng)用普遍存在的對存儲I/O亂序完成的默認(rèn)容忍能力,就可以保證它們在PolarFS上的正常運轉(zhuǎn),并獲得PolarFS提供的數(shù)據(jù)可靠性。
ParallelRaft的亂序執(zhí)行遵循如下原則:
容易知道,依照此原則完成的I/O不會違反傳統(tǒng)存儲語義的正確性。
后面說了一大堆,反正就是paxos,因為同一個raft上面,可能會有多個并行的事務(wù),所以一定要亂序提交,亂序確認(rèn)
PolarFS
PolarFS設(shè)計中采用了如下技術(shù)以充分發(fā)揮I/O性能:
- PolarFS采用了綁定CPU的單線程有限狀態(tài)機的方式處理I/O,避免了多線程I/O pipeline方式的上下文切換開銷。
- PolarFS優(yōu)化了內(nèi)存的分配,采用MemoryPool減少內(nèi)存對象構(gòu)造和析構(gòu)的開銷,采用巨頁來降低分頁和TLB更新的開銷。
- PolarFS通過中心加局部自治的結(jié)構(gòu),所有元數(shù)據(jù)均緩存在系統(tǒng)各部件的內(nèi)存中,基本完全避免了額外的元數(shù)據(jù)I/O。
- PolarFS采用了全用戶空間I/O棧,包括RDMA和SPDK,避免了內(nèi)核網(wǎng)絡(luò)棧和存儲棧的開銷。
PolarFS是共享訪問的分布式文件系統(tǒng),每個文件系統(tǒng)實例都有相應(yīng)的Journal文件和與之對應(yīng)的Paxos文件。Journal文件記錄了metadata的修改歷史,是共享實例之間元數(shù)據(jù)同步的中心。Journal文件邏輯上是一個固定大小的循環(huán)buffer。PolarFS會根據(jù)水位來回收journal。Paxos文件基于Disk Paxos實現(xiàn)了分布式互斥鎖(文件鎖,文件系統(tǒng)里的悲觀鎖,性能如何?)。
由于journal對于PolarFS非常關(guān)鍵,它們的修改必需被Paxos互斥鎖保護(hù)。如果一個節(jié)點希望在journal中追加項,其必需使用DiskPaxos算法來獲取Paxos文件中的鎖。通常,鎖的使用者會在記錄持久化后馬上釋放鎖。但是一些故障情況下使用者不釋放鎖。為此在Paxos互斥鎖上分配有一個租約lease。其他競爭者可以重啟競爭過程。當(dāng)PolarFS當(dāng)節(jié)點開始同步其他節(jié)點修改的元數(shù)據(jù)時,它從上次掃描的位置掃描到j(luò)ournal末尾,將新entry更新到memory cache中。
PolarFS的上述共享機制非常適合POLARDB一寫多讀的典型應(yīng)用擴展模式。一寫多讀模式下沒有鎖爭用開銷,只讀實例可以通過原子I/O無鎖獲取Journal信息,從而使得POLARDB可以提供近線性的QPS性能擴展。
由于PolarFS支持了基本的多寫一致性保障,當(dāng)可寫實例出現(xiàn)故障時,POLARDB能夠方便地將只讀實例升級為可寫實例,而不必?fù)?dān)心底層存儲產(chǎn)生不一致問題,因而方便地提供了數(shù)據(jù)庫實例Failover的功能。(DBFS,單機高可用)
感覺這個系統(tǒng)從db到libpfs、到后端存儲chunkserver,都有WAL…所以最底層做快照,libpfs可以恢復(fù),然后上層的PolarDB也可以恢復(fù)。
對底層盤做快照而不是對上層db做快照有一個問題,就是對盤做快照的時候,當(dāng)時正在執(zhí)行的IO,其是否真正落盤了是UB的。PolarDB管這種快照叫做disk outage consistency snapshot,在具體的實現(xiàn)上,如果做快照,PolarCtrl會通知PolarSwitch,在某個時間點的IO上打Tag,chunkserver收到對應(yīng)的tag之后,說明這個tag時間的時間位點就是一個快照點。所以會先做快照,然后再處理打上tag的IO。這樣,做快照的時間就和上層對應(yīng)的某個事務(wù)的LSN聯(lián)系起來了。
事務(wù)的數(shù)據(jù)可見性問題
一、MySQL/InnoDB通過Undo日志來實現(xiàn)事務(wù)的MVCC,由于只讀節(jié)點跟讀寫節(jié)點屬于不同的mysqld進(jìn)程,讀寫節(jié)點在進(jìn)行Undo日志Purge的時候并不會考慮此時在只讀節(jié)點上是否還有事務(wù)要訪問即將被刪除的Undo Page,這就會導(dǎo)致記錄舊版本被刪除后,只讀節(jié)點上事務(wù)讀取到的數(shù)據(jù)是錯誤的。
針對該問題,PolarDB提供兩種解決方式:
- 所有ReadOnly定期向Primary匯報自己的最大能刪除的Undo數(shù)據(jù)頁,Primary節(jié)點統(tǒng)籌安排;
- 當(dāng)Primary節(jié)點刪除Undo數(shù)據(jù)頁時候,ReadOnly接收到日志后,判斷即將被刪除的Page是否還在被使用,如果在使用則等待,超過一個時間后還未有結(jié)束則直接給客戶端報錯。
二、還有個問題,由于InnoDB BP刷臟頁有多種方式,其并不是嚴(yán)格按照oldest modification來的,這就會導(dǎo)致有些事務(wù)未提交的頁已經(jīng)寫入共享存儲,只讀節(jié)點讀到該頁后需要通過Undo Page來重建可見的版本,但可能此時Undo Page還未刷盤,這就會出現(xiàn)只讀上事務(wù)讀取數(shù)據(jù)的另一種錯誤。
針對該問題,PolarDB解決方法是:
- 限制讀寫節(jié)點刷臟頁機制,如果臟頁的redo還沒有被只讀節(jié)點回放,那么該頁不能被刷回到存儲上。這就確保只讀節(jié)點讀取到的數(shù)據(jù),它之前的數(shù)據(jù)鏈?zhǔn)峭暾?#xff0c;或者說只讀節(jié)點已經(jīng)知道其之前的所有redo日志。這樣即使該數(shù)據(jù)的記錄版本當(dāng)前的事務(wù)不可見,也可以通過undo構(gòu)造出來。即使undo對應(yīng)的page是舊的,可以通過redo構(gòu)造出所需的undo page。
- replica需要緩存所有未刷盤的數(shù)據(jù)變更(即RedoLog),只有primary節(jié)點把臟頁刷入盤后,replica緩存的日志才能被釋放。這是因為,如果數(shù)據(jù)未刷盤,那么只讀讀到的數(shù)據(jù)就可能是舊的,需要通過redo來重建出來,參考第一點。另外,雖然buffer pool中可能已經(jīng)緩存了未刷盤的page的數(shù)據(jù),但該page可能會被LRU替換出去,當(dāng)其再次載入所以只讀節(jié)點必須緩存這些redo。
DDL問題
如果讀寫節(jié)點把一個表刪了,反映到存儲上就是把文件刪了。對于mysqld進(jìn)程來說,它會確保刪除期間和刪除后不再有事務(wù)訪問該表。但是在只讀節(jié)點上,可能此時還有事務(wù)在訪問,PolarFS在完成文件系統(tǒng)元數(shù)據(jù)同步后,就會導(dǎo)致只讀節(jié)點的事務(wù)訪問存儲出錯。
PolarDB目前的解決辦法是:如果主庫對一個表進(jìn)行了表結(jié)構(gòu)變更操作(需要拷表),在操作返回成功前,必須通知到所有的ReadOnly節(jié)點(有一個最大的超時時間),告訴他們,這個表已經(jīng)被刪除了,后續(xù)的請求都失敗。當(dāng)然這種強同步操作會給性能帶來極大的影響,有進(jìn)一步的優(yōu)化的空間。
Change Buffer問題
Change Buffer本質(zhì)上是為了減少二級索引帶來的IO開銷而產(chǎn)生的一種特殊緩存機制。當(dāng)對應(yīng)的二級索引頁沒有被讀入內(nèi)存時,暫時緩存起來,當(dāng)數(shù)據(jù)頁后續(xù)被讀進(jìn)內(nèi)存時,再進(jìn)行應(yīng)用,這個特性也帶來的一些問題,該問題僅存在于StandBy中。例如Primary節(jié)點可能因為數(shù)據(jù)頁還未讀入內(nèi)存,相應(yīng)的操作還緩存在Change Buffer中,但是StandBy節(jié)點則因為不同的查詢請求導(dǎo)致這個數(shù)據(jù)頁已經(jīng)讀入內(nèi)存,可以直接將二級索引修改合并到數(shù)據(jù)頁上,無需經(jīng)過Change Buffer了。但由于復(fù)制的是Primary節(jié)點的redo,且需要保證StandBy和Primary在存儲層的一致性,所以StandBy節(jié)點還是會有Change Buffer的數(shù)據(jù)頁和其對應(yīng)的redo日志,如果該臟頁回刷到存儲上,就會導(dǎo)致數(shù)據(jù)不一致。
為了解決這個問題,PolarDB引入shadow page的概念,把未修改的數(shù)據(jù)頁保存到其中,將Change Buffer記錄合并到原來的數(shù)據(jù)頁上,同時關(guān)閉該Mtr的redo,這樣修改后的Page就不會放到Flush List上。也就是StandBy實例的存儲層數(shù)據(jù)跟Primary節(jié)點保持一致。
Polar-X
ClickHouse
ClickHouse擁有多種表引擎類型,在這眾多的表引擎中,MergeTree是比較有代表性的引擎之一,被廣泛使用。
MergeTree采用列式存儲,類似LSM Tree的架構(gòu)組織數(shù)據(jù)。數(shù)據(jù)導(dǎo)入時被劃分為多個Part,每個Part對應(yīng)一個目錄。Part中包含各個列的數(shù)據(jù),每個列都有獨立的文件。后臺會調(diào)度合并任務(wù),將多個小的Part合并成更大的Part,類似LSM Tree的合并過程。 Part中包含幾類文件:
- 數(shù)據(jù)文件(.bin),每一列的數(shù)據(jù)都分別存儲在數(shù)據(jù)文件,一般以主鍵排序。數(shù)據(jù)文件中劃分為若干個Block,Block是列存文件的壓縮單元。每個Block又會包含若干個索引Granularity,用于索引定位。
- 索引文件(.idx),索引文件又分為主鍵索引和二級索引:
- MergeTree的主鍵索引與傳統(tǒng)數(shù)據(jù)庫的主鍵索引有所不同,MergeTree的主鍵索引只負(fù)責(zé)排序,但是不會去重。主鍵索引文件中,存儲的是每一個Granularity中起始行的主鍵值,可以在掃描過程中過濾部分Granularity。
- MergeTree的二級索引文件中可以存儲Granularity的minmax、set、bloom_filter、ngrambf_v1等信息。
- Mark文件(.mrk),由于索引文件是對Granularity進(jìn)行索引,類似于邏輯索引。Mark文件記錄Granularity在數(shù)據(jù)文件中的物理偏移,類似于將邏輯索引轉(zhuǎn)換成物理索引。
MergeTree對于批量導(dǎo)入支持較好,對OLTP級事務(wù)更新僅有限支持。MergeTree存儲引擎對數(shù)據(jù)實時可見要求非常高的場景是不太友好的。
| 存儲結(jié)構(gòu) | Delta Tree,磁盤行列混存 | 增量 + 基線,磁盤行列混存 | MergeTree,磁盤列存 | Hekaton列存索引,內(nèi)存行列混存 |
| 索引結(jié)構(gòu) | 主鍵索引 | 全列倒排索引 | 主鍵索引 + 二級索引 | 本身是行存的索引,可以利用行存的其他索引 |
| 數(shù)據(jù)更新方式 | MVCC事務(wù)隔離,支持TP型事務(wù)和批量導(dǎo)入 | MVCC事務(wù)隔離,支持TP型事務(wù) | 批量導(dǎo)入友好,有限支持更新 | 與行存保持一致 |
| 數(shù)據(jù)壓縮 | 通用壓縮 | 字典壓縮 | 通用壓縮 | RLE等專用壓縮 |
- ClickHouse深度揭秘
- 獨家深度 | 一文看懂 ClickHouse vs Elasticsearch:誰更勝一籌?
- 干貨連載 | ClickHouse內(nèi)核分析-MergeTree的存儲結(jié)構(gòu)和查詢加速
- 談?wù)凜lickHouse性能情況以及相關(guān)優(yōu)化
- 如何看待yandex開源clickhouse這個列式文檔數(shù)據(jù)庫?
clickhouse極致的列存、查詢優(yōu)化,但是并發(fā)查詢性能不佳,不支持事務(wù)等等,相比其他競品(hadoop、impala。。。)做到了極致的查詢性能
設(shè)計目標(biāo)
- OLAP數(shù)據(jù)庫,適用于大寬表,查詢會掃描到大量行但是只用到了少數(shù)幾列。使用列式存儲,
- 優(yōu)化查詢的吞吐(查詢速度),要求海量數(shù)據(jù)能盡快處理完成。
- 無需事務(wù),數(shù)據(jù)一致性要求低(可以搭配一款事務(wù)型數(shù)據(jù)庫,CH實時從事務(wù)庫中同步數(shù)據(jù))
ClickHouse存儲引擎
- 純列式存儲,然后壓縮(有著十倍甚至更高的壓縮比,節(jié)省存儲空間,降低存儲成本),
- ClickHouse支持在建表時,指定將數(shù)據(jù)按照某些列進(jìn)行sort by。排序后,保證了相同sort key的數(shù)據(jù)在磁盤上連續(xù)存儲,且有序擺放。在進(jìn)行等值、范圍查詢時,where條件命中的數(shù)據(jù)都緊密存儲在一個或若干個連續(xù)的Block中,而不是分散的存儲在任意多個Block, 大幅減少需要IO的block數(shù)量。另外,連續(xù)IO也能夠充分利用操作系統(tǒng)page cache的預(yù)取能力,減少page fault。
- ClickHouse支持主鍵索引,它將每列數(shù)據(jù)按照index granularity(默認(rèn)8192行)進(jìn)行劃分,每個index granularity的開頭第一行被稱為一個mark行。主鍵索引存儲該mark行對應(yīng)的primary key的值。對于where條件中含有primary key的查詢,通過對主鍵索引進(jìn)行二分查找,能夠直接定位到對應(yīng)的index granularity,避免了全表掃描從而加速查詢。但是值得注意的是:ClickHouse的主鍵索引與MySQL等數(shù)據(jù)庫不同,它并不用于去重,即便primary key相同的行,也可以同時存在于數(shù)據(jù)庫中。要想實現(xiàn)去重效果,需要結(jié)合具體的表引擎ReplacingMergeTree、CollapsingMergeTree、VersionedCollapsingMergeTree實現(xiàn)。
- 稀疏索引,ClickHouse支持對任意列創(chuàng)建任意數(shù)量的稀疏索引。其中被索引的value可以是任意的合法SQL Expression,并不僅僅局限于對column value本身進(jìn)行索引。之所以叫稀疏索引,是因為它本質(zhì)上是對一個完整index granularity(默認(rèn)8192行)的統(tǒng)計信息,并不會具體記錄每一行在文件中的位置。目前支持的稀疏索引類型包括:
- minmax: 以index granularity為單位,存儲指定表達(dá)式計算后的min、max值;在等值和范圍查詢中能夠幫助快速跳過不滿足要求的塊,減少IO。
- set(max_rows):以index granularity為單位,存儲指定表達(dá)式的distinct value集合,用于快速判斷等值查詢是否命中該塊,減少IO。
- ngrambf_v1(n, size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed):將string進(jìn)行ngram分詞后,構(gòu)建bloom filter,能夠優(yōu)化等值、like、in等查詢條件。
- tokenbf_v1(size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed): 與ngrambf_v1類似,區(qū)別是不使用ngram進(jìn)行分詞,而是通過標(biāo)點符號進(jìn)行詞語分割。
- bloom_filter([false_positive]):對指定列構(gòu)建bloom filter,用于加速等值、like、in等查詢條件的執(zhí)行。
- ClickHouse支持單機模式,也支持分布式集群模式。在分布式模式下,ClickHouse會將數(shù)據(jù)分為多個分片,并且分布到不同節(jié)點上。不同的分片策略在應(yīng)對不同的SQL Pattern時,各有優(yōu)勢。
- 1)random隨機分片:寫入數(shù)據(jù)會被隨機分發(fā)到分布式集群中的某個節(jié)點上。
- 2)constant固定分片:寫入數(shù)據(jù)會被分發(fā)到固定一個節(jié)點上。
- 3)column value分片:按照某一列的值進(jìn)行hash分片。
- 4)自定義表達(dá)式分片:指定任意合法表達(dá)式,根據(jù)表達(dá)式被計算后的值進(jìn)行hash分片。
- 用戶根據(jù)自身業(yè)務(wù)特點選擇合適的數(shù)據(jù)分片策略,可以有優(yōu)化數(shù)據(jù)傾斜、避免shuffle直接本地oin等優(yōu)點
- ClickHouse采用類LSM Tree的結(jié)構(gòu),數(shù)據(jù)寫入后定期在后臺Compaction。通過類LSM tree的結(jié)構(gòu),ClickHouse在數(shù)據(jù)導(dǎo)入時全部是順序append寫,寫入后數(shù)據(jù)段不可更改,在后臺compaction時也是多個段merge sort后順序?qū)懟卮疟P。順序?qū)懙奶匦?#xff0c;充分利用了磁盤的吞吐能力,即便在HDD上也有著優(yōu)異的寫入性能。
- 在分析場景中,刪除、更新操作并不是核心需求。ClickHouse沒有直接支持delete、update操作,而是變相支持了mutation操作,語法為alter table delete where filter_expr,alter table update col=val where filter_expr。目前主要限制為刪除、更新操作為異步操作,需要后臺compation之后才能生效。
- ClickHouse支持PARTITION BY子句,在建表時可以指定按照任意合法表達(dá)式進(jìn)行數(shù)據(jù)分區(qū)操作,比如通過toYYYYMM()將數(shù)據(jù)按月進(jìn)行分區(qū)、toMonday()將數(shù)據(jù)按照周幾進(jìn)行分區(qū)、對Enum類型的列直接每種取值作為一個分區(qū)等。
總結(jié)來說,極致壓縮,稀疏索引、數(shù)據(jù)分片
計算引擎
ClickHouse在計算層做了非常細(xì)致的工作,竭盡所能榨干硬件能力,提升查詢速度。它實現(xiàn)了單機多核并行、分布式計算、向量化執(zhí)行與SIMD指令、代碼生成等多種重要技術(shù)。
ClickHouse總結(jié)
近年來ClickHouse發(fā)展趨勢迅猛,社區(qū)和大廠都紛紛跟進(jìn)使用。本文嘗試從OLAP場景的需求出發(fā),介紹了ClickHouse存儲層、計算層的主要設(shè)計。ClickHouse實現(xiàn)了大多數(shù)當(dāng)前主流的數(shù)據(jù)分析技術(shù),具有明顯的技術(shù)優(yōu)勢:
- 提供了極致的查詢性能:開源公開benchmark顯示比傳統(tǒng)方法快1001000倍,提供50MB200MB/s的高吞吐實時導(dǎo)入能力)
- 以極低的成本存儲海量數(shù)據(jù): 借助于精心設(shè)計的列存、高效的數(shù)據(jù)壓縮算法,提供高達(dá)10倍的壓縮比,大幅提升單機數(shù)據(jù)存儲和計算能力,大幅降低使用成本,是構(gòu)建海量數(shù)據(jù)倉庫的絕佳方案。
- 簡單靈活又不失強大:提供完善SQL支持,上手十分簡單;提供json、map、array等靈活數(shù)據(jù)類型適配業(yè)務(wù)快速變化;同時支持近似計算、概率數(shù)據(jù)結(jié)構(gòu)等應(yīng)對海量數(shù)據(jù)處理。
相比于開源社區(qū)的其他幾項分析型技術(shù),如Druid、Presto、Impala、Kylin、ElasticSearch等,ClickHouse更是一整套完善的解決方案,它自包含了存儲和計算能力(無需額外依賴其他存儲組件),完全自主實現(xiàn)了高可用,而且支持完整的SQL語法包括JOIN等,技術(shù)上有著明顯優(yōu)勢。相比于hadoop體系,以數(shù)據(jù)庫的方式來做大數(shù)據(jù)處理更加簡單易用,學(xué)習(xí)成本低且靈活度高。當(dāng)前社區(qū)仍舊在迅猛發(fā)展中,相信后續(xù)會有越來越多好用的功能出現(xiàn)。
TiDB
shared-nothing,raft,很多mysql實現(xiàn)的功能還沒實現(xiàn)。底層KV存儲,TiBD主要負(fù)責(zé)和client對接,然后做優(yōu)化,很多執(zhí)行計劃會下推到TiKV
我在想TiDB還是有很多問題的,首先TiDB的底座不是云原生的基礎(chǔ)組件(類比snowflake polarDB ADB),很多問題上云之后就沒法解決了
TiDB目前有兩種存儲節(jié)點,分別是 TiKV 和 TiFlash。TiKV 采用了行式存儲,更適合 TP 類型的業(yè)務(wù);而 TiFlash 采用列式存儲,擅長 AP 類型的業(yè)務(wù)。TiFlash 通過 raft 協(xié)議從 TiKV 節(jié)點實時同步數(shù)據(jù),擁有毫秒級別的延遲,以及非常優(yōu)秀的數(shù)據(jù)分析性能。它支持實時同步 TiKV 的數(shù)據(jù)更新,以及支持在線 DDL。我們把 TiFlash 作為 Raft Learner 融合進(jìn) TiDB 的 raft 體系,將兩種節(jié)點整合在一個數(shù)據(jù)庫集群中,上層統(tǒng)一通過 TiDB 節(jié)點查詢,使得 TiDB 成為一款真正的 HTAP 數(shù)據(jù)庫。
TiFlash
TiFlash的列式存儲引擎Delta Tree參考了B+ Tree和LSM Tree的設(shè)計思想。
- Delta Tree將數(shù)據(jù)按照主鍵劃分為Range分區(qū),每個分區(qū)稱為Segment。
- Segment通過B+ Tree作為索引。也就是說,B+ Tree索引的葉子節(jié)點為Segment。
- 在Segment內(nèi)部采用類似LSM Tree的分層存儲方式,不過采用固定兩層的LSM Tree,分別為Delta層和Stable層。
- Delta層保存增量數(shù)據(jù)部分,其中,新寫入的數(shù)據(jù)寫入Delta Cache中,與LSM Tree的MemTable類似。當(dāng)Delta Cache寫滿后,其中的數(shù)據(jù)刷入Delta層的Pack中,類似LSM Tree的L0層。
- Stable層類似于LSM Tree的L1層,其中的數(shù)據(jù)以主鍵和版本號排序。
- Delta層的Pack和Stable層需要做全量合并,得到新的Stable層數(shù)據(jù)。
- 當(dāng)Segment中的數(shù)據(jù)量超過閾值,就會做類似B+ Tree葉子節(jié)點的分裂操作,分裂成兩個Segment。同時,如果相鄰的Segment中的數(shù)據(jù)量都比較小,也會將相鄰的Segment合并成一個Segment。
C-Store(2005)/Vertica
大多數(shù)DBMS都是為寫優(yōu)化,C-store是第一個為讀優(yōu)化的OLTP數(shù)據(jù)庫。C-Store 的主要貢獻(xiàn)有以下幾點:通過精心設(shè)計的 projection 同時實現(xiàn)列數(shù)據(jù)的多副本和多種索引方式;用讀寫分層的方式兼顧了(少量)寫入的性能。此外,C-Store 可能是第一個現(xiàn)代的列式存儲數(shù)據(jù)庫實現(xiàn),其的設(shè)計啟發(fā)了無數(shù)后來的商業(yè)或開源數(shù)據(jù)庫,就比如 Vertica。
在 C-Store 內(nèi)部,邏輯表被縱向拆分成 projections,每個 projection 可以包含一個或多個列,甚至可以包含來自其他邏輯表的列(構(gòu)成索引)。當(dāng)然,每個列至少會存在于一個 projections 上。
Projection 內(nèi)是以列式存儲的:里面的每個列分別用一個數(shù)據(jù)結(jié)構(gòu)存放。為了避免列太長引起問題,也支持每個 projection 以 sort key 的值做橫向切分。
Projection 是有冗余性的,常常 1 個列會出現(xiàn)在多個 projection 中,但是它們的順序也就是 sort key 并不相同,因此 C-Store 在查詢時可以選用最優(yōu)的一組 projections,使得查詢執(zhí)行的代價最小。
Apache ORC
Apache ORC 最初是為支持 Hive 上的 OLAP 查詢開發(fā)的一種文件格式,如今在 Hadoop 生態(tài)系統(tǒng)中有廣泛的應(yīng)用。ORC 支持各種格式的字段,包括常見的 int、string 等,也包括 struct、list、map 等組合字段;字段的 meta 信息就放在 ORC 文件的尾部(這被稱為自描述的)。
ORC 里的 Stripe 就像傳統(tǒng)數(shù)據(jù)庫的頁,它是 ORC 文件批量讀寫的基本單位。這是由于分布式儲存系統(tǒng)的讀寫延遲較大,一次 IO 操作只有批量讀取一定量的數(shù)據(jù)才劃算。這和按頁讀寫磁盤的思路也有共通之處。
Apache ORC 提供有限的 ACID 事務(wù)支持。受限于分布式文件系統(tǒng)的特點,文件不能隨機寫,那如何把修改保存下來呢?
類似于 LSM-Tree 中的 MVCC 那樣,writer 并不是直接修改數(shù)據(jù),而是為每個事務(wù)生成一個 delta 文件,文件中的修改被疊加在原始數(shù)據(jù)之上。當(dāng) delta 文件越來越多時,通過 minor compaction 把連續(xù)多個 delta 文件合成一個;當(dāng) delta 變得很大時,再執(zhí)行 major compaction 將 delta 和原始數(shù)據(jù)合并。這種保持基線數(shù)據(jù)不變、分層疊加 delta 數(shù)據(jù)的優(yōu)化方式在列式存儲系統(tǒng)中十分常見,是一種通用的解決思路。
Dremel (2010) / Apache Parquet
Dremel 是 Google 研發(fā)的用于大規(guī)模只讀數(shù)據(jù)的查詢系統(tǒng),用于進(jìn)行快速的 ad-hoc 查詢,彌補 MapReduce 交互式查詢能力的不足。為了避免對數(shù)據(jù)的二次拷貝,Dremel 的數(shù)據(jù)就放在原處,通常是 GFS 這樣的分布式文件系統(tǒng),為此需要設(shè)計一種通用的文件格式。
Dremel 的系統(tǒng)設(shè)計和大多 OLAP 的列式數(shù)據(jù)庫并無太多創(chuàng)新點,但是其精巧的存儲格式卻變得流行起來,Apache Parquet 就是它的開源復(fù)刻版。注意 Parquet 和 ORC 一樣都是一種存儲格式,而非完整的系統(tǒng)。
Impala
Impala是Cloudera公司主導(dǎo)開發(fā)的新型查詢系統(tǒng),它提供SQL語義,能查詢存儲在Hadoop的HDFS和HBase中的PB級大數(shù)據(jù)。已有的Hive系統(tǒng)雖然也提供了SQL語義,但由于Hive底層執(zhí)行使用的是MapReduce引擎,仍然是一個批處理過程,難以滿足查詢的交互性。相比之下,Impala的最大特點也是最大賣點就是它的快速。Impala完全拋棄了MapReduce這個不太適合做SQL查詢的范式,而是像Dremel一樣借鑒了MPP并行數(shù)據(jù)庫的思想另起爐灶,因此可做更多的查詢優(yōu)化,從而省掉不必要的shuffle、sort等開銷。
Impala與Hive類似不是數(shù)據(jù)庫而是數(shù)據(jù)分析工具,集群有以下幾類節(jié)點
查詢流程
- Client發(fā)送?個SQL查詢請求到任意?個Impalad節(jié)點,會返回?個queryId?于之后的客戶端操作。
- SQL提交到Impalad節(jié)點之后,Analyser依次執(zhí)?SQL的詞法分析、語法分析、語義分析等操作;從MySQL元數(shù)據(jù)庫中獲取元數(shù)據(jù),從HDFS的名稱節(jié)點中獲取數(shù)據(jù)地址,以得到存儲這個查詢相關(guān)數(shù)據(jù)的所有數(shù)據(jù)節(jié)點。
- 單機執(zhí)行計劃:根據(jù)上?步對SQL語句的分析,由Planner先?成單機的執(zhí)?計劃,該執(zhí)?計劃是有PlanNode組成的?棵樹,這個過程中也會執(zhí)??些SQL化,例如Join順序改變、謂詞下推等。
- 分布式并?物理計劃:將單機執(zhí)?計劃轉(zhuǎn)換成分布式并?物理執(zhí)?計劃,物理執(zhí)?計劃由?個個的Fragment組成,Fragment之間有數(shù)據(jù)依賴關(guān)系,處理過程中要在原有的執(zhí)?計劃之上加??些ExchangeNode和DataStreamSink信息等。
- Fragment : sql?成的分布式執(zhí)?計劃的?個?任務(wù);
- DataStreamSink:傳輸當(dāng)前的Fragment輸出數(shù)據(jù)到不同的節(jié)點;
- Coordinator將Fragment(?任務(wù))根據(jù)數(shù)據(jù)分區(qū)信息發(fā)配到不同的Impalad節(jié)點上執(zhí)?。Impalad節(jié)點接收到執(zhí)?Fragment請求交由Executor執(zhí)?。
- 每?個Fragment的執(zhí)?輸出通過DataStreamSink發(fā)送到下?個Fragment,Fragment運?過程中不斷向coordinator節(jié)點匯報當(dāng)前運?狀態(tài)。
- 查詢的SQL通常情況下需要有?個單獨的Fragment?于結(jié)果的匯總,它只在Coordinator節(jié)點運?,將多個節(jié)點的最終執(zhí)?結(jié)果匯總,轉(zhuǎn)換成ResultSet信息。
- 客戶端調(diào)?獲取ResultSet的接?,讀取查詢結(jié)果。
Druid
Druid可以對多列數(shù)據(jù)構(gòu)建倒排索引(bitmap-based inverted indexes)
Pinot
mongoDB
- MongoDB是如何實現(xiàn)事務(wù)的ACID?
參考鏈接
總結(jié)
以上是生活随笔為你收集整理的分布式数据库产品总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Persistent Memory编程简
- 下一篇: 响应式关系数据库处理R2DBC