

日誌資料已成為企業洞察系統狀態、監控網路安全及分析業務動態的寶貴資源。網易雲音樂引入 Apache Doris 作為日誌庫新方案,替換了 ClickHouse。目前已經穩定執行 3 個季度,規模達到 50 臺伺服器,2PB 資料,每天新增日誌量超過萬億條,峰值寫入吞吐 6GB/s 。
網易雲音樂每天都會產生大量使用者行為資料、業務資料及日誌資料,這些資料在異常行為跟蹤、客訴問題定位、執行狀態監控、效能最佳化等方面扮演守護者的角色。面對每日萬億級別資料的增量,網易雲音樂早期的日誌庫以 ClickHouse 為核心構建,但面臨運維成本高、併發查詢能力不足、寫入效能不穩定、使用費用高昂等問題,在新需求的滿足上稍顯吃力。
為尋找更優質解決方案,結合當前的業務需求,網易雲音樂引入 Apache Doris 作為日誌庫新方案,替換了 ClickHouse。目前已經穩定執行 3 個季度,規模達到 50 臺伺服器,2PB 資料,每天新增日誌量超過萬億條,峰值寫入吞吐達 6GB/s。本文將介紹從 ClickHouse 到 Apache Doris 的遷移思考及調優實踐,並分享網易雲音樂如何在運維效率、併發能力、查詢響應以及儲存效能上實現全方位提升。
雲音樂資料平臺主要包括客戶端日誌、服務端日誌、資料平臺相關元件執行日誌這幾類:
-
客戶端 / 服務端日誌:客戶端 / 服務端產生的日誌是資料體系的核心基礎資料之一,日增資料達萬億級別,儲存佔用數百 TB。幾乎所有業務場景均由該類資料構建。
-
資料平臺相關元件執行日誌:任務及相關元件日誌是資料平臺內部的核心資料之一,每天約 1TB 的資料規模。這些日誌能夠及時反映資料平臺的執行狀態、效能指標、異常情況等,是實現平臺智慧化運維的核心資產。
對於上述日誌資料的處理,早期以 ClickHouse 為核心構建了日誌庫、並設計瞭如下兩條資料處理鏈路。這些資料透過日誌採集、清洗、加工後寫入日誌庫中,由日誌庫進行明細和聚合查詢,為異常使用者行為、社群熱點監控、任務異常分析、任務預警、大盤監控業務場景提供服務。

客戶端 / 服務端日誌處理鏈路

資料平臺相關元件執行日誌處理鏈路
上述兩類日誌資料,均要求在即時任務加工處理後寫入到日誌庫,這對日誌庫的穩定性、可用性、效能、容錯等能力都提出了較高要求。而之前日誌庫以 ClickHouse 為核心構建,在使用中暴露出一些痛點問題,在效能及穩定性的滿足上稍顯吃力:
-
運維成本高:早期為兩條處理鏈路,同時也帶來了雙倍維護成本,此外,早期鏈路在面對壞盤、宕機、擴容等場景時,需要手動進行資料均衡和資料恢復,有些場景甚至需要在寫入任務時配合重啟操作。
-
使用門檻高:ClickHouse 除了有基本的本地表和和分散式表概念外,還提供了 MergeTree/ReplacingMergeTree/SummingMergeTree 等多個引擎,需根據不同情況選擇不同的引擎,比如多副本需要使用 ReplicatedXX 引擎,這對於新人而言使用門檻及成本均比較高。
-
併發查詢能力不足:在併發查詢較多場景下,查詢效能下降明顯,無法支援業務需求。
-
寫入穩定性較差:當單節點宕機或壞盤時,寫入任務會出現 Failover,個別場景還需要人工介入對寫入任務進行重啟。
-
收費較高:由於歷史原因,ClickHouse 使用的相關雲服務,成本高昂。
基於上述問題、技術棧痛點,結合當前的業務需求,網易雲音樂最終選擇 Doris 作為日誌庫的新方案,替換原先架構中的 ClickHouse。Apache Doris 具備運維便捷、高併發能力優異、大規模資料寫入效能穩定等特點,非常符合選型要求。不僅如此,Apache Doris 所提供的冷熱儲存以及資料湖能力也與後續重點技術發展方向高度契合。
-
簡單易用運維難度低:工程師和資料分析師對於 SQL 非常熟悉,經驗可以複用,不需要學習新的技術棧即可快速上手。同時 Doris 具備完善的分散式叢集管理,叢集本身易於運維、支援橫向拓展的儲存方案。
-
高吞吐、低延遲日誌寫入:支援每天百 TB 級、GB/s 級日誌資料持續穩定寫入,同時保持延遲 1s 以內,確保資料的即時性和高效性。
-
高效能日誌全文檢索分析:支援倒排索引和全文檢索,對於日誌場景中常見的查詢(如關鍵詞檢索明細、趨勢分析等)能夠實現秒級響應,為使用者提供極致的查詢體驗。
-
海量日誌資料低成本儲存:支援 PB 級海量資料的儲存,並支援將冷資料儲存到 S3 或 HDFS 等低成本儲存介質,儲存成本進一步降低。
開放、易用的上下游生態:上游透過 Stream Load 通用 HTTP API 對接常見的日誌採集系統和資料來源 Logstash、Filebeat、Fluentbit、Kafka 等,下游透過標準 MySQL 協議和語法對接各種視覺化分析 UI,比如可觀測性 Grafana、BI 分析 Superset、類 Kibana 的日誌檢索 SelectDB WebUI ,為使用者打造全方位的日誌儲存與分析生態。
由於 ClickHouse 和 Doris 均採用關係資料庫模型及 SQL,因此架構變化很小、遷移也比較簡單。在新架構中,使用 Apache Doris 替代 ClickHouse 作為日誌儲存和分析引擎。只需調整上游 Flink 寫入程式,將日誌寫入 Doris,並更新下游日誌查詢的 SQL 語句即可。

