壓測平臺 - 記錄一次百億級資料查詢最佳化

varqiao發表於2024-11-14

引言

為了支撐數十萬 tps 的穩定性壓測,,我們的壓測平臺對壓測資料查詢進行了最佳化,以提高整體測試效率和響應能力。這些最佳化措施確保平臺能夠在大流量場景下高效穩定地執行,從而為產品的效能和穩定性提供更有力的保障。

16w 左右 tps 的 7*24 小時壓測

問題分析

1.壓測資料無法載入

在壓測平臺中,InfluxDB 被用於儲存和查詢壓測資料。然而,由於當時的 InfluxDB 資料庫採用的是單體架構,未進行任何分片或分散式部署。隨著系統中的資料量逐步增大,資料庫逐漸暴露出效能瓶頸,尤其是在處理大規模的壓測資料和歷史資料載入時。

壓測資料無法載入的情況

2.歷史資料載入緩慢

在訪問歷史資料時,由於資料量龐大,InfluxDB 的查詢效率下降明顯。載入歷史資料所需的時間變得過長,使用者體驗極差,查詢往往需要等待數秒甚至數分鐘才能完成,嚴重影響了系統的可用性和使用者滿意度。

3.資源利用率過高

單體架構的 InfluxDB 承擔了所有的讀寫操作,導致日常查詢和寫入的負載極高,難以有效分擔壓力。資料庫伺服器的 CPU 使用率常年保持在 75% 以上,系統壓力大時甚至接近滿負荷,導致 CPU 無法為查詢提供充足的資源支援。此外,資料庫的記憶體經常性地被佔滿,進一步影響了資料查詢的效能。

切換社群版 InfluxDB 的叢集版後遇到的新問題

為了緩解單體架構的效能瓶頸,我們嘗試切換到 InfluxDB 的叢集版本,以便在分散式架構下處理更大的資料量。初期切換後,系統的負載確實有所緩解,一些效能問題得到了改善。然而,在執行約半個月後,新的問題開始顯現:

高 IO 讀操作

在沒有任何查詢操作的情況下,系統的 IO 讀負載持續偏高。經過詳細排查,發現這種高 IO 讀並非由使用者查詢引起,而是在資料寫入時觸發的。這樣的現象導致了系統儲存裝置的高頻讀操作,增加了硬體的負載,並降低了整體系統的穩定性。

資料壓縮導致的 IO 讀壓力

經過分析和閱讀 InfluxDB 的程式碼,發現問題的根源在於 InfluxDB 在進行資料寫入時,觸發了自動的資料壓縮機制。這個壓縮機制在檢測到記憶體索引達到壓縮閾值時,會執行一次資料壓縮操作。資料壓縮的過程需要遍歷索引,這種操作會頻繁地進行大量磁碟 IO 讀取,加重了系統的讀負載。

pprof 分析

influxdb 出問題的程式碼塊

社群支援有限

由於 InfluxDB 的社群版叢集是由社群維護,在發現高 IO 讀負載問題後,我們嘗試向社群尋求支援。然而,由於社群支援有限,未能找到有效的解決方案,問題持續影響系統效能,並可能導致資料載入變慢或讀寫操作卡頓。

決策與解決方案

在社群支援無果的情況下,為了保證系統的穩定性和高效性,我們最終決定 切換底層儲存資料庫,選擇一個能夠更好處理海量資料寫入和壓縮任務的資料庫方案。這個決策的目的是找到一種能夠提供穩定、高效的儲存和查詢功能的底層資料庫,從而支援系統長期的高併發寫入和查詢需求,避免因單點儲存效能限制帶來的瓶頸問題。

新部署架構設計

最佳化前架構梳理

