資料與儲存 2026 年 8 月 22 日

2026-08-22 — ClickHouse 以 cgroup 隔離 Postgres 背景服務、26.7 片語搜尋索引加速 40 倍,DuckDB Java Driver 支援分塊讀取

primary=https://clickhouse.com/blog/protect-postgres-from-supporting-processes primary=https://clickhouse.com/blog/clickhouse-release-26-07 primary=https://github.com/duckdb/duckdb-java/pull/682 primary=https://duckdb.org/2026/08/21/chunked-query-results-java-driver.html

ClickHouse Managed Postgres 如何用 cgroup v2 隔離「背景服務」搶資源的問題

ClickHouse Blog · 2026-08-21

ClickHouse 於 2026 年 8 月 21 日在官方部落格發表文章,說明其 Managed Postgres 服務如何防止「陪跑」的背景程序拖垮資料庫本體。一個 Postgres 執行個體實際上從來不是只有 postgres 一個行程在跑,還包含 PgBouncer、WAL-G 備份代理、Prometheus、postgres_exporternode_exporter 等四個 Go 服務與監控元件。這篇文章描述的是這些「supporting processes」在記憶體、CPU、磁碟壓力上升時如何被系統性地限制,避免其中任何一個因為記憶體洩漏或流量突增而觸發核心 OOM killer,連帶殺死 Postgres 主行程。

核心改動

整體防線分成三層。第一層是執行期記憶體預算:每個 Go 寫成的背景服務都設定了 GOMEMLIMIT,讓 Go runtime 在逼近設定值前就主動觸發垃圾回收、收縮 heap,這是在核心介入之前的「軟性」自我調節,比等到 cgroup 硬限制或 OOM killer 出手更早、更平滑。

第二層是 cgroup v2 的強制隔離:所有背景服務被放進同一個獨立的 cgroup slice,透過 systemd 的 MemoryHighMemoryMax 屬性對應到 cgroup 的 memory.high(超過會觸發回收與節流)與 memory.max(硬上限,超過觸發僅限該 cgroup 範圍的 OOM)。Postgres 本身則被放在另一個獨立的 cgroup,兩者互不干擾——背景服務吃滿記憶體時,核殺的是它們自己那個 cgroup 裡的行程,而不會波及資料庫。文章也提到 Postgres 的 shared_buffers 是以 huge pages 型式在開機階段就配置好、受保護的記憶體區塊,不受這層 cgroup 記憶體壓力影響。

第三層是排程與磁碟滿載時的應變:CPU 資源以 cgroup 的 CPU weight 比例分配,備份與 WAL-G 相關工作被壓在較低的權重下,確保前景查詢優先取得 CPU;而磁碟即將寫滿時,看門狗(watchdog)機制會終止非關鍵連線階段(session),但明確排除 replication 與 monitoring 兩類使用者的連線,讓維運人員在緊急狀況下仍能連進去查看複寫延遲與系統指標。

影響範圍

這篇文章沒有揭露具體的 memory.highmemory.max 數值或 CPU weight 百分比,走的是架構原則說明而非可直接複製貼上的調校範本。但其設計邏輯值得注意的地方在於:把「資料庫本體」與「維運周邊」在資源隔離層面徹底分開,是託管資料庫服務商用來對外承諾可用性 SLA 的常見手法——同一套模式也出現在該公司先前談 huge pages 與 strict overcommit 記憶體策略的文章中,屬於其 Managed Postgres 一系列可靠性工程文章的延伸。

原始來源:ClickHouse Blog: Protect Postgres from supporting processes


ClickHouse 26.7 為文字索引加入詞位資訊,片語搜尋加速 40 倍

ClickHouse Blog(26.7 版本發布說明) · 2026-08-06

從 ClickHouse 8 月電子報中挑出最具工程份量的項目:26.7 版本發布說明裡的文字索引(text index)升級。這個版本讓文字索引除了記錄「哪些 row 含有這個 token」之外,還額外儲存每個 token 在文本中的位置,這是實作片語搜尋(phrase search)在索引層面加速所必需的資訊——沒有位置資訊,索引只能告訴你兩個詞「都出現在同一列」,無法判斷它們是否相鄰、順序是否正確,也就無法跳過不符合片語的候選列。

規格細節

