—— 作者 | 縱行科技平臺開發團隊 ——
業務背景:自縱行科技在2020年推出ZETag云標簽以來廣受市場好評,目前已經在物流、資產管理、庫存盤點等領域有了許多落地項目。在業務量急速增加的過程中,ZETag云平臺作為解決方案中重要的一環,也面臨了許多挑戰與考驗。本文分享了在建設ZETag云平臺過程中,我們在架構設計方面的一些思路與實踐。
面臨的挑戰
1)設備量與數據量的快速增加
不同于傳統的物聯網終端,低成本ZETag云標簽更多用于物的定位與追蹤,同時,還有次拋等新的應用場景。因此,ZETag云標簽的數量遠遠大于傳統的物聯網終端,萬級別標簽每客戶將是業務常態,可以預估ZETag云平臺需要管理的標簽量將在百萬到千萬級,每天需要保存的上報數據將達到億級,這對平臺數據存儲的寫性能、擴展性以及存儲成本將是一個巨大的考驗。
2)如何在保留云上擴展性的同時,降低私有化部署的成本
物聯網行業是一個典型的B2B行業,私有化部署是很多對數據私密性較高要求的客戶的強需求,一個復雜的大數據平臺架構也許能夠滿足我們對性能、擴展性的需求,但是卻同樣有非常高的運維成本與設備成本,對于大部分成本敏感的中小長尾客戶來說,較高的實施運維成本是難以承受的,因此在離線部署私有云的場景,除了性能之外,整體架構的輕量化也是一個重要的考量因素。
3)如何支持實時靈活的多維分析,挖掘數據價值
ZETag云標簽業務大多涉及指標告警、實時追蹤、多維分析報表等,端到端的延遲需要控制在秒級別,同時也需要滿足客戶不同條件、維度、指標的實時統計與分析,因此對于數據的查詢延遲、靈活性都有比較高的要求。
技術選型
綜合來看,查的快、寫的快、成本低是我們三個比較核心的訴求。我們調研了業內常見的開源分布式OLAP數據庫,最終確定了 ClickHouse+MySQL 混合存儲的方式作為ZETag云平臺最終存儲方案。
其中,ClickHouse用于存儲網關、終端、標簽的事件數據,例如心跳、注冊等。同時,MySQL專注存儲設備的物模型數據,通過兩者的協同配合來更好的支撐平臺的業務目標,其中ClickHouse的一些獨特的特性是我們選擇它的主要原因。
- 1.相比其他時序數據庫,例如ElasticSearch、HBase等,ClickHouse的LSM-Tree實現機制更為極致,擁有更強大的寫性能,這意味著可以用更少的成本支撐更大的數據量。
- 2.ClickHouse支持 Apache 2.0 license開源協議,相比ElasticSearch協議更加友好,同時也不像InfluxDB,開源版本有功能上的限制。
- 3.ClickHouse的架構非常的輕量,相比其他數據庫產品,例如OpenTSDB依賴Hbase、Druid.io依賴HDFS,ClickHouse單機版本完全可以不依賴第三方組件,并且只有一個服務進程,有著非常低的離線部署運維成本。
- 4.由于ClickHouse的MPP架構及優秀的工程實現,查詢性能在各大基準測試榜中名列前茅。
特性分析
- 存儲結構
LSM-Tree是業內存儲時序數據的常用數據結構,它的核心思路其實非常簡單,每次有數據寫入時并不將數據實時寫入到磁盤,而是先緩存在內存的memTable中并使用歸并排序的方式將內存中的數據合并,等到積累到一定閾值之后,再追加到磁盤中,并按照一定的頻率與觸發閾值將磁盤存儲的數據文件進行合并。這種方案利用了硬盤順序寫性能遠大于隨機寫的特性,降低了硬盤的尋道時間,對于物聯網設備所產生時序數據這種寫遠大于讀的場景來說有非常好的優化效果。
由下圖可以看到,硬盤的順序IO性能與隨機IO性能有著巨大的差距。
傳統的LSM-Tree雖在寫性能上很優秀,但隨之帶來的讀放大與寫放大依然是業內難以解決的問題,目前最優秀的LSM-Tree結構數據庫讀寫放大倍數也在20倍以上,讀寫放大主要來自于幾個方面:
- 1.由于數據需要buffer在內存之中,為了保證瞬時停機例如斷電時數據不丟失,因此所有內存里的數據都需要記錄一份WAL(Write Ahead Log),用于在極端時刻進行數據恢復。
- 2.后臺進行數據文件合并時是一個先讀取再寫入的過程,這個行為同樣會造成寫放大。
- 3.當數據庫發生數據查詢操作時,由于LSM-Tree寫數據的方式會生成較多的小文件,讀請求往往需要跨越內存與硬盤的多個memTable與數據文件才能獲取到正確的結果。
相比其他使用LSM-Tree的數據庫,ClickHouse在設計上直接取消了memTable的內存聚合階段,只對同一寫入批次的數據做排序并直接落盤。因此,完全不需要傳統的寫WAL的過程,減少了數據的重復寫入。同時,ClickHouse也限制了數據的實時修改,這樣就減少了合并時產生的讀寫放大,這個思路相當于限縮了數據庫的使用場景,但卻換取了更強大的讀寫性能。對于物聯網設備產生的數據來說,寫入時本來就是一定間隔的批量寫入,同時極少有數據修改的場景,與ClickHouse的優化方向正好一致。
列式存儲帶來的極高壓縮比
相比于傳統的行存儲數據庫(例如MySQL),ClickHouse采用列式存儲的方式存儲數據,
而列式存儲,能夠帶來更極致的壓縮比。
壓縮的本質是按照一定步長對數據進行匹配掃描,當發現重復部分的時候就進行編碼轉換。
數據中的重復項越多,則壓縮率越高,舉一個簡單的例子:
壓縮前:12345678_2345678
壓縮后:12345678_(8,7)
上述示例中的 (8,7),表示如果從下劃線開始向前移動8個字節,并向前匹配到7個字節長度的重復項,即這里的2345678,真實的壓縮算法肯定比這個簡單的例子復雜,但本質是一樣的。顯而易見,同一個列字段的數據,因為它們擁有相同的數據類型和現實語義,重復項的可能性自然就更高,在大數據量的場景下,更高的壓縮比,會給我們帶來更大的性能和成本優勢。
- 1.分析場景中往往有需要讀大量行但是少數列的情況。在行存模式下,數據按行連續存儲,所有列的數據都存儲在一個block中,不參與計算的列在IO時也要全部讀出,讀取操作被嚴重放大。而列存模式下,只需要讀取參與計算的列即可,極大地減低了IO cost,加速了查詢。
- 2.更高的壓縮比意味著更小的文件,從磁盤中讀取相應數據耗時更短。
- 3.高壓縮比,意味著同等大小的內存能夠存放更多數據,系統cache效果更好。
- 4.同樣更高的壓縮比下,相同大小的硬盤可以存儲更多的數據,大大地降低了存儲成本。
極低的查詢延遲
在索引正確的情況下,ClickHouse可以說是世界上最快的OLAP分析引擎之一。這里快指的就是查詢延遲,簡單說就是用戶發起一次查詢到用戶獲取到結果的時間,這種快很大的原因也來自于ClickHouse極端的設計思路與優秀的工程實現。
ClickHouse的大部分計算操作,都基于CPU的SIMD指令,SIMD的全稱是Single Instruction Multiple Data,即用單條指令操作多條數據,它的原理是在CPU寄存器層面實現數據的并行操作,例如一次for循環每次處理一條數據,有8條數據則需要循環8次,但使用SIMD指令可以讓這8條數據并行處理,從而一次就得到結果,這種方式被稱為向量化計算。
ClickHouse的每一次查詢或統計分析操作,都會盡可能的使用所有的CPU資源來進行并行處理,這種方式能夠讓廉價的服務器同樣擁有極低的查詢延遲,從而在海量數據的場景下保證平臺產品的流暢與快速,而快速和流暢就是最好的用戶體驗。ClickHouse在工程實現上也同樣堅持了快這個原則,可以看到在ClickHouse源碼中不斷地給函數或者算子的局部邏輯增加更多的變種實現,以提升在特定情形下的性能,根據不同數據類型、常量和變量、基數的高低選擇不同的算法。
例如ClickHouse的hash agg,用模板實現了30多個版本,覆蓋了最常見的group key的類型,再比如去重計數函數uniqCombined函數,當數據量較小的時候會選擇Array保存,當數據量中等的時候會選擇HashSet保存,當數據量很大的時候,則使用HyperLogLog算法等等,Clickhouse的性能,就是大量類似的工程優化堆積起來的。
那么代價是什么呢?
然而,世界上并沒有完美無缺的方案,方案設計更像是一場trade-off,比起了解它的優點,更重要的是能不能接受它的缺點。為了更極致的寫入性能,ClickHouse去掉memtable緩存數據再寫入的機制以及實時修改的能力,前者需要客戶端進行額外的攢批操作,而后者限縮了數據庫的使用場景。
ClickHouse其實更像一個單機的數據庫,極致的單表性能優化,非常輕量的安裝部署流程,這些給我們帶來了非常低的離線部署成本,但在大規模分布式場景下卻有著一些缺陷。
在分布式查詢的場景上,ClickHouse使用Distributed Table來實現分布式處理,查詢Distributed Table相當于對不同節點上的單機Table進行一個UNION ALL,這種辦法對付單表查詢還可以,但涉及多表Join就有點力不從心了,在分布式多表Join的場景下,由于沒有Data shuffling之類的功能,ClickHouse需要耗費更多的內存和帶寬來緩存和遷移數據,造成了性能的嚴重下降,大部分人不得不使用大寬表的方式來規避這個問題。
另外,運維一個分布式ClickHouse集群也是非常頭疼的一個點。ClickHouse并不具備數據均衡功能,提供的Distributed Table由于寫入性能太差形同虛設,往往需要通過業務層來保證分發的數據足夠均勻,開源的ClickHouse并沒有集中的元數據管理,ON CLUSTER語法能夠節約一定的操作,但集體擴容以后由于新的節點并不會同步元數據信息,也不會自動平衡數據的負載,因此需要大量的人工介入。作為從標準的計算存儲一體的Shared-nothing結構發展而來的數據庫,ClickHouse對于云原生和存算分離的支持也比較一般,目前社區正在朝這個方向努力,只能說還算是未來可期。
實踐經驗
- 寫入優化
由于ClickHouse特殊的數據寫入方式,為了獲得更高的性能我們需要在寫入客戶端上進行一定的定制化開發。在整體架構上,我們主要使用Flink來實現ClickHouse數據的寫入,由于目前還沒有官方的Connector,我們基于社區接口自研了自己的ClickHouse Connector,主要實現了以下功能:
- 1.實現了基于表與分區的攢批功能,由于ClickHouse特殊的寫入策略,相同表與分區數據在同一批次進行寫入會有更好的性能,同時也能減少寫入時生成的文件數量。
- 2.支持通過配置不同算法將數據以不同的方式分發到節點的shard中,實現了常規的Hash、輪詢、加權等等算法。
- 3.背壓感知與限流功能,通過查詢ClickHouse不同shard的文件碎片數,經限流算法評估后在必要時觸發Flink的反壓機制,防止ClickHouse客戶端報錯造成寫入性能持續下降。
- 4.支持通過接入設備數自動化調節攢批的各種參數、包括數據量大小、條數、間隔時間等等,減少在參數配置時的工作量與門檻。
冷熱分離
時序數據的價值往往與時間相關,越靠近當前時間的熱數據越有價值,會被頻繁的使用,越久遠的冷數據價值相對較低,但依然需要長期的存儲。
因此,可以通過冷熱分離的策略將近期高價值的數據存儲在相對昂貴的存儲來提升統計分析的性能,并在一段時間后將數據移動到相對便宜的大容量存儲中,這種方式可以在不影響用戶體驗的情況下較好地節省數據的存儲成本。在ClickHouse 19.15版本之后開始原生支持冷熱分離的存儲策略,通過相應配置可以按照時間或大小自動地將數據遷移到冷盤。
上述配置中配置了一個名為moving_from_ssd_to_hdd的存儲策略,該策略包含了hot和cold兩個volume。
在volumes的前后順序決定了volume的優先級,意味著part會優先在這個卷上生成,且沒有輪詢策略。因此volumes內的順序是敏感的。hot中含有一塊ssd類型的disk;cold中含有一塊hdd類型的disk。move_factor定義了前一個卷剩余存儲空間的量。當存儲空間小于這個值時,會將前一個volume中相對較早的part遷移到后面的volume中。上述配置表示,當hotvolume的存儲空間超過80%時,便將數據遷移到cold中。
- 字段擴展場景
查詢中需要擴充字段是非常常見的業務場景,在我們的架構中部分字段甚至存在不同的數據庫例如MySQL中。目前,業內的常見做法是通過流式計算引擎,例如Flink、Storm等,在入庫之前進行數據字段的拼接,在ClickHouse中直接存儲計算后的數據。這種方案可以最大的保證數據的查詢效率,但需要付出額外的開發工作量以及硬件資源,特別是SQL JOIN的場景,需要在流式計算引擎中緩存大量實時更新的狀態,有著很大的資源消耗。而我們在實踐中發現,有些更新頻率很低的字段擴充場景,例如設備型號、所屬企業等其實有更好的解決方案,
通過ClickHouse提供的Dictionaries特性能夠代替部分更新頻率較低JOIN場景。
ClickHouse支持將外部數據源例如MySQL、Redis、PostgreSQL等等配置為一個內置的字典,在查詢中可以通過函數進行key -> attributes的轉換,變相的實現了類似JOIN的功能,這種方式相比于JOIN有著更好的性價比。
總結
在物聯網這個業務場景下,需要存儲大量的時序事件數據并且不需要事后進行修改,剛好契合了ClickHouse的寫入性能優勢并且規避了使用場景上
的劣勢,同時ClickHouse部署成本低、架構輕量化的優勢也很符合當前物聯網客戶需求。
目前,ZETag云平臺已經對接大量的網關、標簽、設備,幫助許多客戶實現了降本增效,這些都離不開一個高效穩定的存儲計算引擎的幫助,后續我們也會持續優化產品,積累優秀實踐,打造一個更強大、穩定、通用的物聯網云平臺。
-
物聯網
+關注
關注
2909文章
44736瀏覽量
374485 -
數據庫
+關注
關注
7文章
3822瀏覽量
64506 -
數據庫管理
+關注
關注
0文章
6瀏覽量
6856 -
ZETA
+關注
關注
0文章
121瀏覽量
10321
發布評論請先 登錄
相關推薦
評論