小 T 導讀:在對多款時序數據庫(Time-Series Database)進行了選型(xing)測(ce)試后,同程旅行自研的“夜鷹監控”搭載 TDengine 代替了現(xian)有存儲(chu)設備,減(jian)少運維(wei)成本(ben)。本(ben)文(wen)分享了他(ta)們對建表模型(xing)的方案選擇思路,接入 TDengine 后所遇到問(wen)題的解決經驗以及(ji)落地效果(guo)展示。
同程旅行有一套自研的基礎監(jian)(jian)控(kong)(kong)系(xi)統“夜鷹監(jian)(jian)控(kong)(kong)”。目(mu)前夜鷹監(jian)(jian)控(kong)(kong)使用(yong)情況為百(bai)萬級別(bie) endpoint、億級 metric、每秒(miao) 200 萬并發寫(xie)入以及 2 萬并發查詢。其存(cun)儲組件基于 RRD 存(cun)儲,RRD 存(cun)儲雖然擁有很好(hao)的性能(neng),卻也存(cun)在著一些問題——基于內存(cun)緩(huan)存(cun)定期寫(xie)入 RRD,在機器重啟后(hou)會丟失部分數(shu)據。
出(chu)現(xian)這一(yi)問(wen)題的原因是 RRD 寫(xie)入為單點寫(xie)入,當機器(qi)故障后(hou)無(wu)法(fa)實現(xian)自動切換,這一(yi)存儲特性也導致無(wu)法(fa)展示更長時間的原始(shi)數據。 針(zhen)對此問(wen)題,夜鷹監控做了(le)很(hen)多高(gao)可用(yong)設計,但還是很(hen)難滿足業務的需(xu)求,之后(hou)又(you)進行了(le)如下改造:
- 引入了 ES 存儲,為夜鷹監控提供 7 天內原始數據的查詢,目前部署的 2 套存儲。
- RRD 提供給 API 調用,調用量在幾萬級 TPS。
- ES 提供給夜鷹面板使用,保存 7 天原始數據,調用量在幾百 QPS。
但隨(sui)著(zhu)基礎監控系統(tong)接入(ru)指標的(de)增長,目前 2 套存儲系統(tong)在資源消耗方面一直(zhi)在增長,同(tong)時業(ye)務對監控也提出了更多的(de)聚合計算功能要求。基于(yu)此(ci),我(wo)們需要尋找一個新的(de)時序(xu)數據庫來(lai)代替現有的(de)存儲系統(tong),以(yi)減少運維成本。
在進行時(shi)序數據庫選型時(shi),實際需求主要(yao)有(you)以下(xia)三點(dian):
- 性能強,可以支持千萬級別并發寫入、10 萬級的并發讀取
- 高可用,可以橫向擴展,不存在單點故障
- 功能強,提供四則運算、最大、最小、平均、最新等聚合計算功能
在對比(bi)了 InfluxDB、TDengine、Prometheus、Druid、ClickHouse 等多款市面(mian)流行的(de) Database 產(chan)品后,最終(zhong) TDengine 從中脫(tuo)穎(ying)而(er)出,能滿(man)足我們所有(you)的(de)選型(xing)要求。
一、基于 TDengine 的建表模型
夜鷹監控系統(tong)不僅存(cun)(cun)在(zai)系統(tong)指(zhi)標(biao)數據(ju)(ju),同時也(ye)會(hui)存(cun)(cun)在(zai)業務指(zhi)標(biao)數據(ju)(ju)。前者(zhe)諸如 CPU、內存(cun)(cun)、磁盤、網(wang)絡一類(lei),這類(lei)信息(xi)是(shi)可(ke)以預測的指(zhi)標(biao),其(qi)指(zhi)標(biao)名是(shi)固定的,總數約為 2000 萬個。后(hou)者(zhe)則會(hui)通過夜鷹監控的 API 上傳業務自身定義的指(zhi)標(biao),指(zhi)標(biao)名是(shi)無法預測的,其(qi)特點是(shi)并發量不大(da)卻存(cun)(cun)在(zai)長(chang)尾(wei)效應(ying),隨(sui)著時間累積,一年可(ke)以達到(dao)一億級。
而 TDengine 在(zai)創建表之(zhi)前需(xu)要先規(gui)劃表的結(jie)構,從上(shang)面的數據存儲背景來看,如果要將海量(liang)的指(zhi)標數量(liang)直接一(yi)次性扁平化全(quan)部創建,則會造(zao)成性能的下(xia)降。通過和 TDengine 技術支持人員溝通,他們給出了(le)兩個建表方案:
其(qi)一(yi),將系(xi)統類基(ji)礎指標聚合到(dao)(dao)一(yi)個(ge)(ge)超級(ji)表(biao)(biao),一(yi)張表(biao)(biao)存放(fang)一(yi)個(ge)(ge)節點,多個(ge)(ge)指標一(yi)次性(xing)寫入。這(zhe)個(ge)(ge)方式的(de)(de)好處是表(biao)(biao)的(de)(de)數量(liang)可以降(jiang)低到(dao)(dao)千萬級(ji)別,但因為夜鷹監控的(de)(de)數據(ju)是單條上傳的(de)(de),很難做到(dao)(dao)一(yi)個(ge)(ge)表(biao)(biao)里面全部指標集齊再(zai)寫入。并且(qie)不(bu)(bu)同(tong)的(de)(de)指標上傳頻率不(bu)(bu)同(tong),如果(guo)再(zai)根據(ju)頻率建(jian)不(bu)(bu)同(tong)的(de)(de)超級(ji)表(biao)(biao),運(yun)維管(guan)理成(cheng)本會非常高。
其二,將不(bu)同的(de)(de)指(zhi)標建成一(yi)個(ge)一(yi)個(ge)的(de)(de)子(zi)表,5 千萬個(ge)左(zuo)右(you)的(de)(de)指(zhi)標匯聚(ju)成一(yi)個(ge)集群,分多個(ge)集群接(jie)入(ru)。這種方(fang)式(shi)的(de)(de)好(hao)處是表結構簡(jian)單(dan),但運維管理(li)多個(ge)集群會(hui)很麻煩。不(bu)過(guo)我們也了(le)解到濤思數(shu)據明年(nian)會(hui)發布 TDengine 3.0 版本,能支持(chi)超過(guo)上億張表,那(nei)么這一(yi)方(fang)案就可以很好(hao)的(de)(de)進行數(shu)據遷(qian)移(yi)了(le)。
最終,我們選擇了第(di)二個方案。同時為了減少搭建集群(qun)的數量(liang),準備寫個程序定期(qi)清理掉(diao)過期(qi)的子表(biao)(biao)。目前夜鷹監控的超級(ji)表(biao)(biao)結構如下(xia)。