這是標記為實驗性的功能,需要先開啟 allow_experimental_text_index_phrase_search 設定才能使用。建立索引時在 text 類型索引上加上 support_phrase_search = 1 參數:

INDEX idx_text text TYPE text(
  tokenizer = 'splitByNonAlpha',
  support_phrase_search = 1)

查詢端則透過 hasPhrase(text, 'Google web search') 函式來做片語比對。官方在 HackerNews 資料集上做的基準測試顯示,同一條片語查詢從 1.343 秒降到 0.033 秒,約 40 倍加速——差距主要來自索引可以直接靠 token 位置排除不相鄰的候選列,不需要在符合「同列出現」條件的所有列上做逐字元的字串掃描。

影響範圍

同一份 26.7 發布說明裡還包含幾項 JOIN 相關的優化,其中最大的一項是build-side 建索引後反向剪枝 probe-side granule,在 TPC-H scale 100 的基準測試中達到 6.2× 提速、讀取資料量減少 9.4×、峰值記憶體降低 8.8×;此外新增了 query_plan_optimize_join_order_algorithm = 'dpsub' 的多表 JOIN 動態規劃排序演算法,以及可以印出實際平行度與各階段耗時的 EXPLAIN ANALYZE 子句。文字索引的片語搜尋因為目前仍是實驗性開關,尚未預設開啟,需要應用端自行評估開啟後的索引建置成本與空間開銷再上線。

原始來源:ClickHouse Release 26.7


DuckDB Java Driver 新增分塊讀取 API,繞過 JDBC 逐列取值的效能損耗

DuckDB Blog · 2026-08-21

DuckDB 官方部落格於 2026 年 8 月 21 日發文,介紹 Java driver 1.5.3.0 版本新增的分塊查詢結果 API。DuckDB 的執行引擎內部是以 2,048 列為單位的欄式資料塊(chunk)在運算,但傳統 JDBC 的 ResultSet 介面規定必須逐列(row-by-row)走訪,每一次 rs.next()rs.getLong() 呼叫都要把欄式資料重新包裝成列式的物件存取,這一層轉換在大結果集下會變成明顯的 CPU 開銷。這個新 API 讓呼叫端可以直接拿到引擎原生產生的資料塊,依欄(vector)為單位批次讀取。

核心改動

這個功能來自 PR duckdb-java#682「Support fetching query results in chunks」,作者 staticlibs,於 2026-05-15 合併進 main 分支(merge commit 23448c1),改動涵蓋 22 個檔案、新增 682 行、刪除 52 行。它把 DuckDB C API 既有的 duckdb_fetch_chunk 能力包裝暴露給 Java 層,新增三個類別:

  • DuckDBChunkedResult:管理惰性抓取(lazy)的資料塊序列,以 nextChunk() 逐塊前進
  • DuckDBDataChunkReader:讀取單一資料塊內容,與既有 Java UDF 使用的介面共用同一套 API
  • DuckDBReadableVector:對單一欄(column vector)做型別特化的存取,例如 getLong()getInt()getString()

使用方式上,這條路徑只能透過 DuckDBPreparedStatementquery() 方法取得,索引一律採零基(zero-based),與 DuckDB C API 的慣例一致:

try (DuckDBPreparedStatement ps = conn.prepare(
        "SELECT l_orderkey, l_linenumber, l_shipmode "
      + "FROM 's3://my-bucket-name/lineitems.parquet'")) {
    try (DuckDBChunkedResult res = ps.query()) {
        while (res.nextChunk()) {
            DuckDBDataChunkReader chunk = res.chunk();
            // 依 vector 逐欄讀取
        }
    }
}

影響範圍

目前這條路徑只支援基本型別,LIST、STRUCT 等複合型別的讀取還沒實作;也只開放給 prepared statement,沒有對應 query(String) 的便利多載,也就是說既有直接用字串下查詢再用標準 Statement 執行的程式碼無法直接改用這條路徑,需要先改寫成 prepared statement 形式。官方也表示 reader 的介面覆蓋面目前有限,UTF-8 byte[] 的直接讀取等能力仍在規劃中,尚未落地。

原始來源:duckdb/duckdb-java PR #682DuckDB Blog


End of article
0
Would love your thoughts, please comment.x
()
x