小 T 導讀:此前,韻(yun)達使(shi)用 MySQL 分區+索引處(chu)(chu)理訂單數(shu)據(ju)(ju)的方式遭受到了挑(tiao)戰(zhan),面對(dui)每日億級(ji)的數(shu)據(ju)(ju)量,MySQL 顯然已經(jing)無法滿足(zu)當下的數(shu)據(ju)(ju)處(chu)(chu)理需求(qiu)。為更好地發(fa)展業務(wu),在此基(ji)礎上韻(yun)達新增了 TDengine 的數(shu)據(ju)(ju)源(yuan),用專(zhuan)業的數(shu)據(ju)(ju)庫來進行時序數(shu)據(ju)(ju)的處(chu)(chu)理。
作為一家頭(tou)部(bu)物流公司,韻(yun)達每日的(de)訂單掃(sao)描量能達到上(shang)億級,這也(ye)是(shi)目前(qian)公司數(shu)據量最大的(de)一塊業(ye)務(wu)。要保證(zheng)業(ye)務(wu)的(de)正常(chang)運作,系統就(jiu)需要匯總統計全國網點的(de)掃(sao)描數(shu)據(韻(yun)達的(de)所有訂單數(shu)據),并實時(shi)反饋給(gei)用戶。此外,這些數(shu)據也(ye)會給(gei)到網點、分撥中心的(de)內部(bu)員工使用,用于個人工作量、站(zhan)點掃(sao)描量等統計工作。
在業務(wu)尚(shang)未擴(kuo)張之前(qian),我們采(cai)用(yong)的(de)是 MySQL 分區+索引方式進(jin)行(xing)此(ci)類數(shu)據的(de)處理,但(dan)隨著企業的(de)發展、業務(wu)量的(de)增加,面對每日億級的(de)數(shu)據量,MySQL 顯然(ran)已經無法滿足當下的(de)數(shu)據處理需(xu)求。
在這種背景下,我們決定進行數據庫選型。考慮到目前業務主要是統計各個網點設備實時上傳的數據,無需再進行修改等操作,是典型的時序數據。經過一番調研,我們發現時序數據庫 TDengine 就很符合當下的業務要求,其數據模型與我們的場景十分契合,基于百億千億級大數據量的查詢性能也很強悍。在對 TDengine Database 進行實際測試與使用后,實際的效果也讓我們很滿意。
一、落地實踐與效果展示
當前我們的架構(gou)是 Spring Boot + MyBatis + MySQL + TDengine,TDengine 負(fu)責(ze)處理(li)時(shi)序(xu)數(shu)據(ju),MySQL 則負(fu)責(ze)非時(shi)序(xu)數(shu)據(ju)的存儲及應用,整體(ti)架構(gou)如下:

由(you)于我(wo)們(men)的(de)架構未(wei)做遷移,只是新(xin)增了(le) TDengine 的(de)數據源,因此沒有增加(jia)很多工作量就完成(cheng)了(le)數據架構的(de)升級。


我們目前使用 TDengine 2.2.2.0 版本,在三臺 16C 64G 的服務器上部署了集群,數據寫入速度大概為每秒 5000 行。根據“一個掃描槍一張表”的模型建表,把設備的地點和站點類型設置為標簽。
為了防(fang)止設備(bei)更(geng)(geng)換(huan)地點(dian)導致標簽值(zhi)發生變化(hua)(hua),我們選擇在建表的(de)時(shi)候(hou)把(ba)地點(dian)也放進表名中,這樣一來,當(dang)地點(dian)發生變化(hua)(hua)后,也能(neng)通(tong)過(guo)新(xin)建一張表達(da)到同(tong)樣的(de)使用效果。比如(ru):scan_6100000000265_790117,代表的(de)就(jiu)是設備(bei)編(bian)號(hao)為 6100000000265 所在地址為 790117 的(de)掃(sao)(sao)描槍,當(dang)這把(ba)掃(sao)(sao)描槍更(geng)(geng)換(huan)位置的(de)時(shi)候(hou),我們可以新(xin)建一張 scan_6100000000265_800000 的(de)子(zi)表,和舊表區分開(kai),并且(qie)同(tong)時(shi)保留兩份數(shu)據(ju)。
當前,這個(ge)超級表(biao)下面已經(jing)有了近百萬子表(biao),經(jing)過 1 個(ge)多月的正式(shi)使用,保(bao)存了大(da)約(yue) 200 億(yi)行的數據量。


值得一提的是,基于 TDengine 常用的查詢基本可以在 1 秒之內完成,一些特定查詢甚至可以達到毫秒級:
select location,sum(weight_info) as weightSum,count (waybill_barcode) as ticketNum from base.scan_data where ts>='2022-04-07 00:00:00' and ts<='2022-04-07 23:59:59' group by location;

展示效果如下:

select waybill_barcode,location,scanning_person,scan_category,remark,weight_info weight,scan_time,volume from base.scan_data where ts>='2022-04-07 00:00:00' and ts<='2022-04-07 23:59:59' and site_type=3 limit 0,10;

展示效果如下:

在存儲上可以看到,我們的超級表是 20 個字段,大部分是 int 類型,有 5 個左右是 varchar 類型,最大的字段是一個用來存儲中文的 500 長度的 nchar ,大約占用 300GB 不到的磁盤(單副本)。而此前使用 MySQL 時,光硬盤使用就需要幾個 TB(主從),這(zhe)還沒有算上(shang)內存(cun)和 CPU 等資源,由此可見(jian) TDengine 帶來的降(jiang)本(ben)增(zeng)效是多么顯著。
二、寫在最后
當然(ran),TDengine 的測試使用過程中也并非一(yi)帆風順,我(wo)們也遇到了一(yi)些問(wen)題,放在這里供大家參(can)考:
- 由于對數據并發量預估不足,我們使用的默認毫秒時間精度經常會出現時間戳重復的現象,導致數據沒能成功入庫,后續依靠增加精度解決。
- 超級表如果新增標簽,已有數據的標簽為 null,需要手動為每個子表更改標簽,不夠友好。
- 由于 TDengine 建表是單線程所以是有瓶頸的,大概每秒是萬張以下,所以在初步搭建環境的時候不建議使用自動建表,如果表數據量不多就無所謂了。
在與 TDengine 的(de)社區工作人(ren)員反饋之后,以(yi)上問題最終都通過參(can)數(shu)的(de)配置優(you)化(hua)(hua)或者合理的(de)使(shi)用(yong)(yong)方式得(de)到了解決,之后我們會(hui)(hui)考(kao)慮把TDengine擴展到更多(duo)業務(wu)中(zhong)去。相信隨著 3.0 的(de)優(you)化(hua)(hua),TDengine 可(ke)以(yi)更好地融入到韻(yun)達的(de)使(shi)用(yong)(yong)場景中(zhong),未來我們會(hui)(hui)有更加緊(jin)密的(de)合作。


























