資料與儲存 2026 年 7 月 3 日

2026-07-03 — ClickHouse 查詢合併 69 倍、PgBouncer 艦隊架構突破單核瓶頸,Redis 定義 AI Agent 記憶的語意過載問題

primary=https://clickhouse.com/blog/artemis-security-real-time-threat-detection primary=https://clickhouse.com/blog/pgbouncer-clickhouse-managed-postgres primary=https://redis.io/blog/semantic-overload-ai-agents-facts-relationships/

資安新創 Artemis 用查詢合併術,把偵測規則執行時間從 173 秒壓到 2.5 秒

ClickHouse Blog · 2026-07-01

資安新創 Artemis SecurityClickHouse 官方部落格的文章中,揭露了他們如何把單一批次的偵測規則查詢從 173 秒壓到 2.5 秒。Artemis 是一家 2026 年 4 月低調上線、募得 7000 萬美元的 AI 原生威脅偵測平台,靠 AI agent 持續對客戶的日誌資料下查詢找可疑行為。這篇文章記錄的是他們在 ClickHouse Cloud 上做的架構調整,其中「查詢合併」讓偵測規則的執行速度提升了 69x

原本的問題

Artemis 每天要處理數量以「兆位元組壓縮日誌、數百億列」計的資料,整體規模是對數兆列資料跑數百萬次查詢。最大的效能瓶頸來自每個客戶要跑一百多條獨立的偵測規則,每一條規則各自是一個 SQL 查詢,卻掃描完全相同的時間窗口資料,造成重複掃描的乘數效應。

另一個問題出在資料本身:多租戶的 SharedMergeTree 資料表裡存了大量 JSON 欄位,這些欄位沒有針對巢狀欄位建立高效索引,任何查詢都得在讀取當下即時解析 JSON,來自 CloudTrail、身分、網路、端點等數十種異質日誌來源的半結構化 schema 還會持續變動,讓解析成本雪上加霜。

採用的方法

Artemis 的核心作法是查詢合併(query coalescing):把同一客戶底下多條規則的判斷條件,用 ClickHouse 原生函式合併進單一查詢裡執行,符合條件的資料列會被標記上所有觸發它的規則 ID,而不是分別對每條規則各跑一次全表掃描。實作上有幾個關鍵調整:

  • 自動排除約 15% 無法合併的規則,包括用到 CTE、JOIN、GROUP BY、LIMIT、子查詢,或是在 ARRAY JOIN 裡用到 lambda 的規則
  • max_query_size 上限從 256 KB 調高到 1 MB,讓合併後動輒巨大的單一查詢語句塞得下
  • 加入二分切割(binary-split)的降級批次機制,查詢超過大小限制時自動拆成更小批次重試

另外針對 JSON 欄位的查詢,Artemis 把常被查詢的 JSON 子欄位額外抽出,建立成型別原生(非 JSON)的平行物化視圖(materialized view),查詢時先在抽取出來的表上做過濾,縮小時間範圍後再回頭查完整的 JSON 表,形成「兩段式」查詢模式。

實際效果

優化項目優化前優化後倍數
單批查詢合併 150+ 條規則173 秒2.5 秒69x
CPU 使用量(同一批查詢)基準值降低46x
記憶體 I/O(同一批查詢)基準值降低100x
狀態/事件代碼過濾(物化視圖)12 秒0.2 秒60x
依來源 IP 分組(物化視圖)45 秒1.5 秒30x

生產環境中,100 條以上規則組成的批次現在可以在一秒內執行完畢,而依查詢型態不同,物化視圖帶來的 CPU 用量降幅落在 60x400x 之間。文章也提到 Artemis 另外用一套整合 ClickHouse 系統表、CloudWatch、Datadog 的 Claude Code 技能(內部代號 /poke)做效能除錯,一次針對突發實例效能下降的調查在 90 秒內就定位出 8 GiB 以上的記憶體用量與 42 TiB 的資料讀取量。

原始來源:How Artemis Security runs 69x faster detection queries with ClickHouse Cloud


ClickHouse Managed Postgres 用一整組 PgBouncer 打破連線池的單執行緒天花板

ClickHouse Blog · 2026-07-01

