给老哥们提个需求, 大佬过来设计下,给个方案 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xboxv
V2EX    问与答

给老哥们提个需求, 大佬过来设计下,给个方案

  •  
  •   xboxv 2022 年 7 月 13 日 1572 次点击
    这是一个创建于 1287 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需求背景: 手机端实时展示 每个 店铺的 当天交易流水总值。 也就是后端实时推送 键值对( shopId, dayBill:该店铺的当前交易总额)数据给手机端。

    dayBill 不需要你去统计,你只需要监听 上游的 mq 交易消息,mq 消息中会传递 shopId 和这个店铺当前累计交易额。 你需要做的内容仅仅是将这个数据推给 手机端,底层通信业不需要关心。

    一个店铺 当前可能没有交易订单, 也可能每秒有上千个订单。 因此 一个店铺的消息可能会有很多。 你需要设计 内容就是 如何 保证 客户端能够实时拿到消息 且服务端不会频繁推送消息。也就是流控设计。允许延迟大概在 5 秒。 你可以假想成 手机客户端 App 有一个 列表,列表的内容 就是店铺的 id 和当前该店铺当天累计交易额。

    我提供三种方案供参考:

    ( 1 )第一种方案:手机端定时拉取数据, 方案不通过!

    ( 2 )第二种方案:redis 中 使用 zset 存放数据,member 是 shopid, score 是当前时间戳。 当接收到店铺的交易消息(消息内有店铺当前累计交易额)的时候 更新 zset 中指定 memeber 的 score 。 然后定时任务每隔 3 秒 取出 score 小于(当前时间戳-3 秒 )的 member ,将这些 member 的 交易信息推送给客户端。 方案不通过: 不通过的原因是, 假设这个店铺每隔 1 秒就有一个交易订单, 那么 监听 mq 消息直接更新 zset 会导致 score 一直递增, 因此会导致这个 店铺的交易额 迟迟无法推送给 手机端的问题,也就是消息推送不够及时。

    从这个方案中我们看出来 监听的第一条店铺消息一定是要推送给手机端的,只不过这条消息 记录的交易额可能并不是最新的。

    ( 3 )延迟队列。 监听到的 mq 交易消息 放入延迟队列,队列 中元素 equals 判断的逻辑是 shopid 相等。因此只要 店铺的第一个交易额 进入队列,后续的交易消息不回进入队列。同时需要已收到的消息中的记录店铺的最大交易额。 另外一个线程 定期 3 秒从 延迟队列中取出数据。 目前这个方案 尚可满足需求。

    归纳: 其实这个需求的设计的 就是 ( 1 )压缩重复的消息 ( 2 )尽可能保证实时推送。 老哥们有没有 在哪些源码中看过类似的需求? 能给个代码参考吗?实现不是问题,想看下别人怎么设计的

    12 条回复    2022-07-14 11:18:49 +08:00
    LeeReamond
        1
    LeeReamond  
       2022 年 7 月 13 日
    设置一个推送保护呗,A 店铺默认状态无保护,第一笔交易实时推送,每次推送完成时给店铺附加一个 3 秒的保护状态,未来三秒里要发送的消息都先缓存下来,结束时统一推送,然后重复这个过程。随着次数增多可以增大保护区间,比如第一次 3 秒一推,而后 3.4, 4, 4.5, 5
    ql562482472
        2
    ql562482472  
       2022 年 7 月 13 日
    手机直接订阅 mqtt 有什么问题吗 我没有看出来需要再做其他操作的必要?
    xboxv
        3
    xboxv  
    OP
       2022 年 7 月 14 日
    @ql562482472 理论上可以 ,方案 应该不行, 不会为了这个搞个 mqtt 。
    xboxv
        4
    xboxv  
    OP
       2022 年 7 月 14 日
    @LeeReamond
    我猜测: 第一个消息 实时推送,并在 redis 打标 过期 3 秒, 后面的消息 发现 redis 有记录则 本地缓存。 然后 定时任务 扫描本地缓存,redis 中没有 key 则推送本地缓存的数据? 感觉方案可以。
    xboxv
        5
    xboxv  
    OP
       2022 年 7 月 14 日
    大佬们有没有 在哪里 源码看过类似的设计?
    LeeReamond
        6
    LeeReamond  
       2022 年 7 月 14 日 via Android
    @xboxv 为什么总要轮询,直接加到期回调就行了,你们业务量真的大到无法负担定时回调开销?我质疑。没什么源码,这需求太简单了哪有人没事记这种源码。。
    cheng6563
        7
    cheng6563  
       2022 年 7 月 14 日
    手机自己把消息 ID 存库把重复消息忽略不行?
    xboxv
        8
    xboxv  
    OP
       2022 年 7 月 14 日
    @LeeReamond redis 的过期监听回调吗? 这个方案确实没想到。 这个方案应该评估不过的, 一方面是 redis 的过期本身是惰性的,定期扫描或者你主动 get key 的时候才发现过期, 时间没法保证。 另一方面 要修改中间件配置,redis 中间件可能不是一个团队在用,这个影响有点大。
    xboxv
        9
    xboxv  
    OP
       2022 年 7 月 14 日
    @LeeReamond 就目前 手机端已经是 18 秒主动 调一次后端 获取数据了,但是 18 秒延迟太大了, 所以设计后端推的服务。 https://juejin.cn/post/6844904158227595271 请勿过度依赖 Redis 的过期监听
    xboxv
        10
    xboxv  
    OP
       2022 年 7 月 14 日
    @cheng6563 手机端处理吗? 手机端不监听 mq 消息的,手机端只做展示。 问题是后端 主动推消息给手机端,并把控流控问题。
    LeeReamond
        11
    LeeReamond  
       2022 年 7 月 14 日 via Android
    @xboxv 你们团队什么水平啊。。你这是固定时长回调,就是个定时,分布式定时任务 mq 就能做啊,就算你用纯 redis ,那用通道监听也能回调啊
    xboxv
        12
    xboxv  
    OP
       2022 年 7 月 14 日
    @LeeReamond 呃呃呃。目前的方案就是定时呀,定时扫描队列数据处理。
    1. 你不是提到 ”直接加到期回调就行了 “么, 这个过期回调 应该是 业务被动回调吧? 我想到的就是 redis 的过期监听回调,这个方案不会通过的。原因上面说了

    2. mq 怎么做,mq 延迟队列吗? Rocketmq 的延迟队列都是固定延迟级别吧? 除非自定义延迟队列?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3269 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 00:37 PVG 08:37 LAX 16:37 JFK 19:37
    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