最佳化前的系統架構如下:壓測代理(agent)將壓測資料寫入 Kafka,資料中心從 Kafka 中獲取資料並按每秒進行聚合處理,隨後將結果寫入 InfluxDB。我們利用 InfluxDB 的持續查詢功能,每分鐘將詳細資料轉存至 1 分鐘間隔的聚合資料表,從而將資料壓縮至原始量的 50% 左右。

雖然該架構在設計上無明顯缺陷,但由於 InfluxDB 的開源版本僅支援單機部署,無法進行分散式擴充套件,因此在短時間內出現大批次資料寫入和查詢請求時會遇到效能瓶頸。為確保系統能夠支撐 15-17 萬 TPS 的壓測需求,我們決定更換底層的儲存資料庫,以支援更高的併發處理能力和更穩定的效能表現。

最佳化後核心部署架構

新的部署架構將原儲存於 InfluxDB 的資料遷移至 ClickHouse 資料庫,以充分利用 ClickHouse 多節點計算的優勢。壓測資料通常按列聚合計算,而 ClickHouse 作為列式資料庫非常適合這一需求。

由於 ClickHouse 沒有類似 InfluxDB 的持續查詢功能,我們開發了一個自定義的 watch 服務,用於每 30 秒自動聚合並轉存原始資料至新的 30 秒維度的表中。考慮到資料隨著時間的推移查詢頻率逐漸降低,我們計劃將超過 30 天的資料轉存為冷資料至磁碟,以降低頻繁讀寫對磁碟的壓力。

Grafana 實時讀取 30 秒維度的分散式表,以近實時方式展示壓測資料,此時資料大約有 1 分鐘延遲,但在效能測試中這一延遲可忽略不計。透過這種架構最佳化,ClickHouse 可以高效地執行資料聚合計算,並實現靈活的歷史資料管理,顯著提升了系統的效能和可擴充套件性。

watch 服務架構

watch 服務啟動時,會從 Redis 中讀取一個 startTime 作為初始查詢時間,並將當前時間 now 作為 endTime,在 ClickHouse 中執行相應的查詢和聚合操作。

在查詢和寫入操作完成後,watch 服務將 now 更新到 Redis 中的 startTime,實現查詢時間視窗的動態滾動更新。這種設計確保 watch 服務始終在正確的時間視窗內執行資料查詢和聚合操作,從而實現資料的持續更新和處理。

透過這種滾動更新機制,系統能夠高效管理資料的時效性,確保資料處理的連續性與一致性,同時有效提升了整體系統的穩定性和可靠性。

成果

透過資料轉存與聚合,本專案成功地將原有的 178 億條資料壓縮至 181 萬條,顯著改善了系統效能和資源利用情況。具體成果如下:

  1. 查詢效率顯著提升
    資料聚合後,查詢的響應速度提高了數倍。由於資料量的減少,系統可以更快速地定位所需資訊,查詢平均響應時間從原來的數秒縮短至毫秒級別,為使用者提供了更流暢的體驗。這一提升在高頻查詢場景下尤為明顯,減輕了伺服器的查詢負擔,使系統在高峰期也能保持穩定的效能。

儲存成本降低

聚合資料後的儲存需求大幅下降,原本需要高儲存容量的 178 億條記錄被壓縮為 181 萬條,大大減少了對儲存空間的需求。這一變化帶來了顯著的成本節省,不僅降低了儲存硬體的開銷,還減少了備份、傳輸和維護資料的時間和成本。

系統資源最佳化

資料量減少後,CPU 和記憶體的佔用也顯著降低,系統資源得到了更加高效的利用。由於減少了處理冗餘資料的負擔,伺服器的整體效能得到提升,可以處理更多併發任務。此外,這種資源最佳化還延長了系統硬體的使用壽命,進一步節約了成本。

可擴充套件性提升

透過資料聚合,系統的可擴充套件性得到提升。在資料規模更大、資料增長更快的情況下,聚合策略能確保系統效能穩定,幫助應對未來的資料擴充套件需求,為系統長遠發展奠定了基礎。

相關文章