得物可觀測平臺架構升級:基于GreptimeDB的全新監控體系實踐
一、摘要
二、部署架構
1. GreptimeDB分布式架構
2. 透明數據緩存
3. 無畏擴縮容
三、GreptimeDB Flow 流計算實踐
1. 多級持續聚合架構
2. UV 近似統計:HyperLogLog
3. 效果與收益
四、最佳實踐與落地建議
一、摘 要
在前端可觀測分析場景中,需要實時觀測并處理多地、多環境的運行情況,以保障 Web 應用和移動端的可用性與性能。傳統方案往往依賴代理 Agent → 消息隊列 → 流計算引擎 → OLAP 存儲的多級架構,雖然能滿足基本數據接入與查詢需求,但面臨以下困難與挑戰:
- 分層架構的精細化演進:
當前分層模型在支撐多業務場景時,需要為分鐘級、小時級、天級等不同時間粒度的數據視圖分別構建計算鏈路。這種模式在保障靈活性的同時,可能存在存儲與計算資源的重復消耗現象,如何通過增量計算或動態視圖技術實現"一次計算多級復用",或將成為提升資源利用效率的關鍵突破點。
- 復雜分析場景的效能平衡:
在應對全量 Join、多維交叉分析等高復雜度場景時,現有的按量計費機制與計算資源調度策略,可能在高頻業務周期(如大促活動)中面臨成本曲線的非線性增長挑戰。探索預計算加速、智能冷熱分層與彈性資源調度的深度結合,或許能進一步釋放大規模分析場景的性價比潛力。
- 生產環境的安全加固:
基于 SQL 的敏捷開發模式在提升數據處理效率的同時,也對企業級數據資產管理提出了更高要求。通過強化語法預校驗、分區保護機制、操作審計追溯等防護手段,構建覆蓋開發、測試、發布全流程的可靠性護城河,將有效降低誤操作風險并提升數據治理成熟度。
本文聚焦將前端可觀測后端數據分析場景演進到 GreptimeDB 的實踐,深入剖析如何利用 GreptimeDB Flow 引擎實現 10s、1m、10m 等多粒度持續聚合,結合HyperLogLog 與 UDDsketch 函數,為前端可觀測場景提供高性能、低成本且易于運維的端到端解決方案。
二、部署架構
圖片
為解決前述痛點,逐步將時序/觀測數據場景遷移至 GreptimeDB,并借助其內置的Flow引擎(SQL)自動維護秒級、分鐘級、小時級等多精度下采樣表,可極大簡化分層建模和物化視圖運維。
GreptimeDB分布式架構
采用 GreptimeDB 開源的分布式模式,在這種模式下,GreptimeDB 的節點可以分為如下角色:
圖片
- Frontend:負責協議處理、請求校驗和鑒權、初步查詢優化,是一個無狀態節點,可以根據負載任意擴縮容。
- Datanode:負責管理數據分片、處理數據寫入和持久化以及執行具體的查詢。
- Flownode:對于配置了流計算任務的集群,Flownode 負責接受 Frontend 鏡像而來的寫入請求并執行流計算任務。流計算的結果最終會被寫入到 Datanode 中進行持久化。
- Metasrv:GreptimeDB 的控制面組件,負責管理集群的元數據(如表的分片路由信息等)。Metasrv 本身是無狀態的,這里我們采用 PostgreSQL 作為后端存儲。
透明數據緩存
GreptimeDB 對數據訪問層進行了高度的抽象,負責管理數據分片的 Datanode 并不需要感知到數據文件位于本地磁盤還是對象存儲。但是考慮到當使用對象存儲時數據文件的訪問延遲會大大增加,因此 GreptimeDB 設計了多層的透明數據緩存來解決此問題。
(GreptimeDB 的緩存結構)
GreptimeDB 的緩存結構如上圖所示。從緩存所在位置可以分為磁盤緩存和內存緩存兩類:
- 磁盤緩存的數據來源通常是對象存儲,其類似于操作系統的 page cache,只不過 page cache 是利用內存加速磁盤數據的訪問,而 GreptimeDB 的這部分緩存則是利用磁盤加速對象存儲的訪問,將頻繁訪問的文件按范圍緩存到磁盤可以實現更低的查詢延遲,并且能夠智能根據訪問模式實現預取(prefetch)、IO 合并等優化。
- 內存緩存除了原始的文件內容之外也包括從磁盤/對象存儲的原始內容反序列化出來的數據結構,如字段的 min/max,bloomfilter 等等。
而從數據類型來分可以分為結構化和非結構化兩類:
- 非結構化緩存的內容通常是文件的二進制內容,而緩存的 key 則是文件名加上字節范圍。比如在 flush 的過程中寫入到對象存儲的文件往往是大概率很快就會被查詢的熱數據,因此可以在本地緩存一份避免查詢請求穿透到對象存儲。
- 結構化緩存則是文件、索引的內容或元數據反序列化得到的結構體,這些數據在查詢剪枝時頻繁被用到,因此 GreptimeDB 緩存了反序列化之后的結構,避免頻繁反序列化帶來的開銷。
盡管 GreptimeDB 的緩存機制較為復雜,但是用戶無需過多了解細節,只需要給定特定的緩存大小,GreptimeDB 會自動分配各類緩存的配額以及管理緩存的分配和釋放,具體調優指南請參考附錄[1]。
無畏擴縮容
GreptimeDB 的最小數據讀寫單元是表的數據分片(稱之為 region)。Region 可以在不同的節點之間進行遷移。目前開源版本的 GreptimeDB 支持手動通過 migrate_region函數進行 region 的遷移(詳見附錄[3])。當監控發現某些 datanode 的負載較高時,可以將部分 region 遷移到其他較為空閑的 datanode 上避免可用性的降級。
圖片
此外,GreptimeDB 是面向云原生基礎設施設計的數據庫,其 Metasrv 節點能夠實時采集各個節點的負載并且將流量在不同節點之間進行分配。對于不同的負載讀寫特性,還可以利用 Kubernetes 的彈性調度特性來調整不同節點組的副本數量來實現讀寫分離。關于 GreptimeDB 讀寫分離的實踐,可以參考附錄[2]。
三、GreptimeDB Flow 流計算實踐
GreptimeDB Flow 是一個專為時序場景設計的輕量級流計算引擎。 它特別適用于提取 - 轉換 - 加載 (ETL) 過程或執行即時的過濾、計算和查詢,例如求和、平均值和其他聚合。通過在 Frontend 將寫入流量鏡像一份到 Flownode 進行計算再寫回 Frontend 并進行持久化,它可以確保數據被增量和連續地處理,根據到達的新的流數據更新最終結果。
圖片
更加重要的是,編寫一個 Flow 流計算任務無需額外的學習成本,它完全使用 SQL 語句定義計算任務。如以下語句:
圖片
定義了一個名叫 ngx_status_count 的任務,它負責流式地統計 ngx_access_log 表中每分鐘內每個不同狀態碼的訪問日志數量。在AS 之后的任務定義部分是一個標準的 SQL,因此對于熟悉 SQL 的開發者來說極容易上手。
多級持續聚合架構
10s 粒度熱數據層
CREATE FLOW rpc_cost_10s
SINK TO rpc_cost_10s_agg
EXPIRE AFTER '12hours'::INTERVAL
AS SELECT
app_name,
url,
date_bin('10s'::INTERVAL, timestamp) AS time_window,
uddsketch(cost_time_ms, 0.01, 0.001) AS cost_sketch
FROM rpc_cost_time
GROUP BY app_name, url, date_bin('10s'::INTERVAL, timestamp);
說明:每 10s 計算一次 UDDsketch,近似捕獲耗時分布,并寫入“熱表”,支持毫秒級查詢。
1m 粒度中層 Roll?up
CREATE FLOW rpc_cost_1m
SINK TO rpc_cost_1m_agg
EXPIRE AFTER '30days'::INTERVAL
AS SELECT
app_name,
url,
date_bin('1m'::INTERVAL, time_window) AS time_window_1m,
uddsketch_merge(cost_sketch) AS cost_sketch_1m
FROM rpc_cost_10s_agg
GROUP BY app_name, url, date_bin('1m'::INTERVAL, time_window);
說明:周期性合并 10s 粒度的 sketch,生成分鐘級聚合,保留 30 天。
10m 粒度冷層
CREATE FLOW rpc_cost_10m
SINK TO rpc_cost_10m_agg
EXPIRE AFTER '180days'::INTERVAL
AS SELECT
app_name,
url,
date_bin('10m'::INTERVAL, time_window_1m) AS time_window_10m,
uddsketch_merge(cost_sketch_1m) AS cost_sketch_10m
FROM rpc_cost_1m_agg
GROUP BY app_name, url, date_bin('10m'::INTERVAL, time_window_1m);
說明:進一步合并至 10 分鐘級,存入低成本對象存儲,保留 180 天。
UV 近似統計:HyperLogLog
和耗時分布統計類似,統計各個 URL 的獨立訪問量(UV)也是常見的需求。不過想要精確統計特定時間段的 UV 成本是極高的,因此業界往往使用近似算法來實現 UV 計算,如 HyperLogLog。GreptimeDB v0.12 提供了對 HyperLogLog 相關函數的支持,結合 Flow 可以實現強大的任意時間段 UV 近似統計。
圖片
10s UV 狀態
CREATE FLOW uv_hll_10s
SINK TO uv_state_10s
EXPIRE AFTER '12hours'::INTERVAL
AS SELECT
app_name,
url,
date_bin('10s'::INTERVAL, ts) AS time_window,
hll(user_id) AS uv_state
FROM access_log
GROUP BY app_name, url, date_bin('10s'::INTERVAL, ts);
- hll 函數: Flow 任務中我們通過 hll 函數將同一時間窗口內的 user_id 進行散列并寫入到 uv_state_10s 的 uv_state 字段中。
- uv_state BINARY 類型: 是一個二進制字段(BINARY 類型),無法直接進行查詢。如果要查詢某個10 秒的時間窗口內的獨立訪問用戶量,需要通過 hll_count 函數來進行查詢。
SELECT
`app_name`,
`url`,
hll_count(`uv_state`) as uv_count
FROM uv_state_10s
WHERE time_window = 1743479260;
1m UV 聚合
- 如果用戶需要進一步將 10 秒的訪問數據聚合到 1 分鐘或者直接需要查詢特定時間段內的用戶訪問數量,則可以通過hll_merge 函數來對二進制的 HyperLogLog 狀態進行合并。
CREATE FLOW uv_hll_1m
SINK TO uv_state_1m
EXPIRE AFTER '180days'::INTERVAL
AS SELECT
app_name,
url,
date_bin('1m'::INTERVAL, time_window) AS time_window_1m,
hll_merge(uv_state) AS uv_state
FROM uv_state_10s
GROUP BY app_name, url, date_bin('1m'::INTERVAL, time_window);
- 查詢示例:
SELECT
app_name,
url,
hll_count(uv_state) AS uv_count
FROM uv_state_1m
WHERE time_window_1m = '2025-04-20T15:23:00Z';
GROUP BY app_name, url;
效果與收益
- 查詢性能顯著提升:
預聚合 + 多級 Roll?up,避免全量掃描,P99 查詢延遲從秒級降至毫秒級。
圖片
- 存儲與成本可控:
不同粒度數據設置差異化 TTL:10s 熱表保留 1 天,1m 中表保留 7 天,10m 冷表保留 180 天,冷熱分離降低存儲成本。
- 資源解偶 & 彈性擴縮容:
Frontend、Flownode、Datanode 獨立伸縮,流計算、存儲、查詢三者互不干擾。
- 開發效率提升:
Flow 編寫使用標準 SQL,上手難度低,Roll?up、HyperLogLog、UDDsketch 等內置函數無需額外學習曲線。
四、最佳實踐與落地建議
- 合理劃分數據分層:根據監控場景與 SLA 要求確定不同粒度保留策略。
- 調整 sketch 精度:UDDsketch 支持自定義誤差范圍(α、β 參數),可根據業務側對 P50/P99 精度要求調優。
- 監控與告警:為各級聚合任務配置失敗重試與告警機制,確保持續計算的穩定性。
- 資源規劃:根據寫入 QPS 與聚合復雜度合理預估 Flownode 與 Datanode 數量,結合對象存儲帶寬設計分區策略。
參考文檔:
1. 性能調優技巧 | GreptimeDB Documentation | Unified Time-Series Database(https://docs.greptime.com/zh/user-guide/administration/performance-tuning-tips/#%E5%A2%9E%E5%A4%A7%E7%BC%93%E5%AD%98%E5%A4%A7%E5%B0%8F)
2. 【使用指南】在 Kubernetes 上部署讀寫分離的 GreptimeDB 集群
3. Region Migration | GreptimeDB Documentation | Unified Time-Series Database(https://docs.greptime.com/zh/user-guide/administration/manage-data/region-migration/#select-a-datanode-as-the-migration-destination)