夜鷹監控接入(ru) TDengine 后,架構(gou)圖如下。

二、接入 TDengine 之后的效果展示
在(zai)(zai)進(jin)行數據(ju)遷移時,我們先是(shi)將夜鷹監(jian)控數據(ju)轉(zhuan)移到 Kafka 中,之后通過消(xiao)費(fei)轉(zhuan)換程(cheng)序將 Kafka 的數據(ju)格式(shi)轉(zhuan)為了 TDengine SQL 格式(shi)。 這個(ge)過程(cheng)還(huan)遇到了如(ru)下(xia)三(san)個(ge)小問題,解(jie)決思路放(fang)在(zai)(zai)這里(li)給大家參考:
- 連接方式問題。剛開始我們使用的是 go-connector sdk 的方式接入 TDengine,跑起來后發現,go-connector 依賴于 taos client 包以及 taos.cfg 配置文件里面的鏈接配置,同時因為 FQDN 的設置難以使用 VIP 負載均衡的配置方式。我們考慮到后面消費程序會部署到容器中,不宜產生過多的依賴,因此還是放棄了 go-connector 的連接方式,改為了 HTTP RESTful 的連接方式。
- Kafka 消費數量問題。由于夜鷹監控上傳到 Kafka 里面的數據是一條一個指標,再加上 200 萬左右的并發,連接數很快就耗光了。通過和 TDengine 技術支持人員溝通,了解到可以改造成批量 SQL 的方式寫入,最佳的實踐效果是 400-600K 單個 SQL 的長度。經過計算,我們上傳的指標條數大概為 5000 條左右,大小為 500K 。
- 讀取速度問題。因為每次要等到消費 5000 條數據,才會觸發一次寫入,這種情況也導致讀取速度較慢。TDengine 技術支持人員再次給出了解決方案——使用 Taos 自己實現的 Queue,代碼地址為: ,有需要的同學可以自行獲取。
聚焦到實際效果上,TDengine 數據寫入性能很強。原本我們的單套存儲系統需要 10 多臺高配機器,IO 平均 30% 最高 100% 的情況下才能寫完數據;現在只需要 7 臺機器,并且 CPU 消耗在 10% 左右、磁盤 IO 消耗在 1% 左右,這點非常的棒!


同時,其(qi)數據讀取接(jie)入過程也很順利。使用 RESTful 接(jie)口(kou)后,結(jie)合 TDengine 自帶的強大聚合函數功能(neng),很容易就能(neng)計算出想要的結(jie)果。
三、寫在最后
在我們(men)的(de)(de)項(xiang)目中,TDengine Database 展現(xian)出了超強的(de)(de)性(xing)能(neng)(neng)和(he)多元(yuan)化的(de)(de)功(gong)能(neng)(neng),不(bu)僅具備(bei)高效的(de)(de)寫(xie)入性(xing)能(neng)(neng)、壓(ya)縮率,其(qi)聚(ju)合函數功(gong)能(neng)(neng)也非(fei)常齊全,支持 Sum/Max/Min/Avg/Top/Last/First/Diff/Percentile 等多種函數,在架構上(shang)也設計的(de)(de)很(hen)合理,可以實(shi)現(xian)很(hen)好(hao)地橫向擴(kuo)展。同時(shi),其(qi)自身監(jian)控也做的(de)(de)很(hen)不(bu)錯,打造了基于 Grafana 的(de)(de) TDengine 零依(yi)賴(lai)監(jian)控解(jie)決方(fang)案 TDinsight,在監(jian)控系統自身狀態上(shang)展現(xian)出了很(hen)好(hao)的(de)(de)效果。
未來(lai),我們也(ye)希望與(yu) TDengine 展開更深層次的合作,在此也(ye)為其提出一些小小的建議,助力 TDengine 往(wang)更好的方向(xiang)發展:
- 官方文檔還不夠完善,新版的功能在文檔中沒有體現,很多用法缺少代碼示例,個人理解起來比較晦澀難懂
- 社區用戶經驗傳遞不是很多, 遇到一些問題時,Google 比較難以找到社區的解決案例
在(zai)接入的(de)過程中,非常感謝 TDengine 的(de)技(ji)術支(zhi)持(chi)人員的(de)全力(li)支(zhi)持(chi)。雖然目前 TDengine 還(huan)處(chu)于發展(zhan)初期,也存在(zai)一些問(wen)題需要優化,不過其優異的(de)性能還(huan)是給了(le)我們一個大大的(de)驚喜!總而言(yan)之,TDengine 是個非常不錯的(de)存儲系統,相信在(zai)陶老師的(de)帶領下會發展(zhan)的(de)越(yue)(yue)來越(yue)(yue)好!


























