睿信物聯(lian)網平(ping)臺是北京睿信世(shi)達自主開發的通(tong)用(yong)物聯(lian)網平(ping)臺,為用(yong)戶(hu)(hu)提(ti)供從傳感器設備、邊緣網關、云平(ping)臺到 App 、小(xiao)程序(xu)的一(yi)整套(tao)端到端物聯(lian)網 SaaS 云平(ping)臺,可以(yi)滿足(zu)用(yong)戶(hu)(hu)的通(tong)用(yong)物聯(lian)網功能(neng)需求;在(zai)此基礎上構建(jian)了(le)智慧水務、智慧消(xiao)防、智慧環保、智慧農業、智能(neng)家(jia)居等行業應用(yong)組件,滿足(zu)用(yong)戶(hu)(hu)的場景化需求。
平臺的整體架構如下。

一、現狀及痛點
目前(qian)采用 OpenTSDB 進(jin)行時(shi)序數據的(de)存儲(chu),功能上滿足(zu)現有需求;但是由于 OpenTSDB 架構(gou)復(fu)雜(za),體(ti)量過(guo)重,給開發(fa)測(ce)試、安裝部署以(yi)及運維管理等工(gong)(gong)作(zuo)帶(dai)來了(le)不小的(de)麻煩,隨著業(ye)務(wu)的(de)發(fa)展(zhan),問題逐漸凸(tu)顯,開始影響(xiang)工(gong)(gong)作(zuo)效率,具體(ti)可(ke)以(yi)歸納為以(yi)下幾方面:
- 安裝難
OpenTSDB 不是獨立(li)的服(fu)(fu)務組(zu)(zu)件(jian),它還要(yao)(yao)依賴(lai) HBase 、 HDFS 、 ZooKeeper 。需(xu)要(yao)(yao)把(ba)這些(xie)服(fu)(fu)務組(zu)(zu)件(jian)全(quan)部安裝(zhuang)配置好(hao),OpenTSDB 才能正常工作,即便(bian)是一個熟(shu)練(lian)的運(yun)維工程(cheng)師,把(ba)這些(xie)服(fu)(fu)務組(zu)(zu)件(jian)全(quan)部安裝(zhuang)配置一遍,也需(xu)要(yao)(yao)很長時間。
- 調試難
在開發(fa)測試過程中(zhong),如(ru)果(guo)出現問(wen)題(ti)(ti)(ti),需要(yao)對(dui) OpenTSDB 進行日志分析,甚(shen)至(zhi)可(ke)能還需要(yao)對(dui) HBase、HDFS 和 ZooKeeper 進行全面的日志分析和問(wen)題(ti)(ti)(ti)排查,才能最終定位(wei)并解決問(wen)題(ti)(ti)(ti)。
- 運維難
在(zai)正式環境中,要求集(ji)群部署(shu),各(ge)種(zhong)服務都是雙份(fen)、三份(fen)甚至n份(fen)部署(shu),各(ge)個(ge)服務節(jie)點之間的(de)關系錯綜復雜,服務節(jie)點和主機(ji)數量越(yue)多,監控管理就會越(yue)難(nan),運(yun)維(wei)人員的(de)工作負擔也就越(yue)重(zhong)。
- 成本高
成(cheng)(cheng)本(ben)可以分(fen)為(wei)兩個(ge)方面,一個(ge)是(shi)人力(li)成(cheng)(cheng)本(ben)高(gao),由于(yu)安裝、調(diao)試、運(yun)維的難度(du)增(zeng)(zeng)加(jia),造(zao)成(cheng)(cheng)開發運(yun)維人員工(gong)作(zuo)量增(zeng)(zeng)加(jia),工(gong)作(zuo)效率變低(di),從(cong)企業(ye)經營角度(du)看,人力(li)成(cheng)(cheng)本(ben)變高(gao);另一個(ge)是(shi)硬件資(zi)源成(cheng)(cheng)本(ben)高(gao),由于(yu)服務節(jie)點眾多(duo),占用(yong)的主(zhu)機、內存和磁(ci)盤空間也(ye)會很多(duo),購買或租用(yong)這些硬件資(zi)源需(xu)要更多(duo)的費用(yong)支出。
二、技術選型
為了解決目前這(zhe)些問題,我們決定重新進(jin)行(xing)(xing)技術選(xuan)型(xing),尋找 OpenTSDB 的替代方案,升級目前的時序(xu)數據庫解決方案。進(jin)而(er),要對技術選(xuan)型(xing)進(jin)行(xing)(xing)全(quan)面評估,結合實(shi)際需要,我們確定了幾(ji)個選(xuan)型(xing)要求:
- :必須是開放源代碼的,并且允許免費商用;
- 成熟穩定:具有較長的發展歷史,經過大量項目應用實踐,經歷過時間的檢驗;
- 社區活躍:開發者社區人員多,討論、問答、咨詢、推廣等線上線下活動頻繁;
- 迭代更新:有開發人員一直在維護,不斷在迭代更新和發布新版本;
- :單機能支持每秒 10 萬以上的插入效率,并能夠通過擴展硬件支持更高的插入效率;
- 開銷低:服務節點少,占用的內存、CPU和磁盤空間少;
- 支持集群:能夠集群部署,容量可水平擴展。
經過初步調查,InfluxDB、TimescaleDB 和 TDengine 這 3 個時序數據庫(Time Series Database)進入了我們的考察范圍(wei)。
- InfluxDB
在(zai) DB-Engines 網(wang)站(zhan)上,InfluxDB 處(chu)于(yu)時序數據庫排(pai)名的第一位,滿足(zu)我們(men)絕(jue)大(da)部分的要(yao)求,但(dan)集群(qun)模塊閉源,因此被排(pai)除在(zai)外。
- TimescaleDB
TimescaleDB 在(zai) DB-Engines 中的排名也比較高,幾乎滿足我們(men)的所有選(xuan)型要求,但是它是 PostgreSQL 上的一個(ge)時(shi)序(xu)數據庫(ku)插件,是基(ji)于 RDBMS 的時(shi)序(xu)數據庫(ku),不(bu)是一個(ge)純粹的時(shi)序(xu)數據庫(ku);另(ling)外,對集(ji)群支持不(bu)好(hao),不(bu)支持水平擴展。
- TDengine
和(he) InfluxDB 一樣,TDengine Database 最初(chu)的(de)(de)開源(yuan)(yuan)版(ban)本也不支持集群(qun),也被排除在外。去年(nian) TDengine 開源(yuan)(yuan)了集群(qun)版(ban)本后,又進入(ru)了我們的(de)(de)考察范圍(wei)。經過各方面的(de)(de)綜(zong)合考察評(ping)估,TDengine 滿足我們所(suo)有的(de)(de)選型要求(qiu),成為技術選型的(de)(de)最終目標(biao)。
三、數據建模
由(you)于是既有(you)系統(tong)(tong)升(sheng)級改造(zao),必(bi)須(xu)符合現(xian)有(you)系統(tong)(tong)架構,不(bu)能(neng)(neng)(neng)影響(xiang)現(xian)有(you)功能(neng)(neng)(neng)。因此,數據建(jian)模必(bi)須(xu)限定(ding)在一定(ding)的范圍內,有(you)一定(ding)的約(yue)(yue)束(shu)和限制(zhi),不(bu)能(neng)(neng)(neng)像設計(ji)一個新系統(tong)(tong)那樣有(you)那么大的自由(you)度。總結(jie)下(xia)來(lai),主(zhu)要有(you)兩方面的約(yue)(yue)束(shu)和限制(zhi):
3.1 schema-free(模式自由)
不需要有 create table 之(zhi)類的(de)(de)建表過程,就可以直接(jie)進行數(shu)據(ju)(ju)的(de)(de)寫(xie)入和查詢。目前(qian)已經使用了 OpenTSDB 這(zhe)種 schema-free 的(de)(de)數(shu)據(ju)(ju)庫(ku),并按照 schema-free 的(de)(de)方式(shi)進行數(shu)據(ju)(ju)的(de)(de)讀寫(xie),希望延續(xu)這(zhe)種方式(shi),避(bi)免功能和架構上的(de)(de)調整。
3.2 單列模式
物(wu)聯網平(ping)臺的設計(ji)初衷(zhong)是要能夠支撐所(suo)有(you)的應用場(chang)景,不(bu)能只(zhi)考慮某一種特定(ding)(ding)的應用場(chang)景,必(bi)須設計(ji)成(cheng)一種通(tong)用架(jia)構(gou),為應用層提供足夠的靈活(huo)度。因(yin)此(ci),我們將(jiang)設備和指標之(zhi)間(jian)的關系設計(ji)為動態綁(bang)定(ding)(ding)關系,并且(qie)能夠進行動態綁(bang)定(ding)(ding)配置。
比如(ru),某種液(ye)位(wei)儀有(you)液(ye)位(wei)和距離(li)兩個指(zhi)標,在 A 場景下只需要采集(ji)液(ye)位(wei),在 B 場景下只需要采集(ji)距離(li)。
為了能夠(gou)支撐設備(bei)和指標(biao)之(zhi)間的(de)這種動態綁定(ding)關系,我們采用了單列模(mo)式(shi)(也(ye)被(bei)稱(cheng)為縱(zong)表模(mo)式(shi)或(huo)(huo)窄表模(mo)式(shi)),每個指標(biao)單獨保存(cun)一條數(shu)據(ju)(ju),如果設備(bei)有 n 個指標(biao),就保存(cun) n 條數(shu)據(ju)(ju)。相反,多列模(mo)式(shi)(也(ye)被(bei)稱(cheng)為橫表模(mo)式(shi)或(huo)(huo)寬表模(mo)式(shi))是將設備(bei)的(de)所有指標(biao)數(shu)據(ju)(ju)存(cun)儲為一條數(shu)據(ju)(ju),分不同(tong)的(de)列存(cun)儲不同(tong)指標(biao)值(zhi)。
很(hen)顯然,TDengine 不是 schema-free 的(de)(de),需要先建表,然后才能進行數據讀寫,這就突破了(le)上面的(de)(de)約束和(he)限制,無法滿足架構上的(de)(de)要求,難道(dao)要放棄 TDengine ?還有沒有變通的(de)(de)辦法呢?經(jing)過(guo)一番(fan)調(diao)查分析,最終(zhong)還是找到(dao)了(le)解決辦法。
下面(mian)從(cong)三方面(mian)進行拆(chai)解說(shuo)明。
3.2.1 通用超級表
TDengine 里有超級表的(de)(de)概念(nian),每(mei)種(zhong)設(she)備對應一個超(chao)(chao)級表(biao),這個超(chao)(chao)級表(biao)只負責存儲這種(zhong)類型的(de)(de)設(she)備數(shu)據(ju);由(you)于前面的(de)(de)約束和限(xian)制,我們肯定不能這么用(yong)。但(dan)可以(yi)變通(tong)的(de)(de)來用(yong),設(she)計(ji)一個能夠兼容所有設(she)備類型的(de)(de)通(tong)用(yong)超(chao)(chao)級表(biao),把(ba)所有設(she)備的(de)(de)數(shu)據(ju)往這個超(chao)(chao)級表(biao)里裝(zhuang);這樣,只需(xu)(xu)要在系統(tong)安裝(zhuang)部署的(de)(de)時候,一次性(xing)執行(xing)超(chao)(chao)級表(biao)的(de)(de)建(jian)(jian)表(biao)腳本(ben),實際運(yun)行(xing)時,就不需(xu)(xu)要再動態(tai)創建(jian)(jian)超(chao)(chao)級表(biao)了。
3.2.2 單列模式
TDengine 支(zhi)持單列(lie)模式和多列(lie)模式,出于插入效(xiao)率(lv)和存(cun)儲效(xiao)率(lv)的考慮,官方(fang)推薦多列(lie)模式。但是,為了(le)符合前面(mian)的約束(shu)和限制,滿足通用場景需(xu)求,我們采用了(le)單列(lie)模式,一(yi)條(tiao)數據中(zhong)僅存(cun)儲一(yi)個指標值。
結(jie)合上面的思路,我們的數據模型(xing)的設計如下(xia)(為了(le)方(fang)便分(fen)析(xi)問題(ti),省去了(le)幾個無關的標簽):

