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