在實際上線過程中,網易雲音樂進行了 Doris 和 ClickHouse 為期兩週的雙跑測試。在此期間,針對最近兩週的資料進行了記錄數、使用者等欄位的統計,以及實際明細查詢的抽樣對比,以驗證資料的一致性。經過校驗,Doris 能夠安全地替代原有的 ClickHouse。
表結構設計是日誌平臺的關鍵因素,其中排序、分割槽、分桶、壓縮、索引等設計將對性產生顯著影響。
-
分割槽:基於 dt 欄位按天分割槽,使用 Dynamic Partition 功能自動建立和刪除分割槽。
-
分桶:採用 RANDOM 隨機分桶,既保證了各分桶的資料均衡,也能大幅提升寫入效能。
-
排序:使用 application_id、log_type、container_id、logs_timestamp、log_level、host_name 作為排序鍵。這是由於大多數查詢會指定 application_id、log_type、container_id,排序後能快速定位到所需資料,跳過不必要的資料。
-
索引:對需要全文檢索的日誌文字欄位 message 和 exception_message 建立倒排索引,加速關鍵詞檢索。
-
壓縮:採用 Doris ZSTD 壓縮演算法,相比 ClickHouse 預設的 LZ4 壓縮演算法,能夠節省 30% 以上的儲存空間。
-
Compaction:因為日誌也是一種特殊的時序資料,因此採用 time_series compaction 策略,利用時序資料區域性性特點減少 Compaction 寫放大,節省 CPU 和 IO 資源。
具體的建表語句參考如下:
CREATETABLE log_table (
application_id VARCHAR(*) NULLCOMMENT'應用id',
log_type VARCHAR(*) NULLCOMMENT'日誌型別/jm/tm',
container_id VARCHAR(*) NULLCOMMENT'container_id',
logs_timestamp BIGINTNULLCOMMENT'日誌產生時間',
log_level VARCHAR(*) NULLCOMMENT'日誌級別',
host_name VARCHAR(*) NULLCOMMENT'主機名',
exception_log TEXTNULLCOMMENT'異常日誌',
job_id INTNULLCOMMENT'任務id',
message TEXTNULLCOMMENT'日誌內容',
tag TEXTNULLCOMMENT'日誌關鍵指標',
log_file_path TEXTNULLCOMMENT'日誌儲存路徑',
exception_class_name TEXTNULLCOMMENT'異常類名',
exception_type TEXTNULLCOMMENT'異常型別',
exception_message TEXTNULLCOMMENT'異常msg',
exception_caused_by TEXTNULLCOMMENT'異常caused_by',
dt dateNULLCOMMENT'天',
hh TEXTNULLCOMMENT'小時',
mm TEXTNULLCOMMENT'分鐘',
INDEX idx_exception_message (exception_message) USING INVERTED PROPERTIES("parser" = "english"),
INDEX idx_message (message) USING INVERTED PROPERTIES("parser" = "english")
) ENGINE=OLAP
DUPLICATEKEY(application_id, log_type, container_id, logs_timestamp, log_level, host_name)
COMMENT'OLAP'
PARTITIONBYRANGE(dt)()
DISTRIBUTEDBY RANDOM BUCKETS 100
PROPERTIES (
"dynamic_partition.enable" = "true",
"dynamic_partition.time_unit" = "DAY",
"dynamic_partition.start" = "-7",
"dynamic_partition.end" = "3",
"dynamic_partition.prefix" = "p",
"dynamic_partition.buckets" = "100",
"dynamic_partition.create_history_partition" = "true",
"compression" = "ZSTD",
"compaction_policy" = "time_series");
原來架構中,日誌資料透過 Flink 寫入 ClickHouse。新的架構中,由於 Doris 提供了 Doris Flink Connector,仍然可以沿用 Flink 來寫資料,只需要進行少量調整。

