在車聯(lián)網(wǎng)場景下,GPS 產(chǎn)生的時(shí)序數(shù)據(jù)量級通常都達(dá)到了億級,高效寫入、存儲和快速查詢是最基本的數(shù)據(jù)處理要求,但在具體實(shí)踐上這卻不是一件容易實(shí)現(xiàn)的事情。最近某企業(yè)就遇到了這樣一個(gè)問題:服務(wù)端接收存儲 GPS 相關(guān)數(shù)據(jù),按 1 次/30 秒的上傳頻率,一天的數(shù)據(jù)條數(shù)估計(jì)在 1.2 億條,其想要實(shí)現(xiàn)后臺的實(shí)時(shí)監(jiān)控和歷史軌跡查詢,一般用什么樣的數(shù)據(jù)庫進(jìn)行存儲?NoSQL(Redis、MongoDB)?MySQL?還是 HBase?
相信上述企業(yè)的數(shù)據(jù)庫選型問題并不是個(gè)例,選擇到一款合適的數(shù)據(jù)庫,對于打造一個(gè)適合業(yè)務(wù)發(fā)展的數(shù)據(jù)架構(gòu)至關(guān)重要。為了找到該問題的最優(yōu)解,濤思數(shù)據(jù)解決方案架構(gòu)師從數(shù)據(jù)本質(zhì)出發(fā)進(jìn)行分析,結(jié)合具體實(shí)踐輸出本文,給到大家參考。
先談 NoSQL 數(shù)據(jù)庫
不管是 Redis/MongoDB/ElasticSearch 當(dāng)中的哪一個(gè),在面對上述場景時(shí)都會面臨同一個(gè)問題:壓縮率。在車聯(lián)網(wǎng)當(dāng)中,按照國標(biāo) 30s 的采樣間隔可以計(jì)算得到單臺車的采集量為 2880 rows/day,在 10W 車輛規(guī)模下,就是 2.88 億/天。假設(shè)單臺車輛采集 250 個(gè)信號,每個(gè)信號 8 Bytes(相當(dāng)于 Double),即每行 2000 Bytes,那么 1 天就會有 562.5 GB 的數(shù)據(jù)量,1 年會有約 200TB 的數(shù)據(jù)。
在這樣的數(shù)據(jù)規(guī)模下,壓縮率即使是 50%,也需要 100TB 的空間。而這樣的空間規(guī)模,通常都需要 10 個(gè)節(jié)點(diǎn)以上的 NoSQL 集群(用 Redis 的話就更可怕了,需要內(nèi)存 100TB 的集群)。這個(gè)結(jié)論的底層原理,就在于 NoSQL 是使用非結(jié)構(gòu)化的方式來存儲結(jié)構(gòu)化數(shù)據(jù)的,這種模式導(dǎo)致了壓縮效果差、存儲成本高、節(jié)點(diǎn)規(guī)模大的劣勢。
再談 MySQL/PostgreSQL
本來這兩款數(shù)據(jù)庫作為 SQL 類數(shù)據(jù)庫,存儲結(jié)構(gòu)化數(shù)據(jù)是很合適的。但是,我們看一下每秒的寫入量:平均 10W/30 = 3333 rows/s,最大值 10W rows/s,由于車聯(lián)網(wǎng)本身會出現(xiàn)“車機(jī)在一段時(shí)間內(nèi)斷網(wǎng)補(bǔ)傳數(shù)據(jù)”、“車機(jī)上傳按時(shí)鐘定時(shí)”等特點(diǎn),會有一定概率觸發(fā)最大值寫入量,甚至超過最大值。因此選用的數(shù)據(jù)庫必須具備高吞吐能力,而且還得留有余力供后續(xù)擴(kuò)容。用過 MySQL 的開發(fā)者都會有體驗(yàn),在沒調(diào)優(yōu)的情況下,這種 2KB 的行寫入,1k tps 基本把單個(gè)節(jié)點(diǎn)打滿了。
另外一方面,我們一般都會建立索引,至少建立時(shí)間戳的索引用于按時(shí)間段查找數(shù)據(jù)。而當(dāng)我們用 B+ 樹存儲索引,在單表數(shù)據(jù)量達(dá)到 2000W 行時(shí),索引的維護(hù)會導(dǎo)致寫入速度的下降,單從這一點(diǎn)看就很難運(yùn)維,更不要說在建立更多索引的情況下。
再者,MySQL 的橫向擴(kuò)展只能靠中間件來實(shí)現(xiàn),沒有更好的方式了,這種分布式的橫向擴(kuò)展能力也為其打了個(gè)折扣。正是基于此,PostgreSQL 才會單獨(dú)出了一個(gè)分支來存儲時(shí)序數(shù)據(jù)。
接下來談 HBase
HBase 單從誕生的背景看,就不是為了時(shí)序數(shù)據(jù)而設(shè)計(jì)的。很多程序員通過設(shè)計(jì) rowkey 的方式,變相實(shí)現(xiàn)了 HBase 對時(shí)序數(shù)據(jù)的存儲,其中 OpenTSDB 就是一種開源的實(shí)現(xiàn)方式。在 5、6 年前,分布式存儲還是 Hadoop 一枝獨(dú)秀的時(shí)代,大家也就自然而然地用上了 HBase/OpenTSDB 這一類數(shù)據(jù)庫。但是從產(chǎn)品設(shè)計(jì)上看,其設(shè)計(jì)目標(biāo)是為了服務(wù)爬蟲存儲這樣的場景——支持幾千億行的表(超大表),并且支持隨時(shí)添加新的列(列族)。從這樣的設(shè)計(jì)里面,我們可以推導(dǎo)出來下面幾個(gè)問題:
- 存儲率不高:因?yàn)?HBase 里用了 Byte 的類型,以 Column Family 為單位做列存,因此壓縮率也上不去。但是比 NoSQL 好一些。
- 運(yùn)維復(fù)雜:用 HBase 就得先上 HDFS/ZooKeeper/MR 這一系列組件,安裝運(yùn)維就是個(gè)問題。本來只是為了存儲數(shù)據(jù),結(jié)果倒騰起大數(shù)據(jù)的組件來了。
- 計(jì)算慢:哪怕是 OpenTSDB 這個(gè)基于 HBase 做的時(shí)序數(shù)據(jù)庫(Time Series Database),在做一些常見的降采樣、排序計(jì)算、時(shí)間段檢索上,都不是特別快。其背后的問題還是在于 HBase 節(jié)點(diǎn)本身不提供時(shí)序的計(jì)算函數(shù),因此查詢時(shí)都得匯聚到 1 個(gè)OpenTSDB 節(jié)點(diǎn)來進(jìn)行,并發(fā)度很有限并且會消耗大量的網(wǎng)絡(luò) IO 成本。
綜上所述,HBase 也并非很適應(yīng)車聯(lián)網(wǎng)場景。
最后談 TDengine
時(shí)序數(shù)據(jù)庫(Time Series Database,TSDB)TDengine 在設(shè)計(jì)的初期就定位要做物聯(lián)網(wǎng)場景下的數(shù)據(jù)庫,也就是時(shí)序數(shù)據(jù)庫。至于上述場景的數(shù)據(jù)問題,TDengine 已經(jīng)從實(shí)踐層面就給出了回答。
在獅橋集團(tuán)的網(wǎng)貨平臺與金融 GPS 系統(tǒng)業(yè)務(wù)中,對于車輛軌跡收集與計(jì)算有著強(qiáng)需求。GPS 每日產(chǎn)生總量在 40 億左右,需要為業(yè)務(wù)方提供實(shí)時(shí)末次位置查詢,近 180 日行駛軌跡查詢,類似車輛軌跡對比查詢,以及一些風(fēng)險(xiǎn)逾期的智能分析等等。在獅橋的產(chǎn)品歷史中,技術(shù)架構(gòu)一共經(jīng)歷過四個(gè)版本的迭代——通過 MQ 接入廠商數(shù)據(jù)、Kudu+Impala 模式、Hbase + Clickhouse、TDengine。
第三階段改版中,獅橋曾嘗試使用 Hbase、Clickhouse 替換 Kudu,但從存儲功能而言,獅橋希望能夠讀寫兼顧、支持 SQL,同時(shí)還有合理的分區(qū)策略,這一點(diǎn) HBase 肯定不能滿足,Clickhouse 雖然表現(xiàn)還算不錯(cuò),但也沒有完全滿足需求。從業(yè)務(wù)需求出發(fā),獅橋開始進(jìn)行時(shí)序數(shù)據(jù)庫選型,最后選擇了 TDengine,實(shí)現(xiàn)了他們“希望找到一個(gè)存儲技術(shù)既可以兼并讀寫性能,又可以契合到自身業(yè)務(wù)場景,且還是 SQL 原生”的數(shù)據(jù)庫選型訴求。
在應(yīng)用 TDengine 后,獅橋的整體數(shù)據(jù)存儲縮減超過 60% 以上,集群更是指數(shù)級的下線——末次位置查詢的 Redis、軌跡查詢的 Hbase 集群集體下掉、Clickhouse 也不再用作軌跡存儲,把裸金屬用在了更需要蠻力干活的地方,真正實(shí)現(xiàn)了降本增效。
有著同樣場景的還有南京津馳。此前他們的 GPS 服務(wù)采用的存儲技術(shù)方案是 Redis + MySQL + CSV,實(shí)時(shí)數(shù)據(jù)存儲到 Redis 隊(duì)列,經(jīng)過服務(wù)消費(fèi)后將原始數(shù)據(jù)存儲到 MySQL,凌晨執(zhí)行定時(shí)任務(wù)將前一天 MySQL 中的原始數(shù)據(jù)存儲到 CSV 文件。隨著業(yè)務(wù)的發(fā)展以及數(shù)據(jù)量的增長,各種問題也逐漸凸顯,開始影響工作效率,出現(xiàn)查詢效率低、數(shù)據(jù)安全性低、數(shù)據(jù)占用空間大、數(shù)據(jù)運(yùn)用不夠靈活等問題。在進(jìn)行選型調(diào)研后,他們選擇將 TDengine 搭建在 GPS 服務(wù)中,輕松抗住了業(yè)務(wù)中每秒接近 400MB 左右的寫入量,并且壓縮率喜人,存儲空間降為原方案的 3%。
同樣的車聯(lián)網(wǎng)落地案例還有蔚來汽車、理想汽車、零跑汽車等,感興趣可以點(diǎn)擊鏈接查看,本篇文章就不多做贅述了。
而 TDengine 之所以能達(dá)到上述效果,還要從 Jeff(TDengine 創(chuàng)始人& CEO 陶建輝)歸納的十條時(shí)序數(shù)據(jù)處理特點(diǎn)說起:
- 所有采集的數(shù)據(jù)都是時(shí)序的 —— 就只處理時(shí)序數(shù)據(jù)
- 數(shù)據(jù)都是結(jié)構(gòu)化的 —— 結(jié)構(gòu)化是所有優(yōu)化的第一切入點(diǎn)
- 每個(gè)數(shù)據(jù)流的數(shù)據(jù)源是唯一的 —— 在寫入過程中不用過分考慮隨機(jī)寫入
- 數(shù)據(jù)少有更新或單條刪除操作 —— 選擇數(shù)據(jù)結(jié)構(gòu)的重要依據(jù)
- 數(shù)據(jù)一般是按到期日期來刪除的 —— 自動淘汰數(shù)據(jù)是長久運(yùn)維的必需品
- 數(shù)據(jù)要優(yōu)先保證寫入操作,讀操作為輔 —— 寫入吞吐量是第一指標(biāo)
- 數(shù)據(jù)流量平穩(wěn),可以較為準(zhǔn)確的計(jì)算 —— 不像 MySQL 的業(yè)務(wù)場景,壓力基本可預(yù)測
- 數(shù)據(jù)一定是指定時(shí)間段和指定區(qū)域查找的 —— 查詢優(yōu)化的主要入手點(diǎn)
- 數(shù)據(jù)多有統(tǒng)計(jì)、聚合等實(shí)時(shí)計(jì)算操作 —— 提供時(shí)序獨(dú)有的函數(shù)
- 數(shù)據(jù)量巨大,一天的數(shù)據(jù)量就超過100億條 —— 針對性的壓縮率、橫向擴(kuò)展架構(gòu)
從上述時(shí)序數(shù)據(jù)特點(diǎn)出發(fā),TDengine 打造了以下的創(chuàng)新技術(shù)點(diǎn):
- 創(chuàng)建一個(gè)設(shè)備一張表、超級表,壓縮率達(dá)到到 10% 的級別
- 行式存儲 + 列式存儲,進(jìn)一步提升壓縮率
- LSM Tree 結(jié)構(gòu)的引擎,SkipList 的 MemTable
- Union all + tag 的超級表語法糖
- 降采樣/狀態(tài)窗口/會話窗口函數(shù)
作為時(shí)序數(shù)據(jù)庫引擎,TDengine 不需要基于 Hadoop 生態(tài)搭建,也不需要拼裝 Kafka、Redis、HBase 等諸多組件,它將數(shù)據(jù)處理中的緩存、消息隊(duì)列、數(shù)據(jù)庫、流式計(jì)算等功能都統(tǒng)一在了一起,這樣輕量級的設(shè)計(jì)不僅讓它的安裝包很小、對集群資源消耗很少,同時(shí)也在一定程度上降低了研發(fā)、運(yùn)維成本,因?yàn)樾枰傻拈_源組件少,因而系統(tǒng)可以更加健壯,也更容易保證數(shù)據(jù)的一致性。
下面延伸一個(gè)話題,分享一下我總結(jié)的數(shù)據(jù)庫選型原則,以此幫助大家更好地進(jìn)行數(shù)據(jù)庫選型。
講講數(shù)據(jù)庫的選型原則
- 如果是事務(wù)的:
- 單機(jī)扛得住的,MySQL/PG 都可以選擇
- 單機(jī)扛不住,但是好分片的,同上一條
- 不好分片,那可以考慮 TiDB 這種分布式事務(wù)的 HTAP
- 對于非事務(wù),基本上就是各種 MPP 型的 OLAP:
- 多維分析為主,不知道自己什么已知維度的分析,就用 ClickHouse/Doris 這種通用的 OLAP
- 有場景特色的,就選場景通用的,例如 TDengine 做時(shí)序場景,Neo4j 做圖計(jì)算
- 分布式數(shù)據(jù)庫,看幾點(diǎn):
- Sharding + Partition 策略:這一點(diǎn)基本上決定了性能的上下限
- 分布式架構(gòu):這一點(diǎn)影響系統(tǒng)的容量上限/瓶頸模塊
- 計(jì)算函數(shù):這一點(diǎn)決定好不好用,能不能減輕業(yè)務(wù)開發(fā)的工作量。不然都只有讀寫沒計(jì)算,啥計(jì)算都自己寫肯定是不合適的。
結(jié)語
事實(shí)證明,專用的比通用的更能打,大家可以移步到 https://docs.taosdata.com/ 去了解 TDengine 的更多技術(shù)細(xì)節(jié)。如果你也面臨時(shí)序數(shù)據(jù)處理難題,歡迎添加小T vx:tdengine1 申請加入 TDengine 用戶交流群,和更多志同道合的開發(fā)者一起探討解決。



互聯(lián)網(wǎng).png)



-1.png)







證.png)


伙伴.png)
伙伴.png)
伙伴.png)



