映客基於 Clickhouse 的日誌體系建設實踐

背景介紹

作爲線上定位問題和排查故障的重要手段,日誌在可觀測領域有着不可替代的作用。因此,日誌系統需要追求穩定性、性能、成本、易用性、可擴展性等關鍵點。

目前我司的日誌系統是基於 ELK 的,支持雲主機、容器日誌採集和特殊分類日誌的綜合採集等功能。但是隨着公司的業務發展,日誌應用場景逐漸遇到了一些瓶頸:

  1. 數據增長和處理需求增加:業務的不斷擴張和數據量的增加,原有的日誌系統無法滿足現有的數據處理需求。數據處理速度變慢,存儲空間不足等問題。

2. 數據質量和可靠性要求提高:日誌數據對於公司業務和運維至關重要,因此數據質量和可靠性要求越來越高。原有的日誌系統存在日誌丟失、日誌收集慢等問題,需要進行改進。

現狀:目前總共運行 8 個 ES 集羣,機器數量 100+, Logstash 機器 50+,需要的硬件和維護成本很高,通過擴容的方法去滿足業務場景,ES 集羣會太大會變動不穩定,創建獨立集羣,也需要更高成本,兩者都會使得成本和維護工作量劇增。

鑑於這些問題,去年下半年開始探索新的日誌系統架構,以徹底解決上面的問題。

目前主流日誌平臺對比

新的日誌平臺關鍵需求

  1. 功能

高效支持聚合查詢
支持多區域和跨租戶查詢

  1. 效率和維護

降低成本,並能處理 10 倍規模的問題
提高可靠性,簡化操作

  1. 從 ELK 平臺透明遷移

兼容性:能夠無縫遷移現有的 ELK 平臺的數據,無需進行大量修改
最好用戶可以繼續使用類 Kibana 來交互分析日誌

  1. 增強日誌系統的完整性

高性能採集器:採用高性能的採集器,提高日誌收集的速度,降低數據採集延遲。
並行處理:採用並行處理的方式,同時處理多個日誌數據流,提高數據處理速度和效率。

新架構

日誌採集 - Log-Pilot for filebeat

Log-Pilot 是在 Kubernetes 中進行容器日誌收集的工具,具有易於部署和使用、支持多種日誌來源、實時日誌查看和搜索、多種輸出方式等優點。支持動態發現配置的能力,採用聲明式日誌配置,可以自動化日誌收集和處理,降低配置的複雜性和出錯的風險。缺點是目前已經沒有維護者了,存在一定的風險和不確定性,但靈活性和易用性比較好。

**日誌解析 - **vector

Vector 是高性能的可觀察性數據管道, 可以收集、轉換日誌、指標和跟蹤信息( logs, metrics, and traces),並將其寫到想要的存儲當中;可以實現顯着的成本降低、豐富的數據處理和數據安全;

Vector 用 Rust 編寫, 設計理念是簡單、高性能、易擴展和低資源佔用,包括自定義 DSL,以一種安全、高性能的方式動態轉換數據。同時支持自定義插件來滿足更復雜的需求,在性能和資源佔用方面表現出色,特別是在處理大規模數據流時。

聚合器用於處理從多個上游源收集數據並執行跨主機聚合和分析。vector 既可以用作代理,也可以用作聚合器。

vector 配置文件

#  來源(sources)
[sources.my_source_id]    # "數據源"名稱
  type = "kafka"          # 類型
  bootstrap_servers = "10.x.x.1:9092,10.x.x.2:9092,10.x.x.3:9092"    # kafka鏈接地址
  group_id = "consumer-group-name"      # 消費組id   
  topics = [ "^(prefix1|prefix2)-.+" ]  # topic,支持正則
# 變換[可選](transforms)      
[transforms.my_transform_id]    # "變換" 名稱
  type = "remap"                # 類型
  inputs = ["my_source_id"]     # "來源"名稱
  source = ". = parse_key_value!(.message)"  # 以鍵/值格式解析值
# 打印輸出到console
[sinks.print]
  type = "console"
  inputs = ["my_transform_id"]
  encoding.codec = "json"
# 水槽(sinks)
[sinks.my_sink_id]      # "水槽"名稱(數據往哪發送)
  type = "clickhouse"   # 類型
  inputs = [ "my_transform_id" ]       # 輸入,這裏的輸入是上一層的“變換”名稱 
  endpoint = "http://127.0.0.1:8123"   # 輸出的地址
  database = "default"     # clickhouse 數據庫名稱
  table = "table"          # clickhouse 表名稱
  auth.strategy = "basic"  # 身份驗證策略
  auth.user = "user"
  auth.password = "password"
  compression = "gzip"        # 壓縮配置
  skip_unknown_fields = true  # 允許丟棄表中不存在的字段
vector 寫入 clickhouse 需要注意的點:
  1. Vector 自帶的自動均衡 topic 功能可以保證數據基本均勻分佈

  2. 合理設置數據批次大小和寫入頻率,以控制數據寫入的速度和頻次,降低 parts 數量、減少服務器 merge、避免 Too many parts 異常的發生。使用閾值控制數據的寫入量和頻次,超過 10w 記錄寫一次或者 10s 寫一次。

