Databend 存儲架構總覽

来源:https://www.cnblogs.com/databend/archive/2022/10/21/16814420.html
-Advertisement-
Play Games

目的 通過本篇文章帶大家理解一下 Databend 的存儲結構。Databend 內置的 Table 引擎為 Fuse table engine,也是接下來要花重點篇幅要講的。 另外,Databend 還支持外置的 Hive table 及 Icebreg Table ( 即將到來)。Fuse ta ...


目的

通過本篇文章帶大家理解一下 Databend 的存儲結構。Databend 內置的 Table 引擎為 Fuse table engine,也是接下來要花重點篇幅要講的。

另外,Databend 還支持外置的 Hive table 及 Icebreg Table ( 即將到來)。Fuse table 是 Databend 直接把數據存儲到 S3 類對象存儲上,從而讓用戶達到一個按需付費,無須關註存儲的高可用及擴容,副本這些問題。

Hive Table 是利用 Databend 替換 Hive 的查詢能力,從而減少 Hive 計算節點,起到降本增效的效果(該功能已經使用)。

Iceberg Table 正在規劃中 https://github.com/datafuselabs/databend/issues/8216

Fuse Table Engine 基礎概念

在 Fuse Table 中有一些基礎概念先做一個解釋方便更想 Databend Fuse Table 的存儲結構。

1. 什麼是 db_id?

這是 Databend 中的一個 internal 的標識 (u64),不是暴露給用戶使用,Databend 對於 create database 會在對應的 bucket/[root] 下麵創建一個整數命名的目錄。

2. 什麼是 table_id?

這是 Databend 中的一個 internal 的標識 (u64),不是暴露給用戶使用,Databend 對於 create table 會在 /bucket/[root]/<db_id>/ 創建一個整數命名的目錄。

3. Databend 的存 block 文件是什麼?

Databend 最終存儲 block 是以 Parquet 為格式存儲,在存儲上以表為單位,文件名為:[UUID].parquet, 存儲路徑為:

/bucket/[root]/<db_id>/<table_id>/_b/<32 位 16 進位字元串 >_v0.parquet

如:d5ee665801a64a079a8fd2711a71c780_v0.parquet

4. Databend 中 segment 文件是什麼?

Databend 中用於組織 Block 的文件。一個 segment 可以多含的 Block 塊,文件是 json 格式: /bucket/[root]/<db_id>/<table_id>/_sg/<32 位 16 進位字元串 >_v1.json 。

如:3b5e1325f68e47b0bd1517ffeb888a36_v1.json

5. Snapshot 是什麼?

snapshot 相當於每一個數據的一個版本號(uuid, 32 位 16 進位字元串)。每個寫入動作都會有一個唯一的版本號, json 格式,內部包含對應的 segment 文件, /bucket/[root]/<db_id>/<table_id>/_ss/<32 位 16 進位字元串 >_v1.json。

如:e7ccbdcff8d54ebe9aee85d9fbb3dbcb_v1.json

6. Databend 支持什麼索引?

Databend 目前支持三類索引:min/max index, sparse index, bloom filter index 。其中 min/max, sparse index 在 Block 的 parquet 及對應的:ss, segment 中都有存儲,bloom fliter 是單獨存儲為 parquet 文件。

Databend 存儲結構 Databend 整體上的存儲結構大概如下:

/bucket/[root]/snapshot 下麵有 N 多的 segment , 一個 segment 里包含至少一個 block, 最多 1000 個 block 。

存儲配置Databend

存儲配置

[storage]
# fs | s3 | azblob | obs
type = "s3"


# To use S3-compatible object storage, uncomment this block and set your values.
[storage.s3]
bucket = "testbucket"
root = "20221012"
endpoint_url = "url"
access_key_id = "=user"
secret_access_key = "mypassword"

上面這段配置的作用:以 s3 方式把文件存到 testbucket 下麵的 20221012 目錄, 最終會形成如下的結構:

其中配置中 root 可以省略。

例如:/testbucket/20221012/17818/17825 對應的是 /bucket/root/db_id/table_id 這樣一個結構。

table_id 裡面每個目錄的意義