ClickHouse Postgres 工程主管 Kaushik Iska 在 ClickHouse 官方部落格撰文,說明 ClickHouse Managed Postgres(ClickHouse Cloud 底下的託管 PostgreSQL 服務)如何解決連線池軟體 PgBouncer 的單執行緒瓶頸。做法是在同一台機器上跑一整組 PgBouncer 行程,並用 Linux 的 SO_REUSEPORT 讓它們共用同一個對外連接埠。在 16 vCPU 的 c7i.4xlarge 測試機型上,這套架構把尖峰吞吐量從約 8.7 萬 TPS 拉高到 33.6 萬 TPS。

原本的問題

PgBouncer 的根本限制是單一行程只能吃滿一顆 CPU 核心,不管機器實際有幾顆核心都一樣。在 16-vCPU 的執行個體上,這代表連線池行程會先於 PostgreSQL 本身觸頂:PgBouncer 這顆核心被打到接近滿載,其餘 15 顆核心卻是閒置的,整體吞吐量還沒摸到資料庫的極限就先被連線池卡死。

對於 Managed Postgres 這種要同時服務大量租戶連線的場景,客戶端連線數一旦往上衝,單一 PgBouncer 行程就會變成無法繞過的天花板,即便後端 Postgres 叢集還有餘裕也無濟於事。

採用的方法

ClickHouse 的解法是把單一 PgBouncer 行程換成一支「艦隊(fleet)」,讓多個行程平行分攤負載:

  • 依可用核心數部署對應數量的 PgBouncer 行程,測試機型上是 16 個行程
  • 所有行程用 SO_REUSEPORT socket 選項綁定同一個連接埠,由核心(kernel)在行程之間自動負載平衡連入的連線
  • 客戶端只需連到單一個對外端點,完全不用知道背後其實有多個連線池行程
  • 沿用 transaction 模式做連線池化:一筆交易一提交,伺服器端連線就立刻歸還連線池
  • 行程之間彼此「認得」對方(peering),這樣當取消查詢的請求被核心誤導到錯誤的行程,該行程能把取消請求轉發給實際握有該連線的行程
  • 把連線預算(max_client_connmax_db_connections)依行程數量平均切分

概念上等同於讓多個 PgBouncer 監聽同一個埠:

# 每個行程各自的設定,靠 SO_REUSEPORT 共享同一個埠
so_reuseport = 1
listen_port = 6432
pool_mode = transaction
max_client_conn = 分配後的配額
max_db_connections = 分配後的配額

實際效果

ClickHouse 在同款 c7i.4xlarge(16 vCPU)機器上,分別對單一 PgBouncer 行程與 16 行程艦隊做壓測:

並發客戶端數單一行程 TPS艦隊 TPS單一行程 CPU艦隊 CPU
88,9106,4500.8%2.9%
6486,570219,4398.3%31.9%
25676,893336,4697.7%48.9%

在 256 個並發客戶端時,單一行程的吞吐量因為卡在一顆核心而先降後平,CPU 使用率顯示它已經被釘死在接近滿載的一整顆核心上;艦隊架構則把負載攤開到約 8 顆核心,尖峰吞吐量達到 336,469 TPS,相較單一行程的 76,893 TPS 是約 4x 的提升。值得注意的是在並發數僅 8 的低負載情境下,艦隊架構的 TPS(6,450)反而略低於單一行程(8,910),顯示多行程協調本身在低競爭場景下有額外開銷。

原始來源:How we scale PgBouncer in ClickHouse Managed Postgres


Redis 把 AI Agent 記錯事實的問題定名為「語意過載」,開出混合檢索與圖譜記憶的藥方

Redis Blog · 2026-07-02

Redis 官方部落格在 一篇文章中,把 AI agent 從檢索資料裡撈到過時或矛盾事實的現象定名為語意過載(semantic overload)。作者 Jim Allen Wallace 舉例:agent 自信地告訴使用者育嬰假是 12 週,但公司政策一年前已經改成 16 週,舊版 HR 手冊、新版手冊、和 Slack 公告全部都還在檢索索引裡,向量搜尋只是撈到了餘弦相似度最高的那份過時 PDF。

什麼是語意過載

語意過載指的是把過多、過雜、或彼此矛盾的語意內容塞給 agent,反而讓表現變差的一群失效模式。Transformer 架構讓 n 個 token 之間產生 n 平方量級的兩兩關聯,每個 token 都在跟其他 token 搶注意力,資料塞得越多,模型不見得答得更準,反而可能更慢、更容易答錯。