數據列包含時間和指標(biao)值(zhi)兩列,對(dui)應上報(bao)時間和上報(bao)的具體值(zhi),標(biao)簽中(zhong)的指標(biao)編碼用(yong)來(lai)對(dui)同一個(ge)設備下的不同指標(biao)做區分,查詢的時候可以用(yong)來(lai)做條件(jian)過濾。
3.2.3 自動建表
TDengine 中(zhong)還有普通(tong)表(biao)的(de)概念(為(wei)了和超級表(biao)概念區分開,這(zhe)里稱(cheng)為(wei)普通(tong)表(biao)),普通(tong)表(biao)也需要(yao)先創建(jian)后插入。還好 TDengine 支持自(zi)(zi)動建(jian)表(biao),可以在插入的(de)時候(hou),順帶(dai)建(jian)表(biao)。于是,我們就可以利用自(zi)(zi)動建(jian)表(biao)語法進行(xing)自(zi)(zi)動建(jian)表(biao),屏蔽(bi)普通(tong)表(biao)的(de)建(jian)表(biao)過程。具體寫法如下:

通用(yong)超級表(biao),單(dan)例模式,再加上自動建表(biao),通過(guo)這些(xie)辦(ban)法,我們把表(biao)的概念(nian)變得越(yue)來越(yue)弱化, TDengine 逐漸被改造成(cheng)了一個 schema-free 的數據(ju)庫,可以按照 schema-free 的方(fang)式來使用(yong) TDengine 。
這(zhe)樣一來,在不改動架構(gou),不影響功能(neng)的前(qian)提(ti)下,數據建模工作(zuo)就圓(yuan)滿完成了。
四、代碼改造
在(zai)物(wu)聯網平臺現有的(de)(de)架構中,有一個時(shi)序數據(ju)服務(wu),專門負(fu)責對時(shi)序數據(ju)庫(ku)進行(xing)封裝,然后對外提(ti)供(gong)時(shi)序數據(ju)的(de)(de)寫入(ru)和查詢服務(wu),物(wu)聯網平臺的(de)(de)其他所有模(mo)塊都通過(guo)這個服務(wu)來訪問時(shi)序數據(ju)庫(ku)。

