Redis实现唯一(去重)队列

本文探讨了在使用Redis作为任务队列时遇到的重复任务问题,并提出了四种解决策略,包括利用List和Set的组合、仅使用List进行去重、在入队前检查元素是否存在,以及使用有序集合的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相关场景:用Redis的List做任务队列,但是有时候任务还没处理到,某些地方超时又来了一条相同的任务,但List本身是支持重复元素的,这个时候需要对队列去重。

 

方法一:同时使用List和Set。

入队列时,同时入List和Set

lpush [key] [member]
sadd [key] [member]

出队列时,判断元素是否在Set中并将其在Set中删除。若不在Set中,忽略此次出队操作。

rpop [key]
sismenber [key] [member]
srem [key] [member]

 

方法二:只使用List,但是出队后删除掉List中相同的元素。

入队列时,同时入List和Set

lpush [key] [member]

出队列时后,删除队列中相同的此次出列的元素。数字0代表移除所有为member的元素。

rpop [key]
lrem [key] 0 [member]

 

方法三:只使用List,入队前判断元素是否在队列中。

暂时没发现List中直接判断元素是否已经存在的命令,这种判断的命令可以自己用其他逻辑的代码实现。但要值得注意的是,不要先删除掉List中相同的元素后再将此元素Push进去,这样可能会导致此元素一直在队尾,没机会Pop出去。

 

方法四:有序集合。

有空再写

### 使用 Redis 实现秒杀功能 Redis 是一种高性能的键值存储数据库,特别适合用于高并发场景下的数据处理。在秒杀场景下,Redis 的原子性和高效性能可以有效解决库存超卖和高并发请求的问题。 #### 秒杀的核心原理 秒杀的主要挑战在于高并发访问可能导致资源竞争和库存超卖。通过 Redis 的 `INCR` 和 `DECR` 命令,可以在毫秒级时间内完成对共享资源的操作,并利用其原子性特性防止多线程冲突[^1]。 以下是基于 Redis 实现秒杀功能的关键点: 1. **库存扣减** 使用 Redis 的 `DECR` 或者 Lua 脚本来实现库存的安全扣减。如果库存小于等于零,则拒绝后续请求。 2. **订单** 防止同一用户多次提交请求导致复下单,可以通过设置用户的唯一标识(如用户 ID)作为 key 来限制。 3. **限流保护** 利用 Redis 的计数器功能或者滑动窗口算法来限制单位时间内的请求数量,从而缓解服务器压力。 4. **异步通知** 对于未能成功抢购到商品的用户,可通过消息队列机制发送延迟通知或补偿策略。 --- #### 示例代码 以下是一个简单的 Java 代码示例,展示如何使用 Redis 实现秒杀功能: ```java import redis.clients.jedis.Jedis; public class SeckillService { private Jedis jedis; private String stockKey = "seckill:stock"; // 库存key private String userOrderPrefix = "seckill:user:"; // 用户订单前缀 public SeckillService(String host, int port) { this.jedis = new Jedis(host, port); } /** * 尝试购买商品 * * @param userId 用户ID */ public void tryToBuy(long userId) { // 检查用户是否已经购买过该商品 String userOrderKey = userOrderPrefix + userId; if (jedis.exists(userOrderKey)) { System.out.println("用户已参与秒杀"); return; } // 执行Lua脚本确保事务一致性 String script = "local currentStock = tonumber(redis.call('get', KEYS[1]));" + "if not currentStock or currentStock <= 0 then " + "return 'soldout'; end;" + "redis.call('decr', KEYS[1]);" + "redis.call('setex', KEYS[2], 60, 1);" // 订单有效期设为60秒 + "return 'success';"; Object result = jedis.eval(script, 2, stockKey, userOrderKey); if ("success".equals(result.toString())) { System.out.println("秒杀成功!"); } else if ("soldout".equals(result.toString())) { System.out.println("商品已售罄!"); } } public static void main(String[] args) { SeckillService service = new SeckillService("localhost", 6379); long userId = 1L; // 测试用户ID service.tryToBuy(userId); } } ``` 上述代码中,我们使用了 Lua 脚本来保证库存扣减和用户标记的一致性,避免因网络延迟或其他原因造成的数据不一致问题[^3]。 --- #### 性能优化建议 1. **预加载库存** 在活动开始之前预先将库存加载至 Redis 中,减少冷启动带来的额外开销。 2. **分片设计** 如果单机 Redis 存储无法满足需求,可以考虑采用 Redis Cluster 进行水平扩展[^4]。 3. **缓存穿透防护** 对不存在的商品信息进行布隆过滤器校验,降低无意义查询的压力。 4. **持久化配置** 启用 AOF 日志模式并定期备份要数据以防丢失。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值