業界已經歸納出五種常見的情境失效模式:context poisoning(脈絡遭污染)、distraction(分心)、confusion(混淆)、clash(衝突)、以及 context rot(脈絡腐化)。這五種模式各自描述內容過多或過雜如何拖垮推理,合起來就是語意過載在實務上的具體樣貌。

向量檢索抓不到的關聯

向量檢索能找出語意相近的內容,卻無法推理事實彼此之間怎麼連結。文章用一個多跳(multi-hop)問題示範這個限制:文件 A 說「幫浦 X」接到「閥門 Y」,文件 B 說「閥門 Y」容易觸發「壓力警告 Z」,若問「幫浦 X 有什麼風險」,一般向量搜尋大概率會失敗,因為「幫浦 X」跟「壓力警告 Z」從沒出現在同一個文字區塊裡,向量資料庫把它們索引成向量空間裡互不相干的兩個鄰域,沒有明確的關係邊可走。

語意相近也不等於事實正確。餘弦相似度在處理否定語意時尤其吃力:像「happy」跟「not happy」這類詞語的向量嵌入往往彼此靠得很近,即使意思完全相反,一個查詢只要卡在一個「不」字,照樣可能撈回原本想排除的內容。另外向量搜尋按語意排序而非時間排序,本身沒有「新舊」的概念,2023 年點名某家供應商的舊報告,可能跟 2024 年已經替換掉它的新公告並列出現,相似度分數完全沒有標示哪一份才可信——這正是文章開頭育嬰假案例的成因。

記憶體裡的關聯缺口

同樣的問題也出現在 agent 跨會話(session)記憶上。目前常見的 agent 記憶多半是線性、非結構化,或簡單的鍵值儲存:固定長度的 token 序列、向量資料庫、或是流水帳式的日誌緩衝區,這些方式能把事實存進去也能撈出來,卻沒有記錄事實彼此的關係——哪個取代了哪個、哪個導致了哪個、哪些該被歸在一起。這段缺失的關係層,就是所謂的關聯缺口(relational gap),具體會表現成四種生產環境常見狀況:

  • 矛盾:扁平儲存把互相衝突的事實並列存放,沒有任何標記說明哪一筆才是最新的
  • 時效:例如「Alice 曾在新創公司工作,現在在大型科技公司」,若沒有記錄各筆事實成立的時間點,兩者會被同等看待
  • 來源:儲存的事實沒有記錄出處,答案難以驗證或追溯
  • 規模:每次互動都往記憶裡塞,久了有用的事實會被雜訊淹沒,拖慢檢索速度

四種緩解做法與 Redis Iris

文章提出四種能各自解決部分問題的做法,沒有單一技術能包辦所有語意過載的失效模式:

  • 混合搜尋(hybrid search):把密集向量檢索跟稀疏的關鍵字(lexical)檢索混用,再疊上 metadata 過濾,用關鍵字比對抓住向量搜尋容易模糊掉的精確用詞
  • 交叉編碼器重排(re-ranking with cross-encoders):把查詢跟每份候選文件一起編碼再重新打分,找出第一輪向量搜尋排名排得太低的相關結果,代價是延遲變高
  • 知識圖譜與 GraphRAG:檢索的對象換成互相連結的實體與關係,而不是各自獨立的文字區塊,能走通前面幫浦 X 到閥門 Y 到壓力警告 Z 的推理鏈,但建圖本身容易出錯,對開放式問題的幫助也有限
  • 結構化的圖式記憶:讓 agent 能查到像「使用者 A 在某日購買了產品 X」這種明確關係,而不是把一大塊文字丟進 prompt 賭模型自己挑出重點

Redis 在文章最後把這套思路對應到自家產品 Redis Iris:一個介於 agent 與資料之間的「情境引擎」,把檢索、記憶、資料新鮮度三層包成 Redis Cloud 上的全託管服務,包括做語意快取的 LangCache、處理跨會話記憶的 Agent Memory、面向結構化商業資料的 Context Retriever,以及負責資料同步的 Data Integration,向量、全文、混合搜尋則統一跑在 Redis Search 之上。

原始來源:Semantic overload: why AI agents get facts wrongKnowledge graphs & GraphRAG for AI agent memory


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