有(you)了這(zhe)樣的架構(gou)設計,代碼(ma)改造(zao)工(gong)作(zuo)就變得非常簡單。只需要改動這(zhe)個時序(xu)數據(ju)服務,在現有(you)基礎上增加對TDengine的支持,將寫入(ru)和查(cha)詢兩(liang)個功能按照(zhao)TDengine的JDBC接口進(jin)行(xing)接口適配(pei),將時序(xu)數據(ju)的寫入(ru)和查(cha)詢切換(huan)到TDengine。
通過這種方式,我們(men)就把TDengine的改造遷移(yi)屏蔽在了時序數據服務內部,上層應用無需關心,功能上不受任(ren)何影響。
五、數據遷移工具
升級改(gai)造(zao)項目(mu),需(xu)要保留歷史(shi)(shi)數(shu)(shu)據(ju),需(xu)要對(dui)歷史(shi)(shi)數(shu)(shu)據(ju)進(jin)行(xing)數(shu)(shu)據(ju)遷移。為此,我們(men)專門開發了(le)(le)一(yi)個數(shu)(shu)據(ju)遷移工具(ju),將OpenTSDB中(zhong)的歷史(shi)(shi)數(shu)(shu)據(ju)遷移到TDengine,并(bing)且進(jin)行(xing)了(le)(le)詳盡的功能測試。為了(le)(le)確保海量數(shu)(shu)據(ju)的快速遷移,我們(men)還做了(le)(le)性能優化(hua),并(bing)進(jin)行(xing)了(le)(le)大數(shu)(shu)據(ju)量的壓力測試。數(shu)(shu)據(ju)遷移是升級上線過程(cheng)中(zhong)非常重要的一(yi)個環(huan)節(jie),所以,我們(men)在這個工具(ju)上投入了(le)(le)很多(duo)精力,甚至(zhi)比代碼改(gai)造(zao)本身還多(duo)。
六、升級上線
為了能(neng)夠平(ping)滑順(shun)利地(di)完成升(sheng)級上(shang)線,不影響用戶正常使用,我們制定(ding)了詳細的遷移方案,將升(sheng)級上(shang)線分為三階段完成。
第一階段:數據遷移
將改造后的新(xin)版本上線,OpenTSDB和(he)TDengine并行運行,同時向兩個(ge)數(shu)(shu)據(ju)庫寫(xie)入(ru)數(shu)(shu)據(ju),由于OpenTSDB有(you)全量數(shu)(shu)據(ju),查(cha)詢請(qing)求全部交給OpenTSDB;與(yu)此同時,啟動數(shu)(shu)據(ju)遷移工具,將歷史數(shu)(shu)據(ju)遷移到TDengine,待(dai)數(shu)(shu)據(ju)遷移完成,進入(ru)到第二(er)階段(duan)。

