延时队列用 zset 加定时轮询实现,到点的消息平均晚十几秒才执行,量一上来延迟还在继续扩大。日志里能对上时间点,这种反而好排。
误差上限等于轮询间隔乘以单轮处理耗时,一次扫太多消息又把扫描本身拖长,误差一轮滚一轮越拉越大。这一点先确认清楚,后面就不用反复试。
redis-cli ZADD delay_q 1735689600 'order:1001' redis-cli ZRANGEBYSCORE delay_q -inf 1735689600 LIMIT 0 200 redis-cli ZREM delay_q 'order:1001'
「Redis 延时队列」确认了原因之后,改动尽量只碰那一处,顺手改的东西后面最容易出问题。线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。
日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。权限不要一口气开到最大,先加到够用再往上试,范围小才好收。
处理上按这个顺序:用 ZRANGEBYSCORE 只取到点的前 N 条 不要全量扫;扫描间隔压到秒级 同时限制每批处理的条数;取到之后先 ZREM 再投递 防止重复执行两次。
结果对不对很好判断,同一批延时消息的实际执行时间和设定时间差在两秒内。
