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

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

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

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


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

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

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



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



-1.png)




.png)


證.png)


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



