Stories

Detail Return Return

ByConity 0.3.0 版本發佈,支持倒排索引等新特性 - Stories Detail

來源|ByConity 開源社區

各位的社區小夥伴們大家好,ByConity 0.3.0 版本於 12 月 18 日正式發佈了,此版本提供了倒排索引,基於共享存儲的選主方式等多項新特性,對冷讀性能進行了進一步的優化,對 ELT 能力也進行了進一步的迭代,同時修復了若干已知問題,進一步提升了系統的性能和穩定性,歡迎大家下載體驗。

GitHub 地址:https://github.com/ByConity/ByConity

下載體驗:https://github.com/ByConity/ByConity/releases/tag/0.3.0

01 倒排索引

|背景

在 ByConity 使用過程中,很多業務對文本檢索相關能力(如 StringLike)提出了非常高的需求,希望社區能夠優化相關查詢性能,同時兼容 ClickHouse 在今年支持的倒排索引的能力。為滿足業務訴求,保持生態兼容,同時提升 ByConity 的文本檢索能力,ByConity 在 0.3.0 版本加入了對文本檢索的支持,為日誌數據分析等場景提供高性能查詢。

ByConity 對文本檢索的規劃分成兩個階段——

  • 第一階段,ByConity 在 ClickHouse 社區版本的基礎上進行功能增強;
  • 第二階段,ByConity 計劃支持更多的文本檢索能力,包括詞組查詢 / 模糊查詢等能力,讓 ByConity 也成為一個文本分析工具。

目前在 12 月 18 日發佈的 0.3.0 版本中,第一階段目標已經完成,ByConity 在支持 ClickHouse 倒排索引能力的基礎上,額外支持了中文分詞,並進行了 IO 相關的優化。

|實現

倒排索引是從值到行號的映射,因此引擎可以根據倒排索引來快速地定位到符合條件的數據,避免大量數據的掃描開銷,並且可以減少一些過濾條件的計算開銷。

為 ByConity 增加倒排索引的支持主要包括寫入 / 讀取鏈路的修改——

  • 寫入鏈路的修改主要包括寫入時根據列數據生成倒排索引,並寫到遠端存儲;
  • 讀取鏈路的修改主要包括查詢時依據過濾條件構建表達式來對查詢的數據範圍進行過濾。

增加倒排索引後,引擎的具體寫入流程和讀取流程如下圖所示。

圖片

|使用方式

ByConity 支持使用 Token 分詞,使用 Ngram 分詞,以及使用中文分詞。以下是使用中文分詞的示例。

CREATE TABLE chinese_token_split
(
    `key` UInt64,
    `doc` String,
    -- token_chinese_default 代表使用token_chinese_default分詞器
    -- default 代表使用default配置
    INDEX inv_idx doc TYPE inverted('token_chinese_default', 'default',1.0) GRANULARITY 1
)
ENGINE = MergeTree
ORDER BY key

使用中文分詞需要在配置文件中額外配置詞典和模型。

|下一步規劃

下一階段主要目標是支持更多的文本檢索能力,並進行性能上的優化。

從功能上而言會增加例如對詞組查詢、模糊匹配、文本相關性判斷這些能力的支持,併為倒排索引添加對 JSON 類型的支持。

同時也會進行一些性能的優化,例如目前倒排索引只是用來做 Granule 的過濾,我們依舊需要將整個 Granule 讀出來再進行過濾,但實際上我們可以從倒排索引中直接獲取數據的行號,來直接讀取對應的行;以及現在 Merge 過程中我們依舊是重新構建倒排索引,但是實際上我們完全可以複用之前的分詞結果,來提升 Merge 的效率。

02 基於共享存儲的選主方案

| 背景

在 ByConity 架構中存在多種控制節點,它們需要各自通過多副本 + 選主來提供高可用的服務能力,例如 Resource Manager,TSO 等。實際中的多個計算 server,也需要選出一個單節點來執行特定的讀寫任務。之前 ByConity 使用了 clickhouse-keeper 組件來進行選主,該組件基於 Raft 實現,提供兼容 zookeeper 的選主接口。但是在實際的使用中遇到了很多運維問題,例如需要部署 3 個以上節點才能提供容災,增加運維負擔;節點增刪和服務發現流程複雜;容器重啓後如果服務變換 ip 和服務端口,keeper 組件難以快速恢復,等等。

考慮 ByConity 作為一個新的雲原生服務,並不需要兼容 ClickHouse 對 zookeeper 的訪問,我們選擇了基於存算分離的雲原生架構實現一種新的選主方式來優化以上問題。

| 設計與實現

選主的競爭和結果的發佈可以看成是一個多線程同步問題。受 Linux mutex 鎖實現的啓發,如果我們把 ByConity 多個試圖選主的節點看成不同的線程,把支持事務提交、可見性順序等於事務提交順序的元數據 KV 存儲看成支持 CAS 寫入、保證可見性順序的本地內存,用節點的定期 Get 輪詢去模擬 Linux 內核的線程喚醒通知機制,我們就可以用 ByConity 所使用的高可用 KV 存儲,通過模擬 CAS 操作去同步多節點之間對“誰是 leader”這個問題答案的競爭:誰 CAS 成功誰就是 leader

