求一个定时取消订单的解决方案
还有一个方案是刚刚搜到的,就是 redis 的 zset,用时间戳当 score,这个方案感觉还挺不错呢,有没有人用过
大佬们多多给点建议 谢谢大家了
还有一个方案是刚刚搜到的,就是 redis 的 zset,用时间戳当 score,这个方案感觉还挺不错呢,有没有人用过
大佬们多多给点建议 谢谢大家了
如果单你说的几十万条订单消息,完全没压力
有这量还在考虑这玩意啊
开源的 rocketmq 能实现的定时 level 也有限,
如果一定要没容量限制, 就买云上的 mq, 比如 aliyun 上的 mq, 支持任意事件量级的延迟消息…
不过一般用 rabbitmq/redis 再加扫表防止遗漏都能解决了..
对所做的技术选型的约束需要有全面的了解啊。
你们需要压测下 rabbitmq 的性能。比如 mysql 非 ssd 单机读 2000,ssd6000,单机写 1000 ssd 单机 3000
rabbitmq 队列,业务场景比较单一,性能估计 50 倍以上于数据库,一般场景下应该是没问题。
比较这些量都不大。
半个小时 100 万 1000000/1800 平均峰值 555,预估最高峰值平均的 5 倍 ,就是 3000 以内。。。数据库都快能抗住了。。。别担心。
当然你可以使用 redis 异步做个备案也行。
想多存点就加内存呗,反正内存比程序员的时薪要便宜,hhh
出个测试报告给领导,同时需要附上你的备用方案。
但是,划重点:你需要有 1-2 个备用方案。涉及到金额,怎么过分小心都不为过。
ps:一般的 cron 脚本解决方案也没什么压力吧?
Redis 做延时队列如果挂了可能存在丢消息的风险,必须有补偿机制。
用 mq 延时消息感觉最合适,不过消费 mq 也可能有重复的消息?如果有的话做好消息幂等就好了。感觉 mq 可能遇到的问题 1 是 mq 容量和性能,这个要自己压测了; 2 是如果消费速度慢的话(数据库事务加互斥锁),实际关单时间要>规定时间。
当时是用阻塞语言写的,redis 就缓冲一下快速给确认,完事都怼 MYSQL 里去了
在前端和后端都做了特殊的优化,适应比较低性能的硬件解决问题 甚至很多逻辑都不依赖后端
跟你这个有关的,比如超时不能支付这个事,都不依赖后端。限时秒杀的接口是有验证码,有反秒杀器的逻辑,跟正常下单入口不一样,这里会生成特殊的订单号,自身验证支付有效期,能不能跳转支付网关选择,能不能拉起支付接口
而清理订单,依赖一个 delete from orders where STH limit 1,这个功能调用一次删 10 个过期订单,这个异步功能集成到了没一个非秒杀逻辑请求里,就是说,只要有一个人访问一次整个系统,就会删掉一条没用记录
2. 说下我的想法
– 2.1 轮询(定时):最简单做就是加一个字段,每隔一段时间轮询一次数据库,逐个处理(弊端:符合条件的订单数太多,处理比较慢)
– 2.2 用延时队列:直接放到队列里,多个消费者并行处理(弊端:订单数太多,mq 积压)
– 2.3 轮询 + 延时队列:就是 39L 提到的。不多余好吗,主你不是担心消息数太多,MQ 内存顶不住吗。这个方案就是把即将过期的提前一点入队列,解决了 2.2 和 2.3 的弊端
以上三种方法都没毛病,按实际需求选择。个人建议不要过度设计,怎么简单怎么来,提前优化就提前提高了系统复杂度。如果是我选择,就用 2.2 。
针对主的主题内容再聊聊我的一些看法:
3. rmq 的水平扩容?多加机器节点不就是水平扩容吗。主提到现在 3 个节点,且队列都设置为镜像模式。看样子架构师很没有安全感呢。一般来说一主一从就可以了,即镜像数量设置为 1 个节点,我认为是 ok 的。这样,随着节点的数的增加,就分摊到不同节点了。因此,主提到的“上限还是为单台机器的容量”这个麻烦,实则是自己给自己找的。
4. redis zset 方案。这个方案实则是自己实现了一套不怎么靠谱的延时队列,有现成的 delayQueue 不用,折腾这个是干啥?是有别的考虑吗。
5. RMQ 的延时队列,可以用插件实现,不需要自己用死信队列实现了。
从最坏的情况来考虑,所有订单都不支付。
流量就只有活动开始的一瞬间,然后每 35 分钟订单超时、继续下单。
流量最大的时候就是订单超时之后重复下单的那个时间段。按照几十万的订单量来计算的话,那个时间段会有几十万的订单被取消,同时又下了几十万的单。
这里就可以先拆分一下,订单被取消之后,库存异步入库,不实时入库可以降低极端情况下的压力。
订单超时之后并不一定要立刻取消的,只要检测一下超时之后不允许支付即可。
异步也可以采用削峰填谷的方式,一下子处理几十万订单受不了的话,每次只处理一部分就好了,处理完的订单再把库存入库。
然后起个定时任务,每隔半小时,就 select 所有 timespan = last_timespan 的订单,足以删除。
你也可以提高一下这个 timespan 的精度,做到每分钟删一次。
@niubee1 主的意思是主动更新订单状态 , 在订单相关操作判断订单有效期逻辑是必须的
p.s. 我觉得上面说用 过期时间 字段的方案更好
顺便说无论下单或者取消都是一个流程问题,怎么能归结为一个 update sql 呢,订单撤回,优惠撤回,库存撤回,这难道不是一个流程么
下单需要及时响应,取消订单不需要啊,你真的并发太高,短时间一般任务无法处理完,晚一点也不算啥问题啊,所以不要想太多
https://github.com/snower/forsun
之前做过的一个定时的服务,用在订单取消还是很方便的,使用 redis 持久化存储稳定性性能也还可以,秒级定时,不会出现并发累积的问题,但是吧要是你这种动辄几万几十万并发的可能还是不行,但是真这么高订单的全中国的没几个吧,算是一种思路吧
如果你瞬时有 10w 数据需要更新,按四台机器均摊下来每台处理 2.5w ?
不过需要注意流量二次波峰的问题,通常活动或者秒杀完事了以后如有 HPA 的话,集群缩容,这时候延时队列的满足条件请求过来可能会造成再次扩容