第二階段:試運行
OpenTSDB和TDengine依然(ran)并行運行,也同時(shi)向(xiang)兩(liang)個(ge)數(shu)(shu)據(ju)庫寫(xie)入數(shu)(shu)據(ju);數(shu)(shu)據(ju)遷移已經(jing)完(wan)成,TDengine中已經(jing)具備全量數(shu)(shu)據(ju),因此(ci),查詢請求全部(bu)切換到(dao)TDengine。觀察(cha)兩(liang)周左右的時(shi)間,沒(mei)有發(fa)現(xian)任(ren)何問(wen)題,進入到(dao)第(di)三階段(duan)。

第三階段:正式上線
TDengine經過試運行一切正常,功能和性能都沒有問題,于(yu)是我(wo)們(men)將OpenTSDB停(ting)止運行,數據只向TDengine寫入,OpenTSDB占用的(de)資源全(quan)部回收(shou)。

到此為止,升級(ji)上線全部完成。
七、改造效果
遷移(yi)到TDengine后(hou),效(xiao)(xiao)果非常明顯(xian),硬件資源減(jian)少到原來的1/5,效(xiao)(xiao)率有了(le)明顯(xian)的提升。隨著存儲規模的不斷變大,這種(zhong)改善和提升效(xiao)(xiao)果會越來越明顯(xian)。此外,在運(yun)維(wei)管理(li)、費用(yong)支出、開發測試(shi)等方面也有了(le)很大的改善。
- 開發人員現在可以自己電腦上搭建一套環境,隨便折騰,不用擔心跑不起來,也不用擔心影響別人;
- 性能測試的時候,用配置低一些的機器也沒問題,照樣能做出壓測效果;
- 遇到技術難題,原來通過Google、百度、StackOverflow尋找答案,現在可以直接在官方渠道提issue,也可以在TDengine的技術社區提問,TDengine的技術專家親自答復,響應非常快;
- TDengine的體積小,只有幾M,上傳起來非常快,有些私有化部署項目,不允許訪問外網,只能手動上傳,體積小的優勢就非常明顯;
- 安裝部署簡單,配合Docker容器,可以在幾分鐘內完成安裝部署;
- 運營監控工作變簡單了,只需要對TDengine的幾個進程進行監控;
- 占用的磁盤空間明顯變小了,減少到原來的1/5;
- 使用的主機減少到原來的1/5,相應的費用支出也減少了。
八、總結
此次(ci)升級(ji)改(gai)造(zao)總(zong)體進行得(de)比(bi)較順利,但過程中也有一(yi)些波折,尤其(qi)是在(zai)數據(ju)建模的時候(hou)遇到了(le)一(yi)些困難(nan)。辦法(fa)總(zong)比(bi)困難(nan)多,通過一(yi)些方法(fa)和(he)技巧,我們(men)把(ba)TDengine改(gai)造(zao)成了(le)schema-free的數據(ju)庫,滿(man)足了(le)物(wu)聯網平臺的要求,最終(zhong)完成了(le)升級(ji)改(gai)造(zao)。
目(mu)前,已(yi)經(jing)支撐起了(le)所(suo)有物(wu)聯網設(she)備上報的數據,同時支撐起了(le)應(ying)用層的各(ge)種應(ying)用場景。

