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


