目前使用 Apache Flink 1.12 版本,Doris Flink Connector 使用的是 branch-for-flink-before-1.13 分支。寫入流程如下圖:每條上游資料寫入 ArrayList 中,當 ArrayList 中資料的條數 sink.batch.size 或大小 sink.batch.bytes 達到閾值後,觸發 flush 操作,同時還會啟動 daemon 執行緒,定時 sink.batch.interval 做 flush 操作。在 flush 操作中,會將 ArrayList 中的資料按 JSON 或 CSV 的方式序列化為 String 格式,如果開啟壓縮 compress_type(只有 csv 格式支援 gz 壓縮),可將 String 序列化為壓縮後的位元組陣列,最後將資料透過 StreamLoad 的方式寫入到 BE 節點。基於該寫入流程,網易雲音樂進行了穩定性及效能壓測,在壓測過程中,發現幾個問題:
-
預設 batch size 太小,會導致吞吐量較低,資料延遲問題嚴重;而如果將 batch size 設定太高(500MB 等),又會導致 Flink TM 端 OOM。
-
寫入 tablet 太多時,元資料產生也較多,不僅影響寫入效能,還可能出現 txn 數超限等問題。
-
Flink 的 subTask 在初始化後,所寫入的 BE 是確定的,除非產生異常需要重新選擇 BE,否則不會主動變更 BE,這就導致 BE 間負載不均衡。
-
BE 在進行滾動變更重啟時,Flink 任務會失敗。
-
監控指標缺失,無法量化客戶端各階段耗時。
基於上述問題,網易雲音樂進行了如下最佳化:
在 append 資料操作時,直接寫入壓縮流,無需經過 ArrayList 中轉。這種方式可大幅降低記憶體的使用,相比之前,TM 記憶體的佔用從 8G -> 4G。
開啟單 tablet 匯入功能(要求表必須使用 random bucket 策略),可極大提升寫入效能。
每個 batch flush 完成後,隨機選擇一個 BE 節點寫入資料,解決 BE 寫入不均衡問題,相較之前匯入效能有 70% 的提升。(效果見下圖 ,4/30 起為最佳化後資料)。
調整 failover 策略,同時最佳化重試邏輯,並增加每次重試的時間間隔,提高系統容錯能力。
新增客戶端全鏈路監控指標,監測 addBatch/ 壓縮 /flush/ 傳送等各階段耗時,可快速定位主要耗時過程。

Flink 寫入 Doris 任務偶爾會出現延遲告警,查詢日誌發現 Stream Load 耗時從 5s 突增到 35s 左右。透過 Doris 大盤監控發現 Be Alive 指標抖動嚴重,接著透過 FE 的日誌 grep "finished to handle tablet report from backend" log/fe.log | tail -n 100 檢視 FE 處理 BE 心跳耗時情況,發現處理 BE 的耗時超 20s。
透過分析 FE 處理 BE 心跳的各步驟,發現大部分處理邏輯都是非同步的,只有同步 tablet 元資料的邏輯是同步的。我們透過 grep "tablets in db" log/fe.log | tail -n 100 檢視相關耗時日誌,發現該階段耗時超 20s,基本可確定是在同步元資料階段出現的嚴重耗時。

