redis缓存穿透之setnx使用场景

本文探讨了业务增长和高并发下引入Redis缓存的重要性,着重讲解了缓存穿透问题及其影响,如数据库连接超时。提出了利用Redis的setnx命令实现进程锁,确保在缓存失效时只有一个进程读取数据库并更新缓存,从而避免大量请求对数据库造成冲击。通过这种方式,以空间换时间,提高系统效率。

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

    随着业务的增长,请求并发的增大。很多公司在业务场景中会增加缓存策略,而缓存用的最多的也就是redis了。

    今天我们来说一下缓存穿透,我们缓存一般是有时效性的,一定的生命周期过去之后就会消失,一般的系统不会设置永久性的存储,这时候就会遇到一个问题,要么就是主动刷新缓存,要么就是程序被动刷新缓存。

    事实证明很多程序当中很少主动刷新因为你要去写脚本,定时去刷新数据,这样的话代价比较大。所以较多的就选择了程序被动刷新缓存,就是在缓存失效之后读库在写入缓存。这里就会导致一个问题那就是:当缓存失效的那一刻大量的请求过来就会直接打到数据库上,如果并发量大的话读库操作肯定会有影响,连接超时,连接数过大这样的情况也会随时遇到。

    针对这种情况redis有一个进程锁也就是我们今天说的setnx

    下面直接贴代码:

    $ret = $this->redis->get(
<think>嗯,用户想了解Redis在电商平台的应用场景和最佳实践。首先,我需要回忆一下之前提到的引用内容,看看有哪些相关的信息可以整合进来。比如引用[2]提到购物车数据存储在Redis中,确保一致性和实时性;引用[4]讲到了页面缓存和数据库查询缓存;引用[5]提到了使用sorted set存储用户关系,以及缓存商品列表等。这些都可能和电商场景相关。 接下来,我应该先列出电商平台常见的使用场景,比如购物车、商品缓存、秒杀活动、页面缓存、分布式锁、用户关系等。然后针对每个场景,结合引用中的具体实现方式,比如购物车用Hash结构,商品信息用String或Hash,秒杀用原子操作和Lua脚本,页面缓存用String存储HTML,分布式锁用SETNX,用户共同好友用sorted set的交集操作。 然后需要考虑最佳实践部分,这部分需要涵盖缓存策略、数据结构选择、持久化与内存管理、高可用架构、缓存问题处理(穿透、击穿、雪崩),以及监控和性能优化。引用[3]提到了缓存击穿时使用分布式锁,引用[1]提到Redis Cluster的高可用方案,这些都需要融入进去。 在结构上,先分应用场景,每个场景下说明实现方式并给出示例代码,再总结最佳实践。要注意使用中文,并且行内公式用$...$,不过可能这个问题里公式用的不多,但如果有的话需要注意格式。同时要生成相关问题,可能用户后续会问到缓存策略的具体细节或者如何解决缓存问题等。 需要确保引用的正确标注,例如购物车部分引用[2],页面缓存引用[4],分布式锁引用[3],用户关系引用[5],Redis Cluster引用[1]。检查每个引用是否恰当,是否有遗漏。比如秒杀部分的原子操作可能没有直接引用,但属于常见实践,可以不用标注。此外,注意代码示例的正确性,比如购物车的hset和hgetall,以及分布式锁的set命令参数。 最后,生成的相关问题要围绕用户可能感兴趣的扩展,比如缓存策略的选择、高并发优化、数据一致性、缓存问题解决方案、性能监控等。确保问题具体且有引导性,帮助用户深入理解。</think>### Redis缓存在电商平台的应用场景及实现方式 #### 一、核心应用场景与实现 1. **购物车数据存储** - **场景**:用户购物车需要实时更新且支持高并发访问,同时需保证分布式系统下多实例的数据一致性。 - **实现**:使用 Redis 的 Hash 结构存储用户购物车信息,Key 为用户 ID,Field 为商品 ID,Value 为商品数量和属性。 - **示例代码**: ```python # 添加商品到购物车 redis.hset("cart:user1000", "product123", "{'quantity': 2, 'price': 299}") # 获取购物车全部商品 cart_data = redis.hgetall("cart:user1000") ``` - **优势**:Hash 结构支持快速字段操作,适用于频繁修改的场景[^2]。 2. **商品详情页缓存** - **场景**:高频访问的商品信息(如价格、库存)需快速响应,减少数据库压力。 - **实现**:将商品数据序列化为 JSON 格式,通过 String 或 Hash 结构缓存,设置合理过期时间(如 10 分钟)。 - **示例代码**: ```python product_key = "product:123" if not redis.exists(product_key): product_data = db.query("SELECT * FROM products WHERE id=123") redis.setex(product_key, 600, json.dumps(product_data)) else: product_data = json.loads(redis.get(product_key)) ``` - **优化**:结合本地缓存(如 Caffeine)形成二级缓存架构[^4]。 3. **秒杀/限时抢购** - **场景**:高并发下需保证库存扣减的原子性和防超卖。 - **实现**: - 使用 Redis 的原子操作(如 `INCRBY`)扣减库存。 - 通过 Lua 脚本实现复杂逻辑(如库存预扣、订单状态更新)。 - **示例代码**: ```lua local stock_key = KEYS[1] local stock = tonumber(redis.call('GET', stock_key)) if stock > 0 then redis.call('DECR', stock_key) return 1 -- 扣减成功 else return 0 -- 库存不足 end ``` 4. **页面静态化缓存** - **场景**:首页或活动页内容频繁访问但变化较少,可通过缓存 HTML 片段提升加载速度。 - **实现**:将生成的 HTML 内容直接存入 Redis使用 Key 标识页面类型(如 `page:homepage`)[^4]。 5. **分布式锁控制** - **场景**:防止缓存击穿时大量请求穿透到数据库。 - **实现**:通过 `SET key value NX EX` 实现分布式锁,确保只有一个请求重建缓存[^3]。 - **示例代码**: ```python lock_key = "lock:product:123" if redis.set(lock_key, "locked", nx=True, ex=5): try: # 重建缓存逻辑 finally: redis.delete(lock_key) ``` 6. **用户关系与推荐** - **场景**:计算共同好友或商品相似度。 - **实现**:使用 Sorted Set 存储用户行为(如浏览记录),通过 `ZINTERSTORE` 计算交集[^5]。 --- #### 二、最佳实践 1. **缓存策略设计** - **读写策略**:采用 Cache-Aside 模式,优先读缓存,失效时异步回源。 - **过期时间**:动态调整 TTL(如热点数据延长,冷数据缩短),避免集中失效导致雪崩[^4]。 2. **数据结构选择** - **高频更新数据**:使用 Hash 或 String。 - **排序需求**:优先使用 Sorted Set(如销量排行榜)。 3. **持久化与内存管理** - **混合持久化**:开启 RDB+AOF 保证数据可靠性,同时监控内存碎片率。 - **淘汰策略**:设置为 `volatile-lru`,优先淘汰过期 Key 防止 OOM。 4. **高可用架构** - **集群模式**:使用 Redis Cluster 实现数据分片和自动故障转移[^1]。 - **多级缓存**:结合本地缓存(如 Caffeine)减少 Redis 访问延迟。 5. **缓存问题处理** - **穿透**:对空值设置短 TTL 或使用布隆过滤器拦截无效请求。 - **击穿**:通过分布式锁控制并发重建。 - **雪崩**:分散 Key 过期时间,或使用熔断机制降级。 6. **监控与调优** - **指标监控**:关注命中率(>95%)、内存使用率、慢查询。 - **Pipeline 优化**:批量操作减少网络开销(如批量获取商品信息)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值