前言
同花順每天需要接收海量交易所行情數(shù)據(jù),確保行情數(shù)據(jù)的數(shù)據(jù)準(zhǔn)確。但由于該部分?jǐn)?shù)據(jù)過于龐大,而且使用場景頗多,每天會產(chǎn)生很多的加工數(shù)據(jù),而組合管理(PMS)還會使用到歷史行情數(shù)據(jù)。之前雖然采用了Postgres+LevelDB作為數(shù)據(jù)的存儲方案,但仍然有不少痛點,所以必須對存儲方案進(jìn)行改造。
通過對ClickHouse、InfluxDB、TDengine等時序數(shù)據(jù)存儲方案的調(diào)研,最終我們選擇了TDengine Database。大數(shù)據(jù)監(jiān)控平臺采用TDengine Database后,在穩(wěn)定性、查詢性能等方面都有較大的提升。
項目背景與問題
同花順?biāo)侥贾医M合管理是一個集多資產(chǎn)管理、實時監(jiān)控、績效分析、風(fēng)險分析、輿情分控、報表輸出等功能于一體的智能投資組合管理平臺。為券商、基金、私募等機(jī)構(gòu)客戶提供實時準(zhǔn)確的投研服務(wù)。
數(shù)據(jù)層面主要依賴實時數(shù)據(jù)及歷史日級別數(shù)據(jù),為所支持的股票、基金、債券、美股、港股、期權(quán)、期貨資產(chǎn)類別的監(jiān)控和分析提供支持。
其中,實時數(shù)據(jù)主要用于資產(chǎn)監(jiān)控,由于使用場景會對數(shù)百個不同的標(biāo)的進(jìn)行資產(chǎn)監(jiān)控,數(shù)據(jù)刷新頻率在1秒左右。因此,整個系統(tǒng)對實時數(shù)據(jù)的讀寫性能及延時有著比較高的要求。
此外,歷史日級別數(shù)據(jù)主要用于投資組合的各種分析。歷史分析所涉及的標(biāo)的數(shù)量,相較實時資產(chǎn)監(jiān)控更多,在時間上的跨度會長至10數(shù)年。此外在輸出分析報告時,還會疊加多種分析指標(biāo)和分析模型。在整個分析過程中,涉及巨量的數(shù)據(jù)集。這對歷史數(shù)據(jù)庫的讀寫性能又提出了更高的要求。

由上述架構(gòu)圖可以看到,該服務(wù)內(nèi)需要大量的基礎(chǔ)數(shù)據(jù)支撐,像實時行情、歷史行情。
針對歷史行情數(shù)據(jù)支撐,涉及多個證券品種的數(shù)據(jù),包括股票、債券、基金、港股、美股、期貨、期權(quán)。數(shù)據(jù)跨度周期從數(shù)天到數(shù)年不等。頁面返回的數(shù)據(jù)是計算結(jié)果,而計算依賴的數(shù)據(jù)是業(yè)務(wù)層數(shù)據(jù)和大量歷史行情數(shù)據(jù)。這個計算過程包含了歷史行情數(shù)據(jù)請求。尤其是在展示結(jié)果包含多證券標(biāo)的和長周期的情況下,產(chǎn)生一個分析報告可能達(dá)到 5s,而行情獲取耗時占比達(dá)到80%以上。而且,輸出報告服務(wù)面臨并發(fā)情況,這種情況帶來的擁堵會進(jìn)一步惡化用戶的使用體驗。

