大佬们,请教一下数据读取

70 天前
 iamtuzi3333
小弟负责是后端内容的编写,现在系统有一批传感器,数据格式都是 json ,每个传感器每秒都有数据发送过来。我接收,然后写入文件,每天一个.json ,例如:传感器编号-日期-文件,这样的格式。文件中每行都是{}的数据,里面有时间戳,data ,例如{"time":12346574,"data":[1,2,3,4,5]},每一行都是这样的形式。文件夹目录有分层,每天都有一个日期对应的目录,里面就是当天的数据文件。数据同时存入到数据库 Mongo 中,单个节点,建了 time 字段的索引。现在查询历史数据量多的话感觉速度还是有点慢,依靠 time 字段找出时间范围的数据,取出每条数据的 data 元素;现在小弟想数据库只存储当前 3 天的数据,就是额外写一个脚本定时删除三天以前的数据,然后历史数据改为读取对应文件及日期的文件数据,这样读取历史数据是否可行,速度是否更快呢,后端用的 node ,他读取数据量量一大就容易内存栈,这个 data 字段元素有 200 个浮点数,一天能存 86400*200 多个数字,所以读取历史数据有时候读的时间范围大就容易崩,想请教大佬们怎么处理好一点。
1946 次点击
所在节点    程序员
26 条回复
skallz
70 天前
如果查询范围不大的话,可以考虑直接让前端拿对应文件的内容前端处理,让客户端分担服务端的性能压力,哈哈哈哈,前提是你的文件服务器和业务服务器不是同一个服务器,比如用的云服务商 oss 之类的
chihiro2014
70 天前
为什么感觉应该是使用 influxdb 之类的产品,而不是 mongo
xiaofsu
70 天前
最好的办法就是换个时序数据库。
daxin945
70 天前
如果是我的话可能会用 clickhouse 替换 mongo
MoYi123
70 天前
没必要, 数据库一般会用一些压缩算法, 肯定比你支持存 json 文件要省的.
数据库里用 partition table, 按日期分
内存溢出肯定是你代码有错, 86400*200 个 float 应该还不到 100MB.
timethinker
70 天前
mongodb 从 5.0 开始支持时间序列( Time Series ),可以提高查询速度。

https://www.mongodb.com/docs/manual/core/timeseries/timeseries-procedures/
sagaxu
70 天前
数据总量是多少,每次查询返回多少,有点儿慢是多慢,查询是怎么写的,这些都没讲清楚,不大好分析。
Oldletter
70 天前
MongoDB 支持 TTL 索引,允许自动删除超过指定时间的数据。你可以为 time 字段创建一个 TTL 索引来确保数据库中只保留 3 天的数据,这样就不需要手动写脚本来删除过期数据。

你的数据感觉不是特别大,所以建议你看看代码问题吧
iamtuzi3333
70 天前
@skallz 范围也大,会查询去年某一个月的所有数据,前端处理不太现实,现在文件跟业务都在一个服务器。
@chihiro2014 我之前看过这个,但是他对 json 格式数据不太友好,部署相对麻烦。
@xiaofsu 看了部分时序数据库,发现部分接口、迁移、数据格式不太方便。
@daxin945 我查查这个数据库看看效果。
iamtuzi3333
70 天前
@MoYi123 内存溢出是 node 的问题好像,我试过查询去年某一段时间的数据,他就查询内存栈溢出了。
@sagaxu 数据总量很多,每天 86400 条 json 存入,每次查询返回不定期,就是得根据前端传回的时间范围作为查询条件,有时候会查询去年某一段时间的数据,慢的时候主要是等待很久,数据库的每个集合的 timestamp 字段有做索引。查询代码如下:
// 获取 MongoDB 原生数据库连接
const db = mongoose.connection.db;
// 获取指定的集合
const collection = db.collection(collectionName);
// 构建查询条件
const query = {};
const timestampInt = parseInt(timestamp, 10);
query.timestamp = timestampInt;
// 查询数据
const result = await collection.find(query).toArray();
if (result.length <= 0) {
ctx.status = 200;
ctx.body = { message: 'no data', data: [] };
return;
}