改造后(hou)的(de)效果明(ming)顯,硬件(jian)資源(yuan)減少為原來1/5,開發、測(ce)試、運維、管理、支(zhi)出等方面都有明(ming)顯的(de)改善(shan)和(he)提升。
我們使用到的功能還比較簡單,主要是插入、連續查詢以及降采樣查詢,對于(yu)(yu)物聯(lian)網平臺來(lai)(lai)說基本夠(gou)用(yong)。UNION、GROUP BY、JOIN、聚合查詢等功能(neng)暫時還未使(shi)用(yong)到,這些功能(neng)對于(yu)(yu)大(da)數據分析的(de)場景非常(chang)有(you)用(yong),將(jiang)來(lai)(lai)在一些大(da)數據項目里可(ke)以嘗試使(shi)用(yong),用(yong)來(lai)(lai)代替Hadoop全家(jia)桶。
此(ci)外(wai),使(shi)用過程中遇到(dao)一些(xie)問(wen)題,希望改(gai)進:
- JDBC-JNI不是純Java的,依賴一個動態庫,給安裝部署帶來不少麻煩;后來通過JDBC-RESTful解決了這個問題,但是中間多了一層RESTful Connector,性能會低一些;最理想的做法,還是用純Java寫一個直連后端服務的JDBC Driver;
- 客戶端是命令行方式,對于開發者不是很友好,尤其是一些初級開發者,或者是用慣了圖形界面的開發者;圖形界面,語法高亮,語法檢查,這些功能還是很香;雖然目前有兩個社區開發者提供的GUI,當然官方能提供支持的話是最好不過了。


























