V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
xboxv
V2EX  ›  问与答

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

  •  
  •   xboxv · 2022-07-13 23:36:42 +08:00 · 1025 次点击
    这是一个创建于 645 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    2. mq 怎么做,mq 延迟队列吗? Rocketmq 的延迟队列都是固定延迟级别吧? 除非自定义延迟队列?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5115 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 08:15 · PVG 16:15 · LAX 01:15 · JFK 04:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.