通過對改造前的數(shù)據(jù)流進(jìn)行分析,當(dāng)前行情獲取模塊的分析, 當(dāng)前存在以下2個需要解決的問題:
- 依賴多,穩(wěn)定性較差:PMS作為多品種的投后分析服務(wù), 需要使用到各種日線數(shù)據(jù)、當(dāng)天實時行情數(shù)據(jù)、當(dāng)天分鐘數(shù)據(jù)等,在數(shù)據(jù)獲取方面需要依賴Http以及Postgres、LevelDB等數(shù)據(jù)庫。過于多的數(shù)據(jù)獲取鏈路會導(dǎo)致平臺可靠性降低,同時依賴于其他各個服務(wù),導(dǎo)致查詢問題過于復(fù)雜。
- 性能不能滿足需求: PMS作為多品種投后分析,在算法分析層面需要大量的行情獲取,而且對行情獲取的性能也有較大的要求,當(dāng)前所有行情會占據(jù)大量分析的性能。
技術(shù)選型
為解決上述問題,我們有必要對現(xiàn)有行情模塊進(jìn)行升級改造。在數(shù)據(jù)庫選型方面,我們對如下數(shù)據(jù)庫做了預(yù)研和分析:
- ClickHouse:運維成本太高,擴(kuò)展過于復(fù)雜,使用的資源較多。
- InfluxDB: 可以高性能地查詢與存儲時序型數(shù)據(jù),被廣泛應(yīng)用于存儲系統(tǒng)的監(jiān)控數(shù)據(jù)、IoT行業(yè)的實時數(shù)據(jù)等場景;但是集群功能沒有開源。
- TDengine:性能、成本、運維難度都滿足,支持橫向擴(kuò)展,且支持高可用。
通過綜合對比,我們初步選定TDengine Database作為行情模塊的數(shù)據(jù)庫。
主要由于行情數(shù)據(jù)是綁定時間戳的形式,所以時序數(shù)據(jù)庫(Time-Series Database)更適用于這個業(yè)務(wù)場景。而且在同等數(shù)據(jù)集和硬件環(huán)境下,濤思官方的測試結(jié)果顯示,TDengine的寫入速度遠(yuǎn)高于InfluxDB。同時TDengine支持多種數(shù)據(jù)接口,包含C/C++、Java、Python、Go和RESTful等。
數(shù)據(jù)接入過程需要進(jìn)行如下操作:
- 數(shù)據(jù)清洗,剔除格式不對的數(shù)據(jù);
- 由于歷史數(shù)據(jù)過于雜亂,采取腳本生成csv形式并直接導(dǎo)入,后續(xù)增量數(shù)據(jù)由Python實現(xiàn)腳本導(dǎo)入數(shù)據(jù)。
數(shù)據(jù)庫建模以及應(yīng)用場景
TDengine Database在接入數(shù)據(jù)前需要根據(jù)數(shù)據(jù)的特性設(shè)計schema,以達(dá)到最好的性能表現(xiàn)。
同花順行情根據(jù)時間頻度的不同,數(shù)據(jù)特性分別如下。
通用特性:
- 數(shù)據(jù)格式固定,自帶時間戳;
- 數(shù)據(jù)極少需要更新或刪除;
- 數(shù)據(jù)標(biāo)簽列不多,而且比較固定;
- 單條數(shù)據(jù)數(shù)據(jù)量較小,字段較少。
tick快照數(shù)據(jù)特性如下:
- 每天數(shù)據(jù)量大,超過2000W;
- 需保留近幾年數(shù)據(jù)。
daily數(shù)據(jù)特性如下:
- 子表很多,約20W張表;
- 每天數(shù)據(jù)20W;
- 需保留近30年數(shù)據(jù)。
根據(jù)上述特點,我們構(gòu)建了如下的數(shù)據(jù)模型。
按照TDengine建議的數(shù)據(jù)模型,將每個特性的數(shù)據(jù)單獨創(chuàng)建數(shù)據(jù)庫,根據(jù)不同特性數(shù)據(jù)設(shè)置不同的參數(shù),在各個數(shù)據(jù)庫內(nèi)根據(jù)品種去創(chuàng)建超級表,例如股票、指數(shù)、債券、基金等,結(jié)合我們的數(shù)據(jù)特點和使用場景,創(chuàng)建數(shù)據(jù)模型如下:
- 以品種類型作為超級表,方便對同一類型的數(shù)據(jù)進(jìn)行聚合分析計算;
- 標(biāo)的本身包括標(biāo)的信息,直接將標(biāo)簽信息作為超級表的標(biāo)簽列,每個品種作為子表。
庫結(jié)構(gòu)如下:

超級表結(jié)構(gòu):