@Oldletter 代码相对来说比较简单,就是传入集合名字,时间范围,就去对应的结合查询,查询代码如上,后端用的 node ,koa 框架,但是我发现 Mongo 的数据迁移不太方便,比如说我要把 a 服务器的某一个库的所有数据转移到 b 服务器的 Mongo 实例中,就不太方便了。
Nitsuya
70 天前
@daxin945 #4 +1
sagaxu
70 天前
前端查一个月的数据干嘛用?浏览器根本无法展示。显然要做好聚合,缩小数据规模。
aloxaf
70 天前
没用过 MongoDB ,不过这类时间序列数据查询的优化方向都是差不多的:
1. 提前按天、按小时聚合数据,根据查询范围来调整返回数据的精度。就像楼上说的,一个月的数据得上百万条了,前端要这么多数据干嘛。
2. 原始数据可以存的时候就按小时打包来存,没必要每秒生成一条记录。
3. 你这数据量也不大,但不知道 MongoDB 存这些数据效率如何,如果太占空间可能要考虑对旧数据降采样(你真的需要查询三年前某分钟内每秒的数据?)或者转冷存储。

不过还是推荐直接用数序数据库,不仅速度更快还节省空间,而且「优化花费的时间」未必比「迁移花费的时间」更少,除了 influxdb 外也可以看看 timescaledb ,对于有 sql 经验的人来说迁移真的方便)
iamtuzi3333
70 天前
@sagaxu 查询画图展示,长时间的我会额外查询宿友再处理,比如每十分钟提取一个最大值,汇聚所有的值返回。但是归根到底我还是要查询这些时间范围的数据。
@aloxaf 前端查询数据主要是展示,会有额外的需求,不过我还是要单独查询出这些范围的数据做进一步的加工。原始数据是传感器就固定每秒会有数据,传感器一多,每小时打包就不方便了,有时需要上半段,有时候需要下半段,每秒是最好的处理方法。数据会查询很久之前的,需要保持。时序数据库我还在找,发现挺多不怎么合适,总有一两项让我退步🤣
nivalxer
70 天前
场景比较类似,只不过我们这边传感器数据没有到每秒,一般大概 10 几秒到几分钟不等。
目前也是 Mongodb 的方案,按每个站点(一个站会有多个参数)一张表方式存储,每个小时会抽一条数据放小时表,统计报表再根据公司配置进行公司表级的存储。
Mongodb 需要考虑查出来的文档返回不能超过 16M ,虽然有一些配置可以绕过限制。目前感觉在数据量比较多,也根据查询条件(时间等)加了索引情况下,响应速度一般。
如果数据比较频繁并且需要偶尔查出来比较多的历史数据(多天、月、季度)还是看看其他的方案,目前我也想看看有没有除 MongoDb 外的其他更好的方案。
hd10180
70 天前
虽然我很菜,但我也做过类似的数据处理。
我的看法是要分析的数据不要存成数组,后期可能不方便做查询,data 的每个数值应该有个属性名。
假设[26, 80, ..]代表的是 [温度, 湿度, ...] 转成 temp: value, hum: value 的方式存储。可能你的情况跟我的不太一样,就当我没说。
另外每个传感器应该有 uuid 的吧,索引做成 uuid+time 不知道会不会好些?还可以考虑写个额外的程序对数据做分析,比如做小时维度的数据统计、月维度的统计等。
securityCoding
70 天前
时序数据库干的活不要硬来
yyt6801
70 天前
楼上都提到的时序数据库就是为了解决这种问题, 首先你要知道 每秒的那个 data:[]里面都代表什么东西;知道结构其他都好办了, 剩下的交给时序数据库解决
sagaxu
70 天前
@iamtuzi3333 “比如每十分钟提取一个最大值”,这个事情可以提前做好。我之前做过一个数据结构类似的项目,有分钟汇总,小时汇总,天汇总,都是提前生成缓存好,当日数据还会存一份在内存里加速访问。一般查询都有个特点,时间段跨度越大,越不关心局部数据,缓存好的汇总表能极大提高查询速度。

一次查大量数据,只能在后台定时任务里跑,不能由前端触发查询,否则任何数据库都无法满足。数据量量一大,即使 nodejs 直接读文件解析,不经过 db ,也会消耗很大资源。
1Z3KYa0qBLvei98o
70 天前
@skallz 我一般就是这么做的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://tanronggui.xyz/t/1101255

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX