V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
iamtuzi3333
V2EX  ›  程序员

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

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

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

    你的数据感觉不是特别大,所以建议你看看代码问题吧
    iamtuzi3333
        9
    iamtuzi3333  
    OP
       3 天前
    @skallz 范围也大,会查询去年某一个月的所有数据,前端处理不太现实,现在文件跟业务都在一个服务器。
    @chihiro2014 我之前看过这个,但是他对 json 格式数据不太友好,部署相对麻烦。
    @xiaofsu 看了部分时序数据库,发现部分接口、迁移、数据格式不太方便。
    @daxin945 我查查这个数据库看看效果。
    iamtuzi3333
        10
    iamtuzi3333  
    OP
       3 天前
    @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
        11
    Nitsuya  
       3 天前
    @daxin945 #4 +1
    sagaxu
        12
    sagaxu  
       3 天前
    前端查一个月的数据干嘛用?浏览器根本无法展示。显然要做好聚合,缩小数据规模。
    aloxaf
        13
    aloxaf  
       3 天前
    没用过 MongoDB ,不过这类时间序列数据查询的优化方向都是差不多的:
    1. 提前按天、按小时聚合数据,根据查询范围来调整返回数据的精度。就像楼上说的,一个月的数据得上百万条了,前端要这么多数据干嘛。
    2. 原始数据可以存的时候就按小时打包来存,没必要每秒生成一条记录。
    3. 你这数据量也不大,但不知道 MongoDB 存这些数据效率如何,如果太占空间可能要考虑对旧数据降采样(你真的需要查询三年前某分钟内每秒的数据?)或者转冷存储。

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

    一次查大量数据,只能在后台定时任务里跑,不能由前端触发查询,否则任何数据库都无法满足。数据量量一大,即使 nodejs 直接读文件解析,不经过 db ,也会消耗很大资源。
    VchentozV
        20
    VchentozV  
       2 天前 via iPhone
    @skallz 我一般就是这么做的
    kivmi
        21
    kivmi  
       2 天前
    从大数据处理基本都是 map-reduce ,所以,这么直接查询原始数据,总感觉有些不妥
    iamtuzi3333
        22
    iamtuzi3333  
    OP
       2 天前
    @nivalxer 我是每个传感器一个表,返回的文档长度不超过 16M 吗,有更好的方案可以分享一下。
    @hd10180 他格式没有这么多,就是固定的 data 数组,要么 50,100,200 ,是根据采样率来定的。传感器也没有 uuid 全靠自己编。
    @yyt6801 data 数组就是 50 或者 100 或者 200 个浮点数,每秒的数据都是这样。
    @sagaxu 是的,我现在只统计了每秒的最大值,最小值,平均值,读取起来还不算太费劲。正常来说我们只关注十分钟这个节点,还有每分钟数据,这个都还算好用处理。文件确实,主要是读取文件比较麻烦,文件目录不固定,没有很好的索引方式。
    @kivmi 是的,但是我们的数据也不算大,就是多,频繁,每秒都有,直接查询原始数据出来也是为了做进一步处理,比如取出每一分钟的最大值,最小值,均值,方差这一些。
    nivalxer
        23
    nivalxer  
       2 天前
    我们这边行业比较特殊,对接 PLC 走场站这块,虽然 PLC 站控那边数据是实时的,我们采集远传还是以间隔来走的,所以数据量不会太多,在 10 秒频率下,按天走也不会超过 16M 。这个 16M 是输出文档大小,如果采用分页查询等,输出文档不超过 16M 也没啥问题。
    数据库我们暂时还是 mongodb 还没改,计划后面改,还没测试其他方案。
    我们行业场景,其实客户不会关注每秒的数据情况,所以大部分时间客户查的小时表(每小时一条取样)和统计表(小时、日、月)这两种,压力就还好。少量在出报警、统计到处等场景才会查完整历史数据。
    可以按客户场景来处理。如果客户有每条数据必须存和频繁的查询需求,在不过多改动现有技术架构情况下,可能看看其他数据库比较合适。
    fishman231
        24
    fishman231  
       2 天前
    MongoDB 也是有时序集合,可以使用 TTL 索引自动删除过期文件.另外时序集合可压缩数据,这样是否可以所有数据都存数据库呢
    pangzipp
        25
    pangzipp  
       2 天前
    mongodb 本身有数据压缩
    你能够实现 3 天以前数据读本地文件文件, 那也可以在 mongodb 里分表。

    可以评估下计划投入的资源,成本多少?
    用自己熟悉的技术栈
    iamtuzi3333
        26
    iamtuzi3333  
    OP
       12 小时 28 分钟前
    @nivalxer 挺好,后者历史数据我们很像,不过我就是还有一个实时数据的波形展示。
    @fishman231 我查询看看。
    @pangzipp 目前还没有实现三天以前读取本地文件,就是想这么做,看到一个方案就是只存储最近几天的数据,然后历史数据都存储到文件,查询历史数据通过读文件的形式去完成。MongoDB 分表我还不熟悉;技术栈都是啥好用简单方便就上啥了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3115 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 13:34 · PVG 21:34 · LAX 05:34 · JFK 08:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.