進一步的,透過 jstack 列印 FE 的執行緒棧,可發現 ReportHandler 在處理心跳時,只有 sync meta 一個地方是同步的,正在等待鎖、獲取鎖的邏輯是 flush 元資料。同時,FE 磁碟的 ioutil 達到 50% 以上。因此,基本確定問題是由於刷元資料導致效能降低。
在查閱原始碼和 bdbje 資料庫的最佳化措施後,決定對 3 臺 Follower FE 調整為非同步刷盤:master_sync_policy=WRITE_NO_SYNC 和 replica_sync_policy=WRITE_NO_SYNC,最終實現 4 倍效能的提升

FE IO Util 最佳化 – 最佳化前後對比

Stream Load 耗時 – 最佳化前後對比
由於 ClickHouse 和 Doris 都支援 SQL,查詢的變化不大,主要區別在於,Doris 支援倒排索引和全文檢索的函式,可用全文檢索代替 LIKE 字串匹配。
select logs_timestamp,message from log_table
where dt>= '2024-07-29'
and application_id='sloth-f52a7cda-50f8-4092-b6e7-6c9d8ce82c7b'
and log_type='jobmanager'
and container_id='sloth-f52a7cda-50f8-4092-b6e7-6c9d8ce82c7b-6457b684bf-vcrjb'
and logs_timestamp>=1722241811000and logs_timestamp < 1722241819000
orderby logs_timestamp desclimit500offset0;
全文檢索的查詢,message MATCH_ANY 'Exception Failed' 匹配 Exception 或者 Failed 關鍵詞。
-- match 全文檢索查詢:
SELECT logs_timestamp,message FROM log_table
WHERE dt>= '2024-07-29'
and application_id='sloth-f52a7cda-50f8-4092-b6e7-6c9d8ce82c7b'
and log_type='jobmanager'
and container_id='sloth-f52a7cda-50f8-4092-b6e7-6c9d8ce82c7b-6457b684bf-vcrjb'
and message MATCH_ANY 'Exception Failed'
and logs_timestamp>=1722241811000
and logs_timestamp < 1722241819000
orderby logs_timestamp desclimit500offset0
-- like 模糊匹配查詢:
message LIKE'%Exception%'OR message LIKE'%Failed%'
隨著匯入任務的不斷增多,系統在高峰期開始出現了延遲。透過監控發現,個別 BE 的出入流量遠高於其他 BE,進一步分析指令碼得知,是由於當天分割槽的 tablet 在 BE 之間分佈不均衡導致。
為解決這一問題,網易雲音樂決定改用 Partition 策略 tablet_rebalancer_type=partition。該策略可將每天的分割槽 tablet 均勻分佈到各 BE 上,避免區域性負載過高的問題。這也要求寫入任務必須保證資料在單分割槽內的 bucket 是均勻分佈的,而當前的日誌場景正好滿足這一要求。下圖為最佳化後資料(6 月 11 日在進行滾動變更,抖動較為嚴重,6 月 13 日後為穩定資料):

重度不均衡
從下圖可以看出,個別 BE 的 Compaction Score 非常高,同時這些 BE 的某些磁碟 I/O 利用率持續保持在 100%。與社群同學交流後得知,這主要是由於 BE 磁碟選擇策略與 trash 清理機制之間的相互影響所致。
具體來說,儘管 BE 選擇磁碟的策略是 round-robin,但當磁碟空間使用率超過 80% 時,系統會強制觸發 trash 清理機制,這會導致某些磁碟的使用率急劇下降,從而使新的 tablet 更多地被分配到這些“低負載”磁碟上,導致這些磁碟負載持續升高。

進一步的,透過 BE 提供的查詢 tablet 分佈 OpenAPI,發現該 BE 上大流量表當天分割槽的 tablet 分佈情況如下圖所示,存在磁碟之間不均衡問題。

