传统库分表麻烦查询慢?TDengine 如何解决“搜狐基金”的应用难题

该项目需要实时展示国内基金的净值和收益(货币基金),在保证满足折线图展示的功能基础上,还需要加入统计排行、分页展示等功能,为用户提供最全面实时的查询服务。此前搜狐基金团队使用的 MySQL 数据库在面对海量数据时存在能力瓶颈,在此背景下,其决定基于 TDengine 尝试一下全新的方案。

选型背景

在使用 TDengine 之前,我们使用的是 MySQL 数据库。

由于所购买的数据源的基金数据都是混在一起的,包含来自国内的2万只基金,跨越几十年(从九几年至今)的数千万行较宽的数据,如果通过 MySQL 来存储这些数据,我们首先要把每个基金的数据分表,有一定程度的工作量,所以我们决定先全量保存这些数据在一张表中。

但这种大表会导致查询的性能非常低下,为了应对这一问题,我们通过离线查询生成每天的基金数据图片返回给用户,暂未对外提供自定义查询服务。

与此同时,经历了以上种种,我们也在怀疑传统关系型数据库面对海量数据的能力瓶颈。这时候,我们了解到了 TDengine ,它的核心是一款时序数据库(Time Series Database),它“一个设备一张表”的特殊设计,与我们正在做的“一个基金一张表”的分表工作不谋而合。因此我们决定基于 TDengine 尝试一下全新的方案。

使用经历

通过充分调研和测试后,我们发现:

由于“超级表”的存在,数据建模变得非常清晰,几乎所有查询都可以以“超级表”为核心用简单的 SQL 完成。

此外,由于“自动建表”这个特色功能,我们可以无需校验就能够直接建表,这让我们得以非常轻松地完成各只基金数据的拆分建表以及写入工作。

可以说,接入 TDengine 的前期准备工作十分顺利。

传统库分表麻烦查询慢?TDengine 如何解决“搜狐基金”的应用难题 - TDengine Database 时序数据库

我们使用三台 4C 16GB 的服务器组建了 TDengine 的集群。

数据库创建语句如下:

传统库分表麻烦查询慢?TDengine 如何解决“搜狐基金”的应用难题 - TDengine Database 时序数据库

值得一提的是,基金数据是一日一条,属于低频次数据。对于这种数据,默认的配置是不够的。一开始我们的查询性能并不快,基本都是在秒级别甚至还有更高。

通过文档和博客以及官方团队的支持,我们放大了 duration 和 stt_trigger 参数,这样确保了不会产生过多的文件碎片影响读写性能,后续的查询全部被优化至毫秒级别。

因此我们总结出来一点经验就是:不同的写入频率属于不同的业务场景,最好不要使用同一个库,而是要分库处理比较好。

超级表建模如下:

传统库分表麻烦查询慢?TDengine 如何解决“搜狐基金”的应用难题 - TDengine Database 时序数据库
传统库分表麻烦查询慢?TDengine 如何解决“搜狐基金”的应用难题 - TDengine Database 时序数据库

当前在日常使用时,业务查询在 100 qps 的情况下,均可以实现毫秒级实时返回数据。

从超级表的设计特点出发,我们在超级表维度上做统计分析就方便多了,比如:筛选类型和日期的全量基金查询——

select time, code, name, manager_id, manager_name, unit_net_value, pre_unit_net_value, accumulate_net_value, pre_day_rate, pre_week_rate, pre_month_rate, pre_three_month_rate, pre_half_year_rate, pre_year_rate, pre_cur_year_rate, pre_start_rate, last_time, last_unit_net_value, last_accumulate_net_value, asset_size from fund_net_value where time = #{date} and (type = '003009' or type = '003010')
传统库分表麻烦查询慢?TDengine 如何解决“搜狐基金”的应用难题 - TDengine Database 时序数据库

又比如,查询目前基金净值排行和收益排行,通过简单的 SQL 即可实现——

select time, code, name, manager_id, manager_name, unit_net_value, pre_unit_net_value, accumulate_net_value, pre_day_rate, pre_week_rate, pre_month_rate, pre_three_month_rate, pre_half_year_rate, pre_year_rate, pre_cur_year_rate, pre_start_rate, last_time, last_unit_net_value, last_accumulate_net_value, asset_size from fund_net_value where time = #{date} and order by ${column} ${sort} limit #{offset}, #{size}
传统库分表麻烦查询慢?TDengine 如何解决“搜狐基金”的应用难题 - TDengine Database 时序数据库

与此同时我们搭建了 Grafana 可视化监控体系,利用各种监控工具和软件来收集、存储和分析监控数据,并通过可视化界面提供实时的监控图表和警报,帮助项目相关负责人即时识别修改问题,进一步提高了服务的可靠性和稳定性。

写在最后

总而言之,在保证稳定高效运行的前提下,我们已经通过 TDengine 逐步平滑替代原有功能。考虑到国内基金项目只是一个开始,围绕着股票等其他项目,我们仍需要对这款国产时序库做更多的研究与学习。

企业简介

搜狐公司是中国著名的的综合性互联网企业,主要业务领域包括新媒体、通信以及移动增值服务,集成了娱乐中心、体育中心、时尚文化中心等多重角色。

作者介绍

武朋,搜狐智能平台高级开发工程师。