落地實施
組合管理主要是需要可以穩(wěn)定高效地獲取到數(shù)據(jù),所以在實施的過程中需要考慮查詢的性能、線上數(shù)據(jù)的更新以及運維情況。
實施難點如下。
- 數(shù)據(jù)寫入:由于歷史行情數(shù)據(jù)會存在大量的歷史數(shù)據(jù),不是只接收當(dāng)前新增的數(shù)據(jù),這對歷史數(shù)據(jù)的遷移有很大的挑戰(zhàn)。當(dāng)前TDengine數(shù)據(jù)庫對于現(xiàn)有數(shù)據(jù)的導(dǎo)入,通過insert語句達(dá)到批量更新,會導(dǎo)致歷史數(shù)據(jù)遷移耗時很大。為了解決該問題,我們在本地建立緩存,將現(xiàn)有csv文件修改為可執(zhí)行導(dǎo)入的形式,直接通過csv導(dǎo)入,大大提升了寫入速度。在這個過程中,我們還發(fā)現(xiàn)了一個問題:通過csv導(dǎo)入的時候,如果采用自動創(chuàng)建表的方式,會在幾個版本內(nèi)出現(xiàn)崩潰。通過詢問官方,他們不建議在導(dǎo)入csv的時候創(chuàng)建表,后來我們就拆解為先創(chuàng)建表結(jié)構(gòu)再進(jìn)行csv導(dǎo)入,問題得到了解決。
- 查詢問題:查詢單點問題。TDengine原生HTTP查詢是直接查詢特定服務(wù)端完成的。這個在生產(chǎn)環(huán)境是存在風(fēng)險的。首先,所有的查詢都集中在一臺服務(wù)端,容易導(dǎo)致單臺機(jī)器過載;另外,無法保證查詢服務(wù)的高可用?;谝陨蟽牲c,我們在TDengine集群使用過程中,在應(yīng)用使用創(chuàng)建鏈接的時候會配置多臺Http的接口來解決單點問題。
- 容量規(guī)劃:數(shù)據(jù)類型、數(shù)據(jù)規(guī)模對TDengine的性能影響比較大,每個場景最好根據(jù)自己的特性進(jìn)行容量規(guī)劃,影響因素包括表數(shù)量、數(shù)據(jù)長度、副本數(shù)和表活躍度等。根據(jù)這些因素調(diào)整配置參數(shù),確保最佳性能,例如blocks、caches和ratioOfQueryCores等。根據(jù)與濤思數(shù)據(jù)工程師的溝通,我們確定了TDengine的容量規(guī)劃計算模型。TDengine容量規(guī)劃的難點在于內(nèi)存的規(guī)劃。
改造效果
完成改造后,線上的行情獲取性能可以達(dá)到預(yù)期,目前運行穩(wěn)定。

- 改造后性能對比情況,可以看到性能提升明顯。

- 改造后穩(wěn)定性對比情況:改造前調(diào)用數(shù)據(jù)情況共40W次,共出現(xiàn)異常0.01%的異常,改造后出現(xiàn)異常降低至0.001%。
TDengine問題解決
在使用TDengine的過程中,我們遇到了一些小問題。比如在通過Restful接口使用TDengine的時候,獲取數(shù)據(jù)超過10240行會有限制。經(jīng)過溝通,我們了解到在啟動服務(wù)端時,參數(shù)restfulRowLimit 可以控制返回結(jié)果集的最大條數(shù)。
其他一些在使用過程中不清楚的地方,在濤思數(shù)據(jù)的物聯(lián)網(wǎng)大數(shù)據(jù)微信交流群都能很快得到反饋和解答。一些小bug也可以通過版本升級解決。
總結(jié)
目前從大數(shù)據(jù)監(jiān)控這個場景看,TDengine Database在成本、性能和使用便利性方面都有非常大的優(yōu)勢,尤其是在節(jié)省成本方面給我們帶來了很大驚喜。
在預(yù)研和項目落地過程中,濤思數(shù)據(jù)的工程師提供了專業(yè)、及時的幫助,在此表示感謝。
希望TDengine能夠不斷提升性能和穩(wěn)定性,開發(fā)新特性,我們也會根據(jù)自身需求進(jìn)行二次開發(fā),向社區(qū)貢獻(xiàn)代碼。祝TDengine越來越好。對于TDengine,我們也有一些期待改進(jìn)的功能點:
- 支持更加豐富的SQL語句;
- 灰度平滑升級;
- 可實現(xiàn)自定義聚合方法;
- 更快的數(shù)據(jù)遷移。
后續(xù)我們也將在同花順的更多場景中嘗試應(yīng)用TDengine,包括:
- tick、minute行情數(shù)據(jù)的遷移以及線上應(yīng)用;
- 采取自定義聚合方法實現(xiàn)分鐘行情、日線行情的聚合計算;
- 當(dāng)天實時行情的數(shù)據(jù)的管理。



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



-1.png)







證.png)


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



