我的redis学习感悟

        既然高并发下面操作I/O的代价很大,那我们就尽量在数据打到DB前操作好,然后再传给数据库,这样就有利于高并发

        而且还有一个问题,如果像秒杀,可能有多个事务同时查到后端的数据,再执行操作,这样就是不安全的,所以考虑Lua脚本,因为他是单线程,全程原子执行不会被插队

        还有一个问题,如果我们的数据存在多个服务器上面,若校验逻辑写在 Java 代码里,每台服务器代码一旦改漏、写错,就会出现漏洞,所以Lua 脚本固定存在 Redis,所有服务共用同一套校验扣减逻辑,规则统一,不会出现各机器判断标准不一样的问题。

总结:优惠券秒杀需要查询库存、逻辑判断、扣减库存三步绑定在一起不被打断,普通分步查询会并发超卖;Lua 脚本在 Redis 服务端原子执行整套逻辑,无间隙、少网络开销,完美解决优惠券超发问题。

        对于Lua来说前面修改的数据永久生效,不会自动撤销,所以回退是我们自己手动写代码做反向操作恢复数据。但是写反向操作是不方便的所以应该

        先校验所有条件,最后再修改数据(不用回退)

对于如果 Lua 脚本已经执行成功,但后续订单消息发送到 Kafka 失败,应该怎么处理?

问题根源:Redis Lua 操作和 Kafka 消息发送分属两个中间件,无法原子执行,Lua 执行成功后消息发送失败会导致库存预扣但无订单,数据不一致。

核心解决思路:不能依赖 Lua 回滚,需通过可靠消息机制保证消息一定送达,搭配定时补偿兜底。

主流实现方案: (1)基础重试:发送失败多次重试,仅适用于测试 / 低并发; (2)本地消息表(推荐):数据库事务落库订单 + 消息记录,定时任务补发失败消息,下游消费实现幂等防重复; (3)Kafka 生产者事务:保证消息要么全部入队,要么全部丢弃,但需配合消息表处理 Redis 库存不一致问题; (4)TCC 分布式事务:预扣库存,消息发送成功确认扣减,失败则调用 Lua 脚本回退库存,强一致性。

兜底机制:定时任务核对 Redis 库存与数据库订单,对库存多扣、无对应订单的数据,执行补偿 Lua 脚本恢复库存,彻底解决数据不一致。

© 版权声明

相关文章