谢谢各位的指点 受教了 我再考虑一下用哪种方案 但是好像有点歪楼了 问题本意是为啥配置没打开依然能用
1 liupeng2579793 2022-07-11 20:23:12 +08:00 这问题消息队列不好吗 |
![]() | 2 dzdh 2022-07-11 20:24:26 +08:00 消息队列+1 |
3 Vkery 2022-07-11 20:25:41 +08:00 消息队列+2 |
![]() | 4 rrfeng 2022-07-11 20:31:24 +08:00 首先,redis 过期监听实现定时器很差劲,即不安全也不高效。 |
![]() | 5 rrfeng 2022-07-11 20:32:00 +08:00 ![]() 也用不到消息队列,看你订单量多少,大部分情况每分钟扫数据库就行了 |
6 crystom 2022-07-11 20:47:10 +08:00 ![]() config get notify-keyspace-events 看看 |
![]() | 8 itechify PRO redisson 延时队列?有个坑,客户端宕机重启,旧的 key 到时间不触发问题 |
![]() | 9 nightsky 2022-07-11 21:19:07 +08:00 几个订单啊?一天几万几十万这个量级的话,放个定时器去操作吧,贼快,还稳定 |
![]() | 10 reter 2022-07-11 21:28:15 +08:00 同建议定时任务,每次扫数据库就可以了。 等到数据量大,延时不能忍受的时候,再考虑其他优化方案。 |
11 demoshengxw 2022-07-11 22:14:35 +08:00 via iPhone 延时队列不是更好么 |
![]() | 12 JoseGuo OP 单体小项目 没集成 MQ 所以没使用消息队列 QZ 定时任务扫的话 每秒一次? 感觉比较浪费 |
![]() | 13 JoseGuo OP 延时队列持久化是个问题 宕机重启就没了 监听 redis 失效 key 肯定也会存在消息丢失问题 技术比较菜 望见谅 |
![]() | 14 luin 2022-07-12 00:03:36 +08:00 这路走得有点弯... keyspace 通知不是用来做这个的。你可以考虑用 redis 的 stream 来做消息队列,不需要额外的服务。 |
![]() | 15 wxw752 2022-07-12 00:09:33 +08:00 单体小项目也可以上 mq ,比较稳妥。 不会的话,可以去 B 站尚硅谷大学花几个小时学一下 |
![]() | 16 RedBeanIce 2022-07-12 00:33:31 +08:00 @JoseGuo 楼上说的没错,定时任务扫库就行了。请记住两点。 大前提:不是为了学习其他技术的情况下 1 ,请不要过度设计,选择当下最适合最简单的方案,当前的场景与性能而言,扫库是最适合最简单的方案吧 2 ,引入 mq ,redis 等中间件会加深你项目的维护难度 |
![]() | 17 haoliang 2022-07-12 04:14:28 +08:00 一个 daemon 就能搞定吧:进程启动时加载全量数据、使用时间轮进行任务排期、根据时间戳之类的 offset 增量添加数据。(单纯想想还挺简单的) |
![]() | 18 haoliang 2022-07-12 04:20:04 +08:00 忘了提虽然设想是单进程,但多线程 /协程是不可避免的 ... |
![]() | 19 ktqFDx9m2Bvfq3y4 2022-07-12 07:38:22 +08:00 via iPhone op 试试 dapr ,应该有延迟消息。 |
![]() | 20 Goooooos 2022-07-12 07:48:10 +08:00 ![]() 可以用 sortset ,定时扫描 element 是订单号,score 是过期的 timestamp 。 这样比直接扫数据库性能会好一点,相对消息队列简单点 |
21 bthulu 2022-07-12 08:06:38 +08:00 @RedBeanIce 你傻啊, 这是订单支付超时, 要精确到秒的, 你每秒扫一次库吗? |
22 NewExist 2022-07-12 08:20:17 +08:00 可以使用 redis 的消息队列。对于小项目升级成本不大 |
23 micean 2022-07-12 08:21:54 +08:00 单体小项目为什么还要花精力去维护 mq ? |
24 hoopan 2022-07-12 08:40:22 +08:00 传统做法就是 crontab 定期执行脚本扫表,如果业务量不大可以这样做。 建议是消息队列,用处多多,以后扩展也方便。消息队列有各类实现方法,redis 也能搞消息队列。 |
![]() | 25 xaplux 2022-07-12 08:44:24 +08:00 ![]() 单体应用,使用延迟队列实现就行,java 可以使用 DelayQueue ,然后每次重启服务,再从把表中未支付订单数据重新加载到延迟队列就行了 |
![]() | 26 cxshun 2022-07-12 08:49:07 +08:00 redis 的失效是延时的,它是依赖定时器和主动获取的时候判断的,不要依赖它来做业务,除非你不需要实时。 这种直接用延时队列就好了,RocketMQ 也有,或者自己用定时任务来处理。 |
27 zr8657 2022-07-12 08:58:49 +08:00 建议上个 mq ,熟练了也就半个小时的事,小规模一个单体 mq 就够了,基本也不用维护 |
![]() | 28 philchang1995 2022-07-12 09:02:29 +08:00 前面好几个人已经说过了 redis 的 key 过期机制用来做这种订单超时未支付自动取消的业务不太合适,刚好前几天看到一篇文章有对比实现这种业务的几种方法的优劣,你可以参考一下。https://mp.weixin.qq.com/s/TBOvb2BKdJUii-XDR50_YQ |
![]() | 29 JoseGuo OP @RedBeanIce 同意 |
![]() | 30 JoseGuo OP @philchang1995 我看一下 谢谢 |
![]() | 33 boks 2022-07-12 09:23:22 +08:00 我之前的做法是使用 redis 的有序集合,把过期时间存在 score 里,每秒查一次 score <= 当前时间戳 的数据 |
![]() | 35 awalkingman 2022-07-12 09:26:50 +08:00 楼上说维护的应该都是老手了。自己搞 demo 可以多尝试一些新技术新东西。生产如果量级不是很大,还是推荐扫表,越简单越好维护,越好调试和排查问题。 开发只是需要几天,维护是没有尽头的。 |
36 tusj 2022-07-12 09:49:11 +08:00 就查订单展示的时候,判断一下状态 + 时间不就好了吗?为啥要引入 redis ? |
![]() | 37 oppoic 2022-07-12 09:49:16 +08:00 定时扫库不行,即便到下一次扫库间隔只有一分钟,用户端也无法接受这么长的延迟 redis 自动过期更不行,redis 过期自动删除 key 实现的没那么严谨,网上有文章分析过这个 “订单到时未支付,自动取消” 这是一个经典面试题,我提供几个不一样的思路: 1 )插入订单表的时候,就有个未支付关闭时间(比如下单时间后的 15 分钟,这个做成可配置的) 2 )用户端一般可以看到 “未支付倒计时”,倒计时结束了,发请求让服务端关订单(服务端做些验证) |
![]() | 38 qinxi 2022-07-12 09:49:42 +08:00 @bthulu #21 冷知识. 你可以把 now+1min 时间前需要处理的都扫出来, 已经过期的直接处理, 未来 1 分钟内过期的你可以放队列延时处理 比如 netty 的 HashedWheelTimer |
![]() | 40 so1n 2022-07-12 10:00:57 +08:00 公众号看多了把...哪些说监听 key 过期的都是没生产经验的 |
41 flashBee233 2022-07-12 10:03:11 +08:00 37 楼的 2 )思路也可以 ,比如规定的是超过 30 分钟未支付订单超时,10:00 下单 10:30 超时 前端检测当前时间是否超过 10:30 且是未完成的订单,但这又依赖前端的请求前端不打开这个页面就不会执行这个操作 |
![]() | 42 jucelin 2022-07-12 10:05:37 +08:00 定时扫,业务上也配合判定下时间 |
![]() | 43 JoseGuo OP 破案了 确实现在开启的配置是 notify-keyspace-events AE 并不是"" |
45 bthulu 2022-07-12 11:20:24 +08:00 @qinxi 更冷的知识, 一分钟数据量有没有可能会把内存撑爆呢? 比如日志类的, 每条数据算 10k, 每秒一千人访问, 每人 10 条日志, 就是 100M. 一分钟就是 6G. |
![]() | 46 nekoneko 2022-07-12 11:27:01 +08:00 体量不大的话 1. 时间轮 2. 定时任务 3. 延时队列 |
47 fifa899 2022-07-12 11:28:13 +08:00 MQ 队列.延迟消费才是正解.redis 都用了.广播通知,延迟消息还是交给 MQ 比较专业 |
49 ccppgo 2022-07-12 11:41:52 +08:00 订单过期时间 + 定时任务才是正解吧 复杂度最低 |
![]() | 50 qinxi 2022-07-12 11:48:10 +08:00 @bthulu #45 你要是非得来杠, 即使每分钟 10 万订单这种方式也可以解决, 思路就是缩短时间 10s 15s 30s 根据情况来. 你已经每分钟 10 万订单了开 50 台机器处理不过分吧? 你算算我现在每台机器多少数据呢? 这种问题需要处理数据分配而已. 分发节点负责把 10 万的 id 分发给 50 个节点不复杂吧? |
![]() | 51 lesismal 2022-07-12 12:20:42 +08:00 redis 通知是存在的问题,比如通知的瞬间,刚好你监听事件的这个服务与 redis 断线了、没收到通知。 时间+定时任务判断处理订单状态就行了。 这里的时间与隔壁帖子根据当前时间计算当前体力、而不是定时去计算更新增加后的体力的玩法其实是类似的。 可以考虑记下这个词:COW(copy on write),其实本质就是只在真正需要的时候才去触发实际操作、尽量减少成本的浪费。 |
![]() | 52 liudaolunhuibl 2022-07-12 13:50:37 +08:00 redis 的这个 key 通知机制不太好,建议用消息队列的延时队列或者自己实现一个时间轮算法,总之需要的效果就是达到一段时间之后再去检查状态 |
53 wu00 2022-07-12 14:07:00 +08:00 肯定是上“定时任务”调度器,一般都提供延时任务。 比如 quartz 、sidekiq 、hangfire 之类的,能统计、执行结果、重试。 自己用 redis/mq 实现一套耗时耗力还不靠谱 |
54 wu00 2022-07-12 14:16:48 +08:00 下单的同时创建一个 delayjob ,xx 分钟后执行,第三方组件去负责调度就行了。 你只管控制 delayjob 里面并发和幂等,未支付就关闭,其他状态就忽略,几乎能控制在秒级,下单并发大你就不会在这提问了。 |
![]() | 55 nilai 2022-07-12 15:24:09 +08:00 redis 的 key 的过期机制 并不是完全精确的过期, 它内部有算法,比如每次按一定的百分比来进行抽样。 这样有可能会导致明明已经过期的 key, 但是它还存在于 redis 中 |
![]() | 56 VisionKi 2022-07-12 15:57:41 +08:00 前段时间也在找类似的解决方案,楼主的方案在于如果宕机了就无法监听到了,最后用了 redis 的 zset 实现。 实现方法: 存入订单的 id ,以过期时间的时间戳为 score 。只需要每秒取出分数小于当前时间戳的 id ,再异步处理业务即可。 有个问题就是 zset 没有类似 LPOP 的原子性操作,不能取出删除一步到位,不过对于单机应用来说也够用了。 |