跳至主要內容

ClickHouse 儲存

ClickHouse 是專為分析工作負載而設計的欄式數據庫。@mastra/clickhouse 套件為多個 Mastra 儲存領域提供儲存適配器,亦是生產環境可觀測性建議使用的後端。

ClickHouse 最常在複合儲存設定中用作專用可觀測性後端,並由另一個數據庫處理其餘領域。

何時使用 ClickHouse
何時使用 ClickHouse 的直接連結

用於 trace、日誌、指標、評分及意見回饋的生產環境可觀測性。

在本機開發時,請使用結合 LibSQL(用於 memory 及 workflow)與 @mastra/duckdb(用於可觀測性)的複合儲存。兩者均無法單獨涵蓋開發設定:LibSQL 未有實作可觀測性領域,而 DuckDB 則未有實作其他領域。例子請參閱可觀測性概覽

安裝
安裝 的直接連結

npm install @mastra/clickhouse@latest

你亦需要一個正在運行的 ClickHouse 伺服器。有關託管及自行託管的選擇,請參閱託管選項

使用方式
使用方式 的直接連結

ObservabilityStorageClickhouseVNext 是目前的可觀測性領域實作。它使用由 ReplacingMergeTree 支援的純插入 schema,並針對 trace、日誌、指標、評分及意見回饋所產生的數據量作出最佳化。

將它與另一個儲存適配器組合使用,令可觀測性寫入不會與應用程式數據爭用資源:

src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { MastraCompositeStore } from '@mastra/core/storage'
import { PostgresStore } from '@mastra/pg'
import { ObservabilityStorageClickhouseVNext } from '@mastra/clickhouse'
import { Observability, MastraStorageExporter } from '@mastra/observability'

const observabilityStore = new ObservabilityStorageClickhouseVNext({
url: process.env.CLICKHOUSE_URL!,
username: process.env.CLICKHOUSE_USERNAME!,
password: process.env.CLICKHOUSE_PASSWORD!,
})

export const mastra = new Mastra({
storage: new MastraCompositeStore({
id: 'composite-storage',
default: new PostgresStore({
id: 'pg',
connectionString: process.env.DATABASE_URL!,
}),
domains: {
observability: observabilityStore,
},
}),
observability: new Observability({
configs: {
default: {
serviceName: 'mastra',
exporters: [new MastraStorageExporter()],
},
},
}),
})

當 ClickHouse 是可觀測性後端時,MastraStorageExporter 會自動選擇 insert-only 策略,以提供最高的寫入吞吐量。詳情請參閱 tracing 策略

配合舊有領域使用可觀測性
配合舊有領域使用可觀測性 的直接連結

ObservabilityStorageClickhouse 是原有的可觀測性適配器,尚未遷移至 vNext schema 的項目仍可繼續使用。其設定格式與 vNext class 相同。

import { ObservabilityStorageClickhouse } from '@mastra/clickhouse'

const observabilityStore = new ObservabilityStorageClickhouse({
url: process.env.CLICKHOUSE_URL!,
username: process.env.CLICKHOUSE_USERNAME!,
password: process.env.CLICKHOUSE_PASSWORD!,
})

新項目應改用 ObservabilityStorageClickhouseVNext

從舊有版本遷移至 vNext
從舊有版本遷移至 vNext 的直接連結

要將歷史 span 從舊有的 mastra_ai_spans 資料表遷移至 vNext schema,請執行:

npx mastra migrate

遷移會以每日為一個批次,將 span 數據從 mastra_ai_spans 複製至 mastra_span_events。過程會處理欄位映射,並為舊有資料列去除重複項目。原有資料表會保留作備份。遷移後,trace 會透過 vNext 適配器顯示於 Studio。

備註

舊有資料表不會被刪除。確認遷移成功後,請手動將其移除。

所有領域均使用 ClickHouse
所有領域均使用 ClickHouse 的直接連結

ClickhouseStoreVNext 使用 ClickHouse 支援 memoryworkflowsobservability 領域,並自動採用 vNext 可觀測性適配器。如果你希望整個應用程式均由 ClickHouse 支援,而毋須手動連接複合儲存,便可使用它。

src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { ClickhouseStoreVNext } from '@mastra/clickhouse'

export const mastra = new Mastra({
storage: new ClickhouseStoreVNext({
id: 'clickhouse-storage',
url: process.env.CLICKHOUSE_URL!,
username: process.env.CLICKHOUSE_USERNAME!,
password: process.env.CLICKHOUSE_PASSWORD!,
}),
})

ClickhouseStoreVNext 接受與 ClickhouseStore 相同的設定,並在所有領域重用同一個 ClickHouse client。

手動組合
手動組合 的直接連結

ClickhouseStore 是長期使用的 class,以舊有可觀測性適配器支援所有領域。新項目應優先選用 ClickhouseStoreVNext。如需自訂複合儲存(例如以不同後端覆寫其中一個領域),請手動建立:

src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { MastraCompositeStore } from '@mastra/core/storage'
import { ClickhouseStore, ObservabilityStorageClickhouseVNext } from '@mastra/clickhouse'