透過調整以下引數,來解決該問題:
-
trash_file_expire_time_sec = 0:關閉 trash,日誌場景中每天資料量級非常大,且 trash 恢復比較困難,沒有必要使用 trash。
-
high_disk_avail_level_diff_usages = 0.8:BE 選擇磁碟時,先根據磁碟的空間使用率劃分級別,每個級別使用 round-robin 的方式分配,提升分級別的引數,可以將使用率高和低的盤強制放在一個級別中(風險提示:如果不確定是 trash 導致,可能存在個別盤打滿的風險)
輕度不均衡
壓測過程中,還發現存在輕度磁碟不均衡問題。這是由於 FE 的 balancer 機制,會選擇 BE 磁碟使用率最小的 disk 進行遷移,從而導致存在部分不均衡問題。可暫時透過設定引數 disable_balance=false 關閉 balancer 解決此問題。
在落地過程中,運維方面主要進行以下三方向的建設:
-
可觀測性:基於社群提供的的 Grafana 監控模版,對相關指標進行完善,構建了全面的可觀測體系,實現對叢集執行狀況、關鍵指標的即時監控與分析。
-
自動化運維:依託內部的運維平臺,構建了自動化告警、自動拉起、問題處理等邏輯。當系統出現異常時,系統可自動檢測並採取相關措施,極大減輕了運維人員的工作負擔。
-
自動化均衡:採取了自動化探測 tablet 磁碟是否分配均衡的策略,並針對不均衡的情況進行自動化遷移。這一能力確保了叢集在擴容或停機維護時,能夠自動達到最佳的負載均衡狀態。
透過這三個方向的建設,進一步強化了 Doris 在運維層面的自動化和智慧化能力,極大提升了整體的運維效率和可靠性。這不僅大幅減輕了運維人員的工作負擔,也為系統穩定執行提供了有力保障。
網易雲音樂使用 Apache Doris 替換 ClickHouse 構建了新的日誌平臺,已經穩定執行三個季度,規模達到 50 臺伺服器、2PB 資料量。這次架構升級帶來查詢響應、併發能力、穩定性和運維效率等多方面可觀的收益。
-
查詢響應提升:整體 P99 查詢延遲降低了 30%。特別是透過倒排索引加速,Doris 的全文檢索 MATCH 查詢效能比 LIKE 查詢提升了 3-7 倍(在查詢約 6TB 資料時,LIKE 查詢耗時 7-9 秒,而 MATCH 查詢僅需 1-3 秒)。此外,倒排索引的全文檢索具備自動的大小寫和單複數歸一化能力,能夠高效檢索出更多相關日誌。
-
查詢併發提升:ClickHouse 併發查詢數超過 200 時就會經常出現 Too many simultaneous queries 錯誤,而 Apache Doris 能夠支撐 500+ 併發查詢。Doris 還可以對單次查詢的資料量和併發數進行調整,以靈活應對不同場景下的併發要求。
-
寫入穩定性提升:FE / BE 發生單點故障時,都能自動感知和重試恢復,保證服務高可用。
-
運維成本降低:在壞盤和宕機場景下,Doris 的自恢復能力結合程序自動拉起指令碼,降低人工干預的運維成本。擴容或停機維護場景下,Doris 的自動均衡能力很強,擴容後隨著 tablet 的自動均衡和老資料的清理,叢集會自動達到均衡狀態。
此外,網易雲音樂在技術能力上也有良好的積累,積極與 Doris 社群同學深入溝通、解決關鍵性問題,同時也積極向社群提交相關 Issue 和 PR,共同推動 Doris 社群的建設與發展。
當前,網易雲音樂內部所應用 Doris 叢集已達 100 餘臺(包括日誌儲存和其他資料分析場景),後續還將在更多場景中推廣落地。未來還將著重從以下幾方面發力:
利用 Doris 冷熱分層儲存等能力,在提高查詢效能的同時進一步降低成本。
使用 Doris Workload Group 能力,進行相關資源隔離,提升叢集穩定,按優先順序保障業務使用。
增加線上查詢等更多應用場景,Doris 出色的併發查詢能力將為這些場景提供強有力的支援。
Doris 的資料湖擴充套件能力也是網易雲音樂非常看重的能力,這為規劃中的 One-SQL 資料架構奠定了堅實基礎。