目錄 意義
_b 用於存儲數據的真正block, 以parquet 格式存儲
_i_b_v2 數據本身的 bloom fliter 索引,以 parquet 格式存儲
_sg 全稱:segment 用於管理 block 組成,json 文件格式, 一個 sg 文件最少包含一個 block ,最多包含 1000 個 block
_ss 全稱:snapshot, 用於關聯一個版本對應的 segment
last_snapshot_location_hint 指向最後一個 snapshot 存儲的位置

驗證環境

驗證1  ss/sg/_b/_i_b_v2 關係

為了分析他們的關係,這裡通過一個 create database/ create table / insert 例子來看看他們是怎麼生成的。

create database wubx;
use wubx;
create table tb1(id int, c1 varchar);
insert into tb1 values(1, 'databend');
show create table tb1;

最後通過 show create table 可以看到:

CREATE TABLE `tb1` (
  `id` INT,
  `c1` VARCHAR
) ENGINE=FUSE SNAPSHOT_LOCATION='17818/17825/_ss/e7ccbdcff8d54ebe9aee85d9fbb3dbcb_v1.json'

這裡可以看到:

  • wubx 的 db_id 是:17818
  • tb1 的 table_id 是:17825
  • 對應的第一個 snapshot 文件是:17818/17825/_ss/e7ccbdcff8d54ebe9aee85d9fbb3dbcb_v1.json

1.查詢對應的 snapshot

MySQL [wubx]> select snapshot_id, snapshot_location from fuse_snapshot('wubx','tb1')\G;
*************************** 1. row ***************************
      snapshot_id: e7ccbdcff8d54ebe9aee85d9fbb3dbcb
snapshot_location: 17818/17825/_ss/e7ccbdcff8d54ebe9aee85d9fbb3dbcb_v1.json
1 row in set (0.005 sec)

2.接下來我們看一下,這個 snapshot 中包含那些 segment:

MySQL [wubx]> select * from fuse_segment('wubx','tb1', 'e7ccbdcff8d54ebe9aee85d9fbb3dbcb')\G;
*************************** 1. row ***************************
     file_location: 17818/17825/_sg/3b5e1325f68e47b0bd1517ffeb888a36_v1.json
    format_version: 1
       block_count: 1
         row_count: 1
bytes_uncompressed: 28
  bytes_compressed: 296
1 row in set (0.006 sec)

從這個查詢中可以看到 snapshot: e7ccbdcff8d54ebe9aee85d9fbb3dbcb 只包含一個 segment: 17818/17825/_sg/3b5e1325f68e47b0bd1517ffeb888a36_v1.json, 而這個 segment 只有一個 1 block,這個 Block 只有 1 行數據。對應的 JSON 文件:

{
    "format_version": 1,
    "blocks": [
        {
            ...
            "location": [
                "17818/17825/_b/d5ee665801a64a079a8fd2711a71c780_v0.parquet",
                0
            ],
            "bloom_filter_index_location": [
                "17818/17825/_i_b_v2/d5ee665801a64a079a8fd2711a71c780_v2.parquet",
                2
            ],
            "bloom_filter_index_size": 470,
            "compression": "Lz4Raw"
        }
    ],
    "summary": {
            ...
        }
}

原始文件較長,有興趣的可以詳細閱讀一個原文件。

3.對應的 block 查詢

MySQL [wubx]> select * from fuse_block('wubx','tb1')\G;
*************************** 1. row ***************************
          snapshot_id: e7ccbdcff8d54ebe9aee85d9fbb3dbcb
            timestamp: 2022-10-14 06:53:55.147359
       block_location: 17818/17825/_b/d5ee665801a64a079a8fd2711a71c780_v0.parquet
           block_size: 28
bloom_filter_location: 17818/17825/_i_b_v2/d5ee665801a64a079a8fd2711a71c780_v2.parquet
    bloom_filter_size: 470
1 row in set (0.006 sec)

驗證1 總結:

  1. 任何一次寫入都會生成對應的 snapshot (用於 time travel)
  1. 生成的 block 會被 Segment 引用,一個寫入產生的 block 數量在小於 1000 個的情況下都會屬於一個 segment 中,如果超過 1000 個 block 會生成多個 segement (這個操作太大了,就不證明瞭)
  1. 如果上面情況,一次 insert 也會生成:一個 snapshot , 一個 segment ,一個 block,一個 bloom fliter block