batch.max_bytes = 2000000000   # 限制每個批次的最大字節數
batch.max_events = 100000    # 限制每個批次的最大事件數
batch.timeout_secs = 10      # 限制批處理操作的最大等待時間

3. 使用分佈式表可以將數據拆分成多個 parts 並在不同服務器上進行寫入,可以提高寫入速度和可靠性。

  1. 在建表時,根據業務需求和數據特性合理設置 partition,避免過多的 partition 和異常的發生。

  2. 合理設置主鍵和索引,避免數據亂序,從而提高寫入速度和數據的可查詢性。

總之,Vector 提供的自動均衡 topic 功能、合理的數據批次、寫入頻率、分佈式表的使用以及主鍵、索引的設置都可以對 Vector 寫入 ClickHouse 數據庫的性能和穩定性產生重要的影響,需要仔細評估和調整。

日誌存儲 - Clickhouse

選擇 clickhouse 的原因

  1. 具有高寫入吞吐量:對比 Elasticsearch (ES),ClickHouse 在寫入吞吐量方面更加高效。

  2. 具有高吞吐量的單個大查詢能力

  3. 服務器成本更低

  4. 更穩定,運維成本更低

  5. ClickHouse 採用 SQL 語法,比 ES 的 DSL 更加簡單,學習成本更低。

clickhouse 集羣規劃

  1. 數據規模和實時性:包括數據量、數據寫入頻率以及實時性要求。

  2. 查詢負載和性能需求:包括查詢負載、查詢複雜度、查詢頻率、併發性以及對集羣性能的需求。

  3. 集羣管理和維護:包括集羣的可靠性、容錯性、監控和維護等方面。

表結構設計要點

  1. 重視字段索引創建:將公共約定的常用名稱獨立成字段,方便添加索引,提升查詢效率。

  2. 合理選擇分區字段:根據業務實際場景,靈活定製設置分區鍵,針對性優化提高性能。

  3. 合併樹引擎與排序字段:選用合適的合併樹引擎 如 MergeTree,排序字段儘可能是查詢的字段,充分利用主鍵索引。

  4. 選擇合適的壓縮算法:更強悍的壓縮算法,往往需要犧牲一定的性能爲代價。經測試,LZ4 查詢響應要比 ZSTD 快 30% 左右,而 LZ4 的磁盤佔用空間要比 ZSTD 多 2.5 倍左右。如果使用 LZ4 查詢耗時爲 1 秒,而 ZSTD 查詢性能爲 1.5 秒左右,雖然秒級的影響對使用方來說,體感並不明顯,但高達 2.5 倍的存儲開銷確耗費不少。選擇合適的壓縮算法可以在保證查詢性能的情況下,降低存儲開銷。

創建 clickhouse 分佈式表

# 創建本地表
CREATE TABLE [IF NOT EXISTS] [db.]local_table_name ON CLUSTER cluster
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
    INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
    INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = engine_name()
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...];
# 創建分佈式表:
CREATE TABLE  [db.]d_table_name ON CLUSTER cluster
 AS db.local_table_name ENGINE = Distributed(cluster, db, local_table_name [, sharding_key])

可視化分析平臺

在升級日誌架構的過程中,很多用戶反應希望能夠延續之前的日誌使用方式,儘量減少遷移學習的成本。爲了後續的定製的需求以及後續的擴展,最終決定自研日誌可視化查詢分析平臺。

目前的日誌平臺實現了查詢語句高亮和提示、日誌時間分佈預覽、查詢高亮以及日誌略縮展示等等。

監控與告警

ClickHouse 提供了豐富的性能監控數據,包括查詢的執行時間、內存使用情況、磁盤使用情況、連接數等等。與 Prometheus 進行集成,可以將 ClickHouse 的監控數據暴露給 Prometheus,再使用 Grafana 等工具進行可視化展示和分析。

成果

ClickHouse 日誌系統對接了 服務端日誌、Nginx 日誌等,與原有 elk 架構相比,日誌方面的總成本減少了 60%,多存儲了 30% 的日誌量

後續規劃

ClickHouse 的確是一個強大的分析引擎
總體來說 ClickHouse 的運維比 ES 簡單,主要包括以下幾個方面的工作:

1)新日誌的接入、性能優化;
2)過期日誌的清理,按 TTL 自動清理
3)ClickHouse 的監控,使用 prometheus+Grafana 的實現;
4)數據遷移,一般不搬遷歷史數據,只要將新的數據接入新集羣,隨着時間的推移,歷史數據會被清理下線,當老集羣數據全部下線後,新老集羣的遷移就完成了。確實需要遷移數據時,採用 ClickHouse_copier 或者複製數據的方式實現。
5)常見問題處理:
慢查詢,通過 kill query 終止慢查詢的執行,並通過前面提到的優化方案進行優化
Too many parts 異常:Too many parts 異常是由於寫入的 part 過多 part 的 merge 速度跟不上產生的速度,導致 part 過多的原因主要包括幾個方面:
a. 設置不合理
b. 小批量、高頻次寫 ClickHouse
c. 寫的是 ClickHouse 的分佈式表
d. ClickHouse 設置的 merge 線程數太少了

總結

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/WdKlJVIAhiuPezcNzqKzcQ