Jerry 是一家位於北美的科技公司,利用人工智慧和機器學習技術,簡化汽車保險和貸款的比價和購買流程。在美國,Jerry 的應用在其所屬領域排名第一。
隨著資料規模的增長,Jerry 在使用 AWS Redshift 時遇到了一些效能與成本的挑戰。Jerry 重新設計了系統架構,使用 ClickHouse 後,資料查詢效能提升了 20 倍,並大幅降低了成本。但在使用過程中也遇到了磁碟損壞和資料恢復等諸多儲存挑戰。作為初創公司,Jerry 希望避免對 ClickHouse 叢集進行大量的維護工作。
於是,Jerry 採納了 JuiceFS, 並創新性地使用其快照功能實現了 ClickHouse 主從架構。這一架構不僅確保了資料的高可用性和穩定性,還顯著提高了系統的效能和資料恢復能力。在超過一年的時間裡無停機和無複製錯誤,並提供了可預期的效能。
01 Jerry 資料架構:從 Redshift 到 ClickHouse
起初,我們很自然地選擇使用 Redshift 來滿足分析查詢的需求。然而,隨著資料量的急劇增長,我們開始遭遇嚴重的效能和成本挑戰。例如,在生成漏斗和 AB 測試報表時,我們面臨著長達數十分鐘的載入等待時間。即便在規模合理的 Redshift 叢集上,這些操作也耗時過長,導致資料服務一度陷入不可用狀態。
我們需要一個更快、更經濟的解決方案,並且我們可以接受其不支援實時的更新和刪除操作的特性。基於這些條件,在三四年前的時間背景下,ClickHouse 成為了我們的首選。隨後,我們成功切換到 ClickHouse,並引入了全新的資料倉儲設計,最終取得的成果如下:
重要報表的載入時間從原先的十幾分鍾到幾十分鐘大幅縮短至幾秒,顯著提升了資料處理的效率。我們的總成本降低至原來的四分之一,甚至更低。這一變革讓我們的團隊以及其他相關部門倍感欣喜,因為他們現在能夠更高效地工作,迭代速度更快,且能夠編寫直觀的 SQL 查詢。對於 Jerry 而言,是一次巨大的成功。
Jerry 目前採用的架構以 ClickHouse 為核心,輔以 Snowflake。在大部分場景下,即 99% 的資料應用場景中,都依賴 ClickHouse 的高效處理能力。當面臨 ClickHouse 無法處理的 1%的資料任務時,我們採取將資料轉移至 Snowflake 進行處理的策略。我們做了一些工作以確保使用者平滑地在 ClickHouse 與 Snowflake 之間進行資料交換。
02 ClickHouse 部署方式與挑戰
我們預計在較長一段時間內維持單機狀態。在決定採用此種方法前,我們審慎地評估了單機部署的可持續性,並非僅著眼於眼前的部署需求,而是基於對未來幾年內是否適合我們方案的長期考量。
-
首要考慮因素是效能。在同等計算資源條件下,由於避免了叢集的開銷,單機部署表現出色,這也符合官方的推薦。我們可以堅持採用單機部署,直至其無法滿足業務需求。
-
另一重要原因在於單機部署對我們而言具有最低的維護成本。這不僅涵蓋了整合維護成本,還涉及應用資料設定以及應用層暴露的維護成本。
-
我們發現目前的硬體條件已經可以支援很大規模的單機 ClickHouse。例如,現在我們可以在 AWS上 買到 24TB 記憶體和 488 個 vCPU 的 EC2 例項,這個規模比很多投入部署的 ClickHouse 叢集都大,使用最新的硬體技術,硬碟頻寬也能達到我們設想的規劃容量。
因此,從記憶體、CPU 和儲存頻寬等角度考慮,單機 ClickHouse 是一個可行的方案,預計在可預見的未來將繼續有效。
當然,ClickHouse 方案亦存在其固有的問題。
-
首先,當遭遇硬體故障時,ClickHouse 的當機時間相對較長,這對業務的連續性和穩定性構成了威脅。
-
其次,資料遷移和備份在 ClickHouse 中至今仍是一項具有挑戰性的任務,實現良好的資料備份和遷移方案尚顯困難。
在我們部署該專案後,還遇到了一些問題。
首要問題是常規的儲存擴充套件和維護需求,由於資料量迅猛增長,保持合理的磁碟利用率變得尤為重要,每次操作都需要我們投入大量精力。
另一問題則是由磁碟故障引發的一系列連鎖反應。ClickHouse 被設計為瘋狂使用硬體資源以提供最好的查詢效能,它對磁碟的讀寫操作非常頻繁,經常接近最高頻寬,這就帶來更大的硬碟硬體故障的可能性。當發生硬體故障的時候,根據資料量的大小,故障恢復通常需要幾小時到十幾小時,我們也在一些使用者中聽到了類似的情況。雖然資料分析系統通常被看作是其他系統的資料副本,但這帶來的影響還是非常大的。因此,我們必須對可能出現的硬體故障做好充分準備,而資料備份、恢復和遷移等任務也極具挑戰性,需要我們投入更多的精力和資源來應對。
03 在 JuiceFS 上執行 ClickHouse
因此,我們萌生了一個思路,即考慮將 ClickHouse 遷移到基於 JuiceFS 的共享儲存環境中執行。這篇文章當時給我提供了一些參考:ClickHouse 存算分離架構探索。
為了驗證此方案的可行性,我們進行了一系列測試。測試結果顯示,在啟用快取的情況下,JuiceFS 的讀取效能與本地硬碟的效能接近,與 JuiceFS 部落格中展示的結果相似。
寫入效能雖降至寫入磁碟速度的 10%至 50% ,但對於我們而言,這是一個可接受的範圍。
以下是我們對 JuiceFS 掛載進行了針對性的調優操作:
- 首先,我們啟用了 writrback 功能,以實現非同步寫入,從而避免潛在的阻塞問題。
- 其次,在快取設定方面,我們設定了 attrcacheto 為 3600.0 秒,cache-size 為 2300000,並啟用了 metacache 功能。
- 此外,針對 JuiceFS 上 IO 執行時間可能較長於本地磁碟的情況,我們調整了相應策略,引入了 block-interrupt 功能。
最主要的調優目標是提高快取命中率。由於我們使用的是 JuiceFS 雲服務版,我們成功將快取命中率提升至 95%。若仍需進一步提高,我們將考慮增加硬碟資源。
ClickHouse 結合 JuiceFS 的方案顯著減少了運維工作。我們不再需要頻繁進行硬碟擴充套件,而是著重監控快取命中率,從而大大減輕了擴充套件硬碟的緊迫性。其次,在硬體故障發生時,我們無需進行資料遷移,這極大地減少了潛在的風險和損失。
JuiceFS 快照(snapshot)功能提供了方便的資料備份與恢復手段,這對我們來說非常有價值。使用快照功能,我可以在未來某個時刻再次執行在資料快照上執行資料庫服務,以檢視其原始狀態,這在檔案系統層面上解決了以往需要在應用層面解決的問題。(社群版使用者使用克隆功能,實現類似功能,點選此處瞭解。)
此外,由於無需進行資料遷移,當機時間得到了大幅減少。我們能夠迅速應對故障,或者讓自動化系統在另一臺機器上掛載目錄,確保業務的連續性。值得一提的是,ClickHouse 的啟動時間僅需幾分鐘,這進一步提升了系統的故障恢復速度。
再者,我們的讀取效能在遷移後保持穩定,整個公司都未察覺到任何變化,這充分證明了該方案在效能方面的穩定性。
最後,我們的成本也得到了大幅下降。透過將昂貴的雲端儲存產品替換為廉價的物件儲存,我們實現了成本的最佳化,進一步提升了整體效益。
為何要搭建主從架構?
在遷移 ClickHouse 後,我們遇到了如下問題,這些問題最終促使我們考慮構建主從架構。
第一:資源競爭所引發的效能下降。在當前的 ClickHouse 使用方式中,我們把所有的任務都放在了這個架構中,當時 ETL 任務與報表任務之間時常發生衝突,影響了整體效能。
第二:硬體故障導致的當機問題。對於需要隨時檢視資料的公司而言,長期的當機是不可接受的。因此,我們考慮在現有基礎上尋找解決方案,從而引出了構建主從架構的構想。
JuiceFS 支援在不同地點掛載多個掛載點。於是我們嘗試在其他地方直接掛載 JuiceFS 檔案系統,並在相同位置執行 ClickHouse。然而,在實施過程中我們遇到了一些問題。
首先,ClickHouse 透過檔案鎖機制限制同一份檔案只能由一個例項執行,這確實帶來了一些挑戰。但幸運的是,這個問題相對容易解決,我們只需修改 ClickHouse 的原始碼並對其進行鎖定即可。
其次,即便在應用過程中僅進行只讀操作,ClickHouse 仍會保留一些狀態資訊,如寫入時的快取。
最後,後設資料同步也是一個問題。當 JuiceFS 上執行多個 ClickHouse 例項時,寫入例項的部分資料可能無法被其他例項感知,這需要我們重啟例項以解決問題。
這當然是不理想的,所以我們決定利用 JuiceFS snapshot 功能來實現主從架構。這個架構的使用方式與常規理解的主從架構並無顯著差異。所有的資料更新操作均發生在主例項上,包括資料同步和 ETL 等任務;而從例項則專注於為使用者提供查詢能力。
怎樣建立 ClickHouse 從例項?
-
使用 JuiceFS 的快照功能命令:從主例項的 ClickHouse 資料目錄建立出一個快照目錄,並在此目錄上部署一個 ClickHouse 服務。
-
暫停 Kafka 消費佇列:在啟動可用於 ClickHouse 的例項之前,必須確保停止對其他資料來源的有狀態內容的消費。對於我們而言,這意味著暫停 Kafka 訊息佇列的執行,以避免與主例項競爭 Kafka 資料。
-
在快照目錄上執行 ClickHouse: 啟動 ClickHouse 服務後,我們還將注入一些後設資料,以向訪問者提供關於 ClickHouse 建立時間等資訊。
-
刪除 ClickHouse data mutation:在從例項上刪除所有的 data mutation,這有助於提升系統效能。
-
如何進行連續複製:值得注意的是,快照僅保留建立時的狀態,為了讓“從例項”讀到最新的資料,我們定期重新建立副本例項,並替換原有例項。這種方法直觀且高效,每個副本例項都從兩個副本開始,並有一個指向某個副本的指標。我們可以根據時間間隔或特定條件來重新建立另一個副本,並將指標指向新建立的副本例項,從而無需停機更新。我們設定的最小時間間隔為 10 分鐘,通常每小時執行一次即可滿足需求。
ClickHouse 的主從架構已穩定執行超過一年,期間完成了超過 2 萬次的複製操作而未曾失敗,展現了其極高的可靠性。工作負載隔離和資料副本的穩定性是提升效能的關鍵。我們成功地將整體報表的可用性從不足 95% 提升至 99% ,而且這一提升無需任何應用層面的最佳化。此外,該架構支援彈性擴充套件,極大地增加了靈活性,使我們能夠根據需求隨時開發和部署新的 ClickHouse 服務,而無需額外的複雜操作。
未來展望
-
我們期望開發一個更為最佳化的控制介面,以實現自動化例項的生命週期管理、建立操作以及快取管理功能。
-
在執行主從架構的過程中,我們觀察到主例項在 JuiceFS 上相較於本地硬碟更易發生崩潰現象。儘管大多數情況下可以同步資料,並且同步的資料通常隨時可由其他副本訪問,但在處理失敗時仍需考慮這一特殊情況。儘管我們從概念和原則上對崩潰原因有所瞭解,但至今仍未完全解決這一問題。簡而言之,由於檔案系統上的 I/O 系統呼叫時間較本地硬碟更長,這些異常情況可能會傳導至其他元件,進而引發主例項的崩潰。
-
最佳化寫入效能。主要涉及兩個方面。首先,從應用層面來看,由於當前對 Parquet 開放格式的支援已經相當完善,因此,對於大部分負載,我們可以在 ClickHouse 之外將其直接寫入 JuiceFS,以便於訪問。這樣,我們可以採用傳統方式實現並行寫入,從而提高寫入效能。
-
我們注意到一個新專案 chDB,該專案允許使用者在 Python 環境中直接嵌入 ClickHouse 功能,無需 ClickHouse Server。結合 CHDB 和 JuiceFS 我們可以實現完全 serverless 的 ClickHouse。這是一個我們在探索的方向。
04 為什麼選擇 JuiceFS
第一個原因十分明確,JuiceFS 在當時是我們唯一可選的能在物件儲存上執行的 POSIX 檔案系統。
第二個原因在於其無限的容量特性。自我們使用以來,基本上無需再為容量問題而擔憂。
第三個原因則是其成本優勢顯著,相較於其他方案,JuiceFS 的成本大幅降低。
第四個令人稱道的功能是其強大的快照(snapshot) 能力。它巧妙地將 Git 分支的思維模型引入檔案系統層面,並正確、高效地實現了這一模型。當兩個不同層面的概念結合得如此完美時,往往能帶來極具創意的解決方案,使得之前需要付出巨大努力才能解決的問題變得輕而易舉。正如我們之前所面臨的主從架構問題,若在其他層面處理,無疑會是一個龐大的專案。
05 JuiceFS 在各場景的應用
資料交換:我們聚焦於 ClickHouse 的應用。利用其訪問共享儲存的特性進行資料交換,為我們提供了諸多有趣的場景。其中,將 JuiceFS 掛載在 JupyterHub 上尤為引人注目。一些資料科學家將資料輸出到特定目錄中,這使得在編寫報表時,我們可以用這個資料直接對所有 ClickHouse 中的表進行聯合查詢,極大地最佳化了整個工作流程。儘管許多工程師認為將資料同步寫入並不困難,但長期累積下來,若每日都能省去這一步驟,將極大地減輕心智負擔。
機器學習管線:在 JuiceFS 上儲存所有機器學習管線所需的資料,包括訓練資料等,JuiceFS 為我們打通工作流提供了便捷的途徑。透過這種方式,我們可以輕鬆地將訓練時的 notebook 輸出放置到指定位置,從而在 JupyterHub 上實現快速訪問,使得整個管線流暢無阻。
Kafka + JuiceFS:我們將 Kafka 儲存在 JuiceFS 上,儘管我們直接訪問 Kafka的應用場景並不多,但考慮到其作為資料資產的長期儲存價值,我們仍選擇採用這種方式。相較於使用 AWS 相應產品,我們透過這種方式保守估計節省了約 10-20 倍的成本。經過效能測試,我們發現單機效能有所下降,但是這個方案具備良好的水平擴充套件能力,可以透過新增節點獲得我們所需要的吞吐量。該方案的資訊延遲相較於本地儲存稍大,且存在某些不穩定問題,不適合用在需要實時流處理的場景。
最初,我作為個人使用者開始使用 JuiceFS, 在我看來,JuiceFS 的設計優雅、是一個能讓開發者的生活變得簡單的產品,這一點非常重要。當我在工作中引入 JuiceFS 時,它也總能把事情變得簡單。希望這篇文章能給創業型公司,或者大公司裡的小型業務,帶來有價值的參考。