解決了相互競爭的寫者之間的同步,我們還需要把寫者競爭的結果發佈給讀者。Linux 的鎖的數據結構會記錄誰是 mutex owner,這裏也可以把 leader 的監聽地址寫入競爭的結果:CAS 的 key 寫入內容 value 需要包括自己的監聽地址。所以讀者訪問這個 key 就可以完成服務發現(讀者不需要知道非 leader 的地址)。

leader 選舉的實現包括制定選舉基本規則,實現備選、競選、勝選、就職、續任、主動離職,被動離職等流程,同時解決新舊 2 任 leader 的時間共識,對任期過期的判斷等問題。

下圖介紹了一個新 leader 的產生是如何在 follower 之間競爭產生分佈式共識,並和舊任 leader 以及未來可能出現的新 leader 對這個共識的有效期的安全性產生共識,再讓客户端感知到這個共識的全過程。

圖片

| 實際使用

如果使用 K8s 部署 ByConity 集羣,只需要調整 replicas 屬性就能簡單地增減服務 Pod 副本。

如果採用物理部署 ByConity 集羣並且手動配置,這套方案無需配置內部微服務之間以及副本之間的服務發現,增加的副本只要能啓動即能被發現,並自動參與選主競爭,從而可以從 ByConity 集羣中去除對 clickhouse-keeper 組件配置的依賴。

03 冷讀性能的進一步提升

在 ByConity 0.2.0 中,我們通過引入 IOScheduler 等方式提高了冷讀查詢的性能,尤其是在 S3 上的冷讀性能。0.3.0 版本通過引入 ReadBuffer 的 Preload 等優化,進一步提高了冷讀性能。

主要有以下的優化策略:

| Prefetch

優化了執行側 Mark Ranges 下推的調用棧,引入了 Prefetch,如下圖所示:

圖片

其中:

  1. 階段 1: 將所有需要查詢的 mark 按 Thread 平均劃分
  2. 階段 2: 每個 Thread 的所有 Mark 被進一步細分為多個 Task,方便 Threads 之間 Steal work
  3. 階段 3: 以單個 Task 為單位進行 Prefetch

    • Task 越大,則發送的網絡請求次數越少,但是可能會對 work steal 有影響
    • 不需要擔心 Task 太大對 Prefetch 耗時的影響,因為 PocoHttpClient S3 返回的 Stream 是流式的,從發送請求到返回並不需要讀取全部數據,在請求返回後可以再按需讀取

| 自適應 mark per task

由於 Prefetch 的優化效果受單個 Task 包含的 Mark 數影響顯著,尤其是大查詢和小查詢最優方案採取的 Mark 數可能不同,因此對 mark per task 採取自適應優化。

圖片

  1. 全局 mark pool 在 thread 之間的第一次分配,仍然採取平均分配的策略,保證每個 thread 初始任務大小相同;
  2. 在每個 thread 下的 task,不再採取平均分配的策略。

    • 如果除了正在讀取的 part,剩餘 part 數 >= 1,則這次選擇該 part 內的所有 mask 執行,剩餘 part 可以滿足 steal 的需要
    • 如果剩餘 part 數 = 0,則根據 part 的大小進行切分

此外,我們對第一次 Prefetch 同步等待時間較長的問題,即 long start,也有專門的優化,這裏不再詳述。

| 效果

Prefetch 以及相關的優化可以將 S3 冷讀性能提升一倍以上,HDFS 冷讀性能提升 20% 左右。

04 ELT 能力增強

在 ByConity 0.2.0 發佈的時候我們介紹了 ByConity 在 ELT 方面的規劃,以及在 0.2.0 中提供的能力異步執行,隊列和 disk based shuffle。

在 0.3.0 中,我們引入新的 BSP 模式,通過 stage by stage 的執行以及增強 disk based shuffle,滿足有限條件下的計算,提高吞吐。在 ByConity 中複雜查詢對 query plan 的 stage 進行了切分並進行了 stage by stage 的調度,但在語義上仍然是 all at once 的調度。ELT 在執行時需要對查詢進行分階段運行,需要進一步達到 stage by stage 執行的效果。

| 設計與實現

執行計劃(物理 / 邏輯)自下而上根據 shuffle 拆分成多個 stage,以 plan segment 或者 plan fragment 的形式具體體現,也稱一個 phase。stage 中存在多個 task,每個 task 的計算邏輯相同,但執行的數據分片不同。前後依賴的 stage 的 task 之間有數據交換。

Stage 執行的實現包括調度器的分層重構,引入 StagedSegmentScheduler(DAGScheduler)負責 stage 的狀態管理和調度,TaskScheduler 負責拆分 stage,形成 task set。併為每個 task 選擇調度節點,發送給相應節點;同時我們需要把構建 io 的過程也放到異步執行中,引入 BSP 模式的調度過程,具體過程與我們在 0.2.0 實現的 insert query 中的異步執行的處理邏輯類似,但鑑於 select 和 insert 可能存在某些處理過程的不確定性,後續根據情況做相應方案調整。在後續版本中,我們會對異步處理模式和調度器的實現做進一步的增強。

更多 0.3.0 相關特性及優化的內容可查看:https://github.com/ByConity/ByConity/releases/tag/0.3.0

圖片

加入 ByConity 技術交流羣

user avatar u_17021563 Avatar qiumi_685b70038c171 Avatar apachekylin Avatar 240cgxo4 Avatar guhejiahongdoumianbao Avatar
Favorites 5 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.