const credentials = {
url: process.env.CLICKHOUSE_URL!,
username: process.env.CLICKHOUSE_USERNAME!,
password: process.env.CLICKHOUSE_PASSWORD!,
}

export const mastra = new Mastra({
storage: new MastraCompositeStore({
id: 'composite-storage',
default: new ClickhouseStore({ id: 'clickhouse-storage', ...credentials }),
domains: {
observability: new ObservabilityStorageClickhouseVNext(credentials),
},
}),
})

使用你自己的 ClickHouse client
使用你自己的 ClickHouse client 的直接連結

如需自訂連線設定,例如請求逾時、壓縮或 interceptor,請傳入預先設定的 client:

import { createClient } from '@clickhouse/client'
import { ClickhouseStore } from '@mastra/clickhouse'

const client = createClient({
url: process.env.CLICKHOUSE_URL!,
username: process.env.CLICKHOUSE_USERNAME!,
password: process.env.CLICKHOUSE_PASSWORD!,
request_timeout: 60_000,
compression: { request: true, response: true },
})

const storage = new ClickhouseStore({ id: 'clickhouse-storage', client })

ObservabilityStorageClickhouseObservabilityStorageClickhouseVNext 亦接受相同的 client 格式。

設定
設定 的直接連結

ClickhouseStore 選項
clickhousestore-options 的直接連結

id:

string
此儲存實例的唯一識別符。

url?:

string
ClickHouse 伺服器 URL(例如 https://your-instance.clickhouse.cloud:8443http://localhost:8123)。如未傳入預先設定的 client,此項為必填。

username?:

string
ClickHouse 使用者名稱。如未傳入預先設定的 client,此項為必填。

password?:

string
ClickHouse 密碼。如未傳入預先設定的 client,此項為必填。本機實例的預設使用者可使用空字串。

client?:

ClickHouseClient
來自 @clickhouse/client 並已預先設定的 ClickHouse client。需要自訂請求設定時使用。不可與上述憑證欄位同時使用。

ttl?:

object
建立資料表時套用的逐資料表 TTL 設定。接受以 NANOSECONDYEAR 為間隔單位的資料列層級及欄位層級 TTL。

replication?:

{ cluster?: string; zookeeperPath?: string; replicaName?: string }
供多副本 ClickHouse 叢集選用的複寫資料表設定。設定後,Mastra 會建立複寫的 MergeTree 資料表。設定 cluster 後,Mastra 亦會在由 Mastra 管理的資料定義語言(DDL)中加入 ON CLUSTER

disableInit?:

boolean
= false
設為 true 時,儲存不會在首次使用時建立資料表或執行遷移。請從部署指令碼明確呼叫 storage.init()

ClickhouseStore 亦接受 ClickHouseClientConfigOptions 的所有選項(例如 databaserequest_timeoutcompressionkeep_alivemax_open_connections)。

複寫叢集
複寫叢集 的直接連結

當 Mastra 透過負載平衡器寫入多副本 ClickHouse 叢集時,請使用 replication

const storage = new ClickhouseStoreVNext({
id: 'clickhouse-storage',
url: process.env.CLICKHOUSE_URL!,
username: process.env.CLICKHOUSE_USERNAME!,
password: process.env.CLICKHOUSE_PASSWORD!,
replication: {
cluster: 'company_cluster',
},
})

設定 replication 後,Mastra 會將其 MergeTreeReplacingMergeTree 資料表引擎改寫為 ReplicatedMergeTreeReplicatedReplacingMergeTree。預設引擎引數如下:

  • zookeeperPath: '/clickhouse/tables/{shard}/{database}/{table}'
  • replicaName: '{replica}'

這些預設值符合最常見的自行管理慣例。如果叢集的現有資料表採用不同配置(例如 /clickhouse/tables/{shard}/{table},當中不含 {database} 部分),請明確設定 zookeeperPath 以保持一致。Mastra 不會從 Keeper 讀取叢集的慣例,因此不相符的預設值會將 Mastra 的中繼資料寫入與叢集其餘部分分開的分支。

new ClickhouseStoreVNext({
url: process.env.CLICKHOUSE_URL!,
username: process.env.CLICKHOUSE_USERNAME!,
password: process.env.CLICKHOUSE_PASSWORD!,
replication: {
cluster: 'company_cluster',
zookeeperPath: '/clickhouse/tables/{shard}/{table}',
},
})

設定 cluster,即可在由 Mastra 管理的 DDL 中加入 ON CLUSTER,包括建立資料表、建立 materialized view、欄位遷移、更改 TTL 及移除資料表。

設定 cluster 後,optimizeTable()materializeTtl() 等手動維護工作會在每個副本上執行。在大型叢集上,這些操作可能耗用大量資源。建議在非繁忙時段執行,並讓例行合併在背景合併佇列中進行,避免每次重新啟動時均觸發有關操作。

如現有 Mastra 資料表使用本機 MergeTreeReplacingMergeTree 引擎,啟用 replication 後初始化便會失敗。Mastra 不會在未有提示的情況下轉換本機資料表,因為在副本之間執行複製再交換並不安全。要進行遷移,請在啟用複寫前,將受影響的資料表重新建立為 Replicated*。安全的遷移方式是重新命名本機資料表,執行 CREATE TABLE ... ENGINE = ReplicatedMergeTree(...) ON CLUSTER ...,再執行 INSERT INTO ... SELECT * FROM <renamed_local>,然後移除 <renamed_local>

請勿在 ClickHouse Cloud 上設定 replication。Cloud 會在伺服器端將 MergeTree 改寫為 SharedMergeTree,而明確指定 ReplicatedMergeTree 引擎會產生不正確的 DDL。replication 僅適用於自行管理的多副本叢集。

可觀測性領域選項
可觀測性領域選項 的直接連結

ObservabilityStorageClickhouseObservabilityStorageClickhouseVNext 接受與 ClickhouseStore 相同的連線選項(urlusernamepassword,或預先設定的 client)。

託管選項
託管選項 的直接連結

只要能透過 HTTP 連接,ClickHouse 便可在任何地方運行。常見選擇包括:

本機開發設定:

docker run -d --name mastra-clickhouse \
-p 8123:8123 -p 9000:9000 \
-e CLICKHOUSE_USER=default \
-e CLICKHOUSE_PASSWORD=password \
clickhouse/clickhouse-server
new ObservabilityStorageClickhouseVNext({
url: 'http://localhost:8123',
username: 'default',
password: 'password',
})

部署至 Railway 及類似平台
部署至 Railway 及類似平台 的直接連結

RailwayFly.ioRender 及 Heroku 等平台在暫存檔案系統上運行應用程式容器。DuckDB 等嵌入式可觀測性後端需要可寫入且持久的本機檔案,因此在這些平台上重新啟動時會遺失數據,或完全無法部署。

請改用 ClickHouse。由於 ClickHouse 透過 HTTP 連接,因此同一個連線可在任何主機上使用:

src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { MastraCompositeStore } from '@mastra/core/storage'
import { PostgresStore } from '@mastra/pg'
import { ObservabilityStorageClickhouseVNext } from '@mastra/clickhouse'
import { Observability, MastraStorageExporter } from '@mastra/observability'

export const mastra = new Mastra({
storage: new MastraCompositeStore({
id: 'composite-storage',
default: new PostgresStore({
id: 'pg',
connectionString: process.env.DATABASE_URL!,
}),
domains: {
observability: new ObservabilityStorageClickhouseVNext({
url: process.env.CLICKHOUSE_URL!,
username: process.env.CLICKHOUSE_USERNAME!,
password: process.env.CLICKHOUSE_PASSWORD!,
}),
},
}),
observability: new Observability({
configs: {
default: {
serviceName: 'mastra',
exporters: [new MastraStorageExporter()],
},
},
}),
})

可透過以下任一選項佈建數據庫:

  • 託管:使用 ClickHouse Cloud。在託管平台中將 CLICKHOUSE_URLCLICKHOUSE_USERNAMECLICKHOUSE_PASSWORD 設為環境變數。
  • 在 Railway 自行託管:使用官方 Docker 映像,在 Railway 項目中加入 ClickHouse 服務,然後透過 Railway 的私人網絡在應用程式服務中參照該服務。

同一種做法亦適用於其他使用暫存檔案系統的主機。如果應用程式數據亦應儲存於主機以外的位置,請將此設定配合受管理的 PostgreSQL 或 LibSQL/Turso 實例,作為 default 儲存。

注意

請勿將 DuckDB 等嵌入式後端指向暫存容器檔案系統內的路徑。容器重新啟動時,寫入該處的數據會遺失,而在部分平台上該路徑更是唯讀。

初始化
初始化 的直接連結

傳入 Mastra class 後,ClickhouseStore 會自動呼叫 init() 來建立 schema,並執行任何待處理的遷移。透過 MastraCompositeStore 使用 ObservabilityStorageClickhouseVNext 時亦一樣。

如你在 Mastra 以外管理儲存,請明確呼叫 init()

import { ObservabilityStorageClickhouseVNext } from '@mastra/clickhouse'

const observability = new ObservabilityStorageClickhouseVNext({
url: process.env.CLICKHOUSE_URL!,
username: process.env.CLICKHOUSE_USERNAME!,
password: process.env.CLICKHOUSE_PASSWORD!,
})

await observability.init()

在 CI/CD pipeline 中,請在 ClickhouseStore 設定 disableInit: true,並從使用較高權限憑證的部署步驟執行 init()。之後便可將執行階段應用程式憑證限制為讀取及插入權限。

可觀測性
可觀測性 的直接連結

ClickHouse 是生產環境可觀測性建議使用的後端:

  • 純插入策略MastraStorageExporter 會分批寫入已完成的 span,而不會逐一更新 span,是現有策略中吞吐量最高的一種。
  • 欄式壓縮:與資料列導向數據庫中的相同數據相比,span 屬性及日誌 payload 可獲得更佳壓縮效果。

如需完整策略矩陣及生產環境指引,請參閱 MastraStorageExporter 參考