求一个定时取消订单的解决方案

2020-05-05 10:23:23 +08:00
 yangyuhan12138
目前我们的方案是 rabbitmq 的死信队列,并发不高还好,但是我们最近会搞一波促销活动,订单超时时间是 35 分钟,意思就是有 35 分钟时间窗口的订单都会进入死信队列,害怕把 mq 弄挂了...或者说 rabbitmq 有没有啥水平扩容的方案,我们现在的模式为镜像模式,三台机器存的是一样的内容,所以消息的上限还是为单台机器的容量

还有一个方案是刚刚搜到的,就是 redis 的 zset,用时间戳当 score,这个方案感觉还挺不错呢,有没有人用过

大佬们多多给点建议 谢谢大家了
12880 次点击
所在节点    程序员
90 条回复
UFc8704I4Bv63gy2
2020-05-05 11:22:54 +08:00
这是有多少订单啊
yangyuhan12138
2020-05-05 11:27:33 +08:00
@wangyanrui nb 哈哈哈哈
yangyuhan12138
2020-05-05 11:28:31 +08:00
@cabing 好的...
yangyuhan12138
2020-05-05 11:29:07 +08:00
@weiqk 就那会儿高 要搞活动 秒杀
zzl22100048
2020-05-05 11:30:46 +08:00
单机 rabbit 128g 内存 5000 万消息还算正常
sanggao
2020-05-05 11:50:40 +08:00
百度: 环形定时任务

ps:一般的 cron 脚本解决方案也没什么压力吧?
ConradG
2020-05-05 11:57:57 +08:00
这个量一般确实是扛得住的,只要机器不太磕碜。
zrange 方案直观上会觉得很奇怪,因为最大可能你通过时间来取 key,然后你的场景下似乎大量 key 会集中在某个区间内。这就要求你能吃掉自己造出来的峰。
定时任务算是常规方案,它属于慢但是不会有什么坑的选择。特别你担心的是持久化问题,而用数据库做持久化则是最不用担心的。
ming7435
2020-05-05 12:23:25 +08:00
每一分钟跑一次关闭超时订单的任务可行否?
liyunlong41
2020-05-05 12:28:27 +08:00
后台 worker 一直扫库感觉可行,不过要给订单状态和下单时间做个联合索引,保证扫库时用到索引不会扫很多无用的行,但是数据库中数据量大的话加索引是件很麻烦的事……而且最好保证 worker 只有一个。

Redis 做延时队列如果挂了可能存在丢消息的风险,必须有补偿机制。

用 mq 延时消息感觉最合适,不过消费 mq 也可能有重复的消息?如果有的话做好消息幂等就好了。感觉 mq 可能遇到的问题 1 是 mq 容量和性能,这个要自己压测了; 2 是如果消费速度慢的话(数据库事务加互斥锁),实际关单时间要>规定时间。
liuhan907
2020-05-05 12:55:29 +08:00
如果消息队列要求用的时候出队必须大于入队,那用队列做什么呢…几十万的消息,只要不是每秒几十万,rmq 没问题的,机器不要太寒酸就行。另外这个问题主要是压测啊,试试不就什么都清楚了
nvkou
2020-05-05 13:06:44 +08:00
等等。我记得 redis 本身就有 key TTL 的啊。未支付订单过了 TTL 。直接 drop 不就是了
KasonPasser
2020-05-05 13:13:05 +08:00
我以前都是支付时才锁定减少库存。这种下单不支付的过期订单都是再次查询时判断过期时间直接释放掉就可以了。
yunshansimon
2020-05-05 13:30:05 +08:00
生成订单有序号,你不用一个订单一个任务,你可以 1 分钟生成一个 30 分钟后的任务,取消当前订单和之前的所有订单。
NoString
2020-05-05 13:31:22 +08:00
你这并发听着吓人,既然要依赖 mq 也要保证消息可靠,就得有对应的补偿策略.. zset 不推荐 一般这种定时任务就够了...,在订单的流转状态在加下代码判断最稳定。如果非要依赖 建议定时任务,消息队列肯定没定时任务可靠,比如楼上说的一分钟扫一次,给前端显示和有订单变更的接口加一下取消时间判断,其实就已经比较可靠了
realpg
2020-05-05 13:33:39 +08:00
这个逻辑,这个并发量(不超过 70 万的订单超时),曾经 MYSQL+redis 就无性能瓶颈抗住过
我觉得你的超时流程,在程序这边逻辑设计有问题
ty89
2020-05-05 14:20:38 +08:00
为啥定时取消就必须得进队列, 订单上增加一个过期时间字段不行吗?
xuanbg
2020-05-05 14:47:18 +08:00
@ty89 我们也是有一个过期时间,这样不同的订单可以有不同长度的付款时间窗口。过期处理也很简单,就是 5 分钟跑一次 SQL 把过期的且不在支付中的订单状态从待付款改成已关闭。然后订单在支付时需要实时判断是否已过期,没有过期的支付状态改为支付中,以免被批处理任务处理掉。
kisshere
2020-05-05 14:47:39 +08:00
你这订单量,天天双十一啊
Kyle18Tang
2020-05-05 14:51:19 +08:00
我们订单量不多, 也是下单的时候就进延时队列, 如果你们订单多, 可以通过定时任务去扫描即将超时的才去放入延时队列而不是下单的时候就放, 这样压力应该会小一些.
yangyuhan12138
2020-05-05 15:33:58 +08:00
@Kyle18Tang 我都起了定时任务 感觉就不用再放 mq 了吧 这样是不是有点多余了....
@kisshere 没 就瞬时 35 分钟 几十万订单应该正常吧 哪敢跟双十一比哦
@ty89 重点就是怎么定时去修改这个字段呀 他不会自己改过来
@realpg 就是 redis 的 zset 吗?
@KasonPasser 商城和支付是两个系统,这边创建订单成功了才会到支付系统,但是到了支付系统可能不支付,所以才这样做的
@nvkou 订单信息是入了库的..
@ConradG 这个还好 不是 zrange 一次取出来 他是取马上要过期的一条(zset score 当分数嘛) 然后处理 峰还是削了的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/668600

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX