设计: 一个统计设备上下线的方案 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
lanqing
V2EX    Python

设计: 一个统计设备上下线的方案

  •  
  •   lanqing 2021-03-30 11:56:43 +08:00 5496 次点击
    这是一个创建于 1706 天前的主题,其中的信息可能已经有所发展或是发生改变。
    假设有 10000 台设备,统计任意 A 天到 B 天的某设备 SN 的在线时长
    我能收到每台设备的上线下线消息。
    如何存储,如何查询,大佬们有啥方案么?

    本人不才,设计到 mysql 存储每台设备每天的上下线消息,但是不管是查询还是设计,都感觉丑陋无比,有啥更好的方案么?
    第 1 条附言    2021-03-30 16:23:58 +08:00
    还要能查询出最近一次 在线时长,离线时长
    39 条回复    2021-04-03 16:39:33 +08:00
    wangyuhang
        1
    wangyuhang  
       2021-03-30 12:18:04 +08:00 via Android
    你现在有哪几个方案,说下
    dapang1221
        2
    dapang1221  
       2021-03-30 12:22:21 +08:00   2
    能保证一个上线消息必定会受到一个下线消息吗?能的话一条记录两个字段,上线时间、下线时间,用这俩一减。不能保证的话,做心跳包机制,收到消息的数量 * 心跳包间隔就是在线时间
    vcfghtyjc
        3
    vcfghtyjc  
       2021-03-30 12:29:04 +08:00
    感觉问题描述的不太清楚呀。是要设计数据库,还是设计整个系统架构?
    opengps
        4
    opengps  
       2021-03-30 12:34:37 +08:00 via Android
    我也有过类似的设计,设计出来总感觉不完美,似乎关系型数据库用起来不匹配
    IvanLi127
        5
    IvanLi127  
       2021-03-30 12:47:54 +08:00 via Android
    今日每台设备每次上下线消息存 redis 或者数据库,次日定时统计。redis 用 list 存上线时间 下线时间,list key 日期+设备编号,应该差不多了
    oott123
        6
    oott123  
       2021-03-30 13:20:40 +08:00 via Android
    首先做个数据库,redis 还是 mysql 不重要,把设备 ID 存进去,在线状态设为不在线
    收到上线消息,去数据库里改成在线;下线消息同理

    然后配一个 Promethues,监控项是每台设备的当前在线情况

    搞完了,然后你想用什么时序数据库存想怎么查都可以
    xcstream
        7
    xcstream  
       2021-03-30 13:25:24 +08:00
    定义任务 每天计算一下所有设备的在线时长
    lanqing
        8
    lanqing  
    OP
       2021-03-30 14:05:42 +08:00
    @dapang1221 上线下线存一条消息,我担心 10000 台*100 天*10 次上下线 = 1000W 条数据,mysql 查询会不会有点性能问题
    lanqing
        9
    lanqing  
    OP
       2021-03-30 14:06:11 +08:00
    @vcfghtyjc 能够存储,能够查询就行了
    lanqing
        10
    lanqing  
    OP
       2021-03-30 14:08:46 +08:00
    @oott123 时序数据库能解决天到天的查询是么?我去看下
    scofieldpeng
        11
    scofieldpeng  
       2021-03-30 14:47:48 +08:00
    要统计在线时长,首先定义怎么判定在线这个过程,如果是设备会自动上报,

    你只有 1w 各设备,mysql 一张表就能解决,

    sn,first_report_time,last_report_time 这 3 个字段就可以完成你说的时长+统计,每个设备每天一条记录,当收到上报信息的时候,看下这张表 sn 有没有今日的记录,没有的话 insert,first_report_time,last_report_time 写入上报时间,有的话就只需要更新 last_report_time 就好了

    楼上说的普罗米修斯啥的,真没必要
    scofieldpeng
        12
    scofieldpeng  
       2021-03-30 14:49:34 +08:00
    一天 1w 条记录,就算跑一年也才 365w 条记录,这点量,太小了,随便玩
    Slartibartfast
        13
    Slartibartfast  
       2021-03-30 14:53:38 +08:00 via iPhone
    你这个用 MySQL 足够了,如果太大,就按照时间或者设备 id 分库分表。
    4kingRAS
        14
    4kingRAS  
       2021-03-30 15:24:08 +08:00
    id 一个表,device 一个表包括上线 timestamp 。下线 timestamp, 上下线的 log 一个表,记录 id,时间,动作。
    统计用 log 表在 Java 里统计。
    silencegg
        15
    silencegg  
       2021-03-30 15:26:26 +08:00
    CREATE TABLE `heart_beat` (
    `sn` varchar(50) DEFAULT NULL COMMENT 'sn',
    `start_time` varchar(50) DEFAULT NULL COMMENT '心态开始时间',
    `end_time` datetime DEFAULT NULL COMMENT '心跳结束时间',
    `online_time` bigint(20) DEFAULT NULL COMMENT '在线时长',
    `creat_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `reason` varchar(50) DEFAULT NULL COMMENT '原因'
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='心跳'
    silencegg
        16
    silencegg  
       2021-03-30 15:27:40 +08:00
    这个是之前我用 EMQ 监听设备上下线的表来统计设备在线时长
    4kingRAS
        17
    4kingRAS  
       2021-03-30 15:28:47 +08:00
    原来是担心一天内上下线次数太多啊,那就做个 trigger,log 表限制为只记录当日,0 点统计时长存入一个专门统计时间的表:id ,日期,第一次上线,最后一次下线,在线时长。虽然多了一个表,但是比较灵活。
    q149072205
        18
    q149072205  
       2021-03-30 15:41:20 +08:00
    还有一个问题,如果第一天上线一直没下线 ,到第二天下线你要怎么统计
    Lee2019
        19
    Lee2019  
       2021-03-30 15:42:29 +08:00
    用 influxdb 之类的 tsdb 呢?
    甚至直接写到 prometheus 里面?
    {sn="xxx", active=1/0}这种?
    LeeReamond
        20
    LeeReamond  
       2021-03-30 15:46:05 +08:00
    以天为单位展示就以天为单位储存,每天登录多长时间通过业务维护,整个系统很简单
    Kinnice
        21
    Kinnice  
       2021-03-30 16:09:09 +08:00
    下线时记录 时长
    zardly666
        22
    zardly666  
       2021-03-30 16:10:26 +08:00
    我目前做的是以某台设备某天为一条数据存储。限定到某台机器,某一天的上下线信息都只更新这一条数据。
    {
    "date": "2021-03-26",
    "online_sum": 40044000,
    "device_sn": "xxxxxxxxxx",
    "last_online_time": "2021-03-26 12:52:36",
    "last_status": "online",
    "merchant": "xxx"
    }
    ch2
        23
    ch2  
       2021-03-30 16:12:44 +08:00 via iPhone
    用 mongo 正好,数据类型简单的话存再多也能 cache 的住无压力
    lanqing
        24
    lanqing  
    OP
       2021-03-30 16:22:04 +08:00
    @zardly666 如果设备连续 3 天在线,这 3 天怎么统计的?
    lanqing
        25
    lanqing  
    OP
       2021-03-30 16:25:22 +08:00
    @Lee2019 后续优化会去考虑 tsdb,目前公司业务没有用到这个 db,而且赶工期,所以不尝试,哭
    lanqing
        26
    lanqing  
    OP
       2021-03-30 16:27:41 +08:00
    @silencegg 你这个能保证下线消息一定能够收到,或者能够处理成功么?如果不能,心跳结束时间永远不会更新
    zardly666
        27
    zardly666  
       2021-03-30 17:23:23 +08:00
    @lanqing 忘记说了。每天零点有一个调度任务:
    ①把零点时前一天最后状态仍为在线的,用零点的时间戳减去前一天最后一次上线时间的时间戳,加和进前一天这条记录的在线时长。
    ②插入一条这台机器,时间为今天的新数据,以今天零点为上次在线时长戳,在线时长为 0.
    zardly666
        28
    zardly666  
       2021-03-30 17:28:28 +08:00
    @lanqing 这样涉及有个弊端,就是想查看今天的在线时长,从记录查不出来,需要计算。

    比如机器从昨天一直开机,在今天早上零点产生了一条数据,今天零点为上次在线时长戳,在线时长为 0.

    需要用当前时间戳-今天凌晨的时间戳。
    redtea
        29
    redtea  
       2021-03-30 17:32:36 +08:00
    存 MongoDB,每隔几秒向服务器发送一次消息,超过时间视为离线。
    Maboroshii
        30
    Maboroshii  
       2021-03-30 18:43:00 +08:00
    心跳吧, 频率越高越精准 。 丢失心跳视为下线
    dapang1221
        31
    dapang1221  
       2021-03-30 18:54:14 +08:00
    @lanqing 才 1kw 条数据,太小看 mysql 了。。实在不行就分表,1w 台按照 id 平均分到 10~100 个表里,而且冷数据也能定期清掉或转移
    securityCoding
        32
    securityCoding  
       2021-03-30 18:56:22 +08:00
    往高大上的方向整就对了
    joesonw
        33
    joesonw  
       2021-03-30 19:03:07 +08:00
    influxdb 每在线 5 分钟, 插一条. 随便怎么统计.
    owenliang
        34
    owenliang  
       2021-03-30 19:10:42 +08:00 via Android
    spark 处理一下就好
    useben
        35
    useben  
       2021-03-31 09:35:46 +08:00
    心跳统计
    zm8m93Q1e5otOC69
        36
    zm8m93Q1e5otOC69  
       2021-03-31 09:48:11 +08:00
    我们是冗余了一张最新设备信息表
    LeeReamond
        37
    LeeReamond  
       2021-03-31 11:38:33 +08:00 via Android
    @dapang1221 1kw 慢明显是没优化,不用嘲讽楼主了。。不过话说回来 mysql 确实跟同类产品比性能不行啊,pg 和 oracle 大概 1kw 数据没优化硬顶也能顶住吧
    Lee2019
        38
    Lee2019  
       2021-03-31 12:20:58 +08:00 via Android
    @lanqing 不过感觉你们的场景天然就该用 tsdb
    SHSF
        39
    SHSF  
       2021-04-03 16:39:33 +08:00
    没人提 MQTT 吗
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2600 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 37ms UTC 09:15 PVG 17:15 LAX 01:15 JFK 04:15
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86