缓存雪崩、击穿、穿透的原因与解决方法
缓存不一致的原因,解决方法
Redis做分布式锁
-
单一Redis实例做分布式锁
- SET lock_key 客户端唯一标识 PX 10000 NX(如果lock_key不存在就创建,value为客户端唯一标识,10秒过期)
- Lua脚本判断和删除(保证读取、判断、删除原子性)
redis-cli --eval unlock.script lock_key , unique_value
(执行unlock脚本,传入参数)
-
高可用多个Redis实例做分布式锁
- Redlock算法(获取超过一半Redis实例锁的数量)
- 获取第一个锁的时候记录时间戳
- 一次加锁(给加锁操作设置一个超时时间,防止某个Redis故障)
- 获取到最后一个锁的时候获取时间戳
- 相减不能超过锁的过期时间则有效。
- 释放锁和单一Redis实例一样
Redis的事务
Redis 的事务机制可以保证一致性和隔离性,但是无法保证持久性。不过,因为 Redis 本身是内存数据库,持久性并不是一个必须的属性,我们更加关注的还是原子性、一致性和隔离性这三个属性。原子性的情况比较复杂,只有当事务中使用的命令语法有误时,原子性得不到保证,在其它情况下,事务都可以原子性执行。
Redis主从集群、切片集群
主从:
切片:
哨兵集群
- 监控:
- 哨兵检测主库超时,判定主观下线,发起投票。
- 如果赞成票>quorum值,标记主库客观下线。
- 选主:
- 选举:发起选举,投自己一票。同时超过半数并且>=quorum值则执行选主。
- 筛选:筛掉网络差的和已经客观下线的
- 打分:
- 优先级最高的
- 同步程度最高的
- id最小的
- 通知其他从库与客户端
Redis删除机制、淘汰策略
Redis如何支撑秒杀
秒杀场景对 Redis 操作的根本要求有两个。
- 支持高并发。这个很简单,Redis 本身高速处理请求的特性就可以支持高并发。而且,如果有多个秒杀商品,我们也可以使用切片集群,用不同的实例保存不同商品的库存,这样就避免,使用单个实例导致所有的秒杀请求都集中在一个实例上的问题了。不过,需要注意的是,当使用切片集群时,我们要先用 CRC 算法计算不同秒杀商品 key 对应的 Slot,然后,我们在分配 Slot 和实例对应关系时,才能把不同秒杀商品对应的 Slot 分配到不同实例上保存。
- 保证库存查验和库存扣减原子性执行。针对这条要求,我们就可以使用 Redis 的原子操作或是分布式锁这两个功能特性来支撑了。我们先来看下 Redis 是如何基于原子操作来支撑秒杀场景的。
- 使用分布式锁来支撑秒杀场景的具体做法是,先让客户端向 Redis 申请分布式锁,只有拿到锁的客户端才能执行库存查验和库存扣减。
- 我们可以使用切片集群中的不同实例来分别保存分布式锁和商品库存信息。使用这种保存方式后,秒杀请求会首先访问保存分布式锁的实例。如果客户端没有拿到锁,这些客户端就不会查询商品库存,这就可以减轻保存库存信息的实例的压力了。