基於上面的原理:

對於 Databend 寫入推薦使用批量寫入,不推薦單條的 insert 做生成中的數據生成。在 Databend 海量數據寫入推薦使用 copy into, streaming_load , clickhouse http handler 這三種方法, 其中前兩種吞吐能力最好。

驗證1  ss/sg/_b/_i_b_v2 關係

多次重覆制執行:Insert into tb1 select * from tb1; 共執行 10 次,加上原來 1 次,總共會形成 11 個 snapshot:

接下來看 tb1 的 snapshot 指向:17818/17825/_ss/5a0ba62a222441d3acd2d93549e46d82_v1.json

show create table tb1;
CREATE TABLE `tb1` (
  `id` INT,
  `c1` VARCHAR
) ENGINE=FUSE SNAPSHOT_LOCATION='17818/17825/_ss/5a0ba62a222441d3acd2d93549e46d82_v1.json'

Q1:snapshot 主要用來做什麼?

Databend 基於 snapshot 獲取相應版本的數據,Databend 也是基於 snapshot 實現事務的 RR 隔離級別。

例如:Select count() from tb1;相當於:select count() from tb1 at(snapshot=>'5a0ba62a222441d3acd2d93549e46d82');

這個 at 語句是 time travel 的一個特性,對於 time travel 可以參考:https://databend.rs/doc/reference/sql/query-syntax/dml-at#obtaining-snapshot-id-and-timestamp

Q2:snapshot 是否可以被清理?

可以的。

清理 snapshot 命令:optimize table tb1; 或是 optimize table tb1 purge;

MySQL [wubx]> optimize table tb1;
Query OK, 0 rows affected (0.013 sec)

MySQL [wubx]> select snapshot_id, snapshot_location from fuse_snapshot('wubx','tb1');
+----------------------------------+----------------------------------------------------------+
| snapshot_id                      | snapshot_location                                        |
+----------------------------------+----------------------------------------------------------+
| 5a0ba62a222441d3acd2d93549e46d82 | 17818/17825/_ss/5a0ba62a222441d3acd2d93549e46d82_v1.json |
+----------------------------------+----------------------------------------------------------+
1 row in set (0.005 sec)

但清理後,time travel 功能需要針對後面的數據才能生效,前面的 time travel 數據已經丟掉。

Q3:是否可以創建一個不帶 time travel 的表?

可以的。

Databend 支持:CREATE TRANSIENT TABLE .. 創建的表

參考:https://databend.rs/doc/reference/sql/ddl/table/ddl-create-table#create-transient-table-

該方式創建的表存在一個缺點:在高併發寫入讀取中,容易造成正在讀取的 snapshot 被回收及報錯的問題。

存儲優化Tips

Q1:大量小的 block 文件,是不是可以進行合併?

可以合併的。

目前需要用戶進行手工觸發。

optimize table tbname compact; 

這個命令的作用:

  • 把原有的  block 塊 max_threads 進行併發合併,生成一份最佳的 Block size 文件列表
  • 每個 thread 任務對應一個 segment 文件,超過 1000 個 block 會生成多個 segment
  • 最終生成一個 snapshot 文件

經過 Compact 的最佳的 Block 塊,後續在運行 compact 動作會直接跳過。

Q2: 什麼時間決定需要運行 tb 的 compact?

目前 Databend 對於 Block 判定要執行 compact 的條件:

  • 單個 block 塊里行數少於 80 萬行且 block 小於 100M 會進行合併
  • 單個 block 塊超過 100 萬行,block 會被拆分。

可以用一個簡單的條件來判斷

a. Block 數量大於 max_threads* 4 倍

select count(*) from fuse_block('db','tb');

b.表裡 block 數據少於 100M 且行數低於 80 萬的數量超過 100 個

select if(count(*)>100,'你需要運行compact','你的block大小非常合理') from fuse_block('db','tb') where file_size <100*1024*1024 and row_count<800000;

Q3:  當出現大量的 segment 文件,是不是需要對 segment 文件合併?

是的。

對於 segment 合併也可以引入一條簡單的規則

select count(*),avg(block_count),if(avg(block_count)<500,'need compact segment','segment file is ok') from fuse_segment('db','tb','snapshot_id');

如果 segment 總數超過 1000 ,而且每個 segment 平均 block 數小於 500 需要運行:

 optimize table tb compact segment; 

對於頻繁寫入的場景建議定期運行一下 compact segment ,這樣來壓縮一下 ss 及對 segemnt 文件的大小, 方便 meta 信息進行緩存。

Q4:進行合併操作後文件占用空間比較大,如何釋放?

Databend 是一個多版本及支持 Time travel 特性的雲數倉,隨著歷史增長,會出現挺多的版本數據,對於存在的歷史版本數據可以使用

 optimize table table_name purge;

現在 purge 動作會把當前的 snapshot  之外的版本全部清理掉,造成 time travel 失效的問題。後續 purge 會支持傳入 snapshot 或是時間指定清理到什麼位置。

Q5:如何進行 compact 和同時清理過舊的數據?

 optimize table table_name all;

這個命令相當於:optimize table table_name compact; optimize table table_name purge;

Q6:如何真正刪除一張表?

Databend 中 Drop table 為了支持 undrop table 不會所表直正刪除,如果你需要立即 Drop 一張表建議使用:

drop table table_name all;

目前需要刪除一個 Database 也面臨這樣的問題,需要先做表的刪除,再刪 Database 。

關於 Databend

Databend 是一款開源、彈性、低成本,基於對象存儲也可以做實時分析的新式數倉。期待您的關註,一起探索雲原生數倉解決方案,打造新一代開源 Data Cloud。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 許可權類 主要用途:用戶登錄了,某個介面可能只有超級管理員才能訪問,普通用戶不能訪問 案列:出版社的所有介面,必須登錄,而且是超級管理員才能訪問 分析步驟 第一步:寫一個類,繼承BasePermission 第二步:重寫has_permission方法 第三步:在方法校驗用戶時候有許可權(request ...
  • 開始分析 【1】分析入口類做了什麼 //org.apache.zookeeper.server.quorum包下QuorumPeerMain類 public static void main(String[] args) { QuorumPeerMain main = new QuorumPeerM ...
  • http HTTp 什麼是HTTP 超文本傳輸協議 (HTTP) 是萬維網的基礎,用於使用超文本鏈接載入網頁。HTTP 是一種應用層協議,旨在在聯網設備之間傳輸信息,併在網路協議棧的其他層之上運行。HTTP 上的典型流程涉及客戶端機器向伺服器發出請求,然後伺服器發送響應消息。 當您http://在域 ...
  • 1、如何在Asp.Net Core中激活Session功能 首先添加Session包,其次在ConfigService方法中添加Session,然後在ConfigService中調用useSession。 2、什麼是中間件 指註入到應用中處理請求和響應的組件,是通過多個嵌套形成的 3、Applica ...
  • 01、進程和線程的區別 1、進程 進程是資源分配的基本單位。 進程式控制制塊 (Process Control Block, PCB) 描述進程的基本信息和運行狀態,所謂的創建進程和撤銷進程,都是指對 PCB 的操作。 下圖顯示了 4 個程式創建了 4 個進程,這 4 個進程可以併發地執行。 2、線程 ...
  • 虛擬用戶: 不存在於操作系統中,而是專門給對應服務使用的賬號。 虛擬用戶的家目錄: 所有虛擬用戶會統一映射為一個指定的系統帳號:訪問共用位置,即為此統帳號的家目錄 虛擬用戶的許可權: 各虛擬用戶可被賦予不同的訪問許可權,通過匿名用戶的許可權控制參數進行指定 例如:mysql的虛擬用戶就是存放在mysql. ...
  • FTP:File Transfer Protocol ,文件傳輸協議 FTP:屬於NAS存儲的一種協議,基於CS結構。 FTP的工作原理: ftp採用的是雙埠模式,分為命令埠和數據埠 命令埠:固定,tcp/21,命令埠對應的就是命令通道 數據埠:不固定,數據埠對應的就是數據通道 說明: ...
  • Linux 文件操作介面 在使用語言編寫服務的時候不乏會遇到需要對文件進行操作的場景,Linux內核是用C語言寫的,瞭解Linux之前先熟悉一下C語言文件操作介面,方便對比。 C語言文件操作介面 C語言文件描述 #ifndef _FILE_DEFINED struct _iobuf { char * ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...