1. Redis的Red Lock是什么
Red Lock 是一种分布式锁的实现方案,旨在解决分布式环境中使用Redis实现分布式锁时的安全性问题。
一般情况下,我们在生产环境中会使用主从+哨兵方式来部署Redis。
如果我们正在使用redis分布式锁,此时发生了主从切换,但是从节点不一定已经同步了主节点的锁信息。
所以新的主节点上可能没有锁的信息,此时,另一个业务去加锁,一看锁还没被占,于是抢到了锁开始执行。此时就发生了两个竞争者同时进入临界区操作临界资源的情况,发生数据不一致问题。
Redis官方推出了红锁,避免这种状况发生,主要解决的问题就是当部分节点发生故障也不会影响锁的使用和数据问题的发生。
1. 红锁的实现原理
首先要使用红锁需要集群部署Redis,官方推荐至少5个实例,不需要部署从库和哨兵,只需要主库。
客户端会对这5个实例依次申请加锁,如果最终申请成功的数量超过半数,则表明加锁成功,反之失败。
2. 红锁一定安全吗
- 如果client1获得了锁,但是此时业务逻辑处理很长,redis的锁过期了,此时client2也在此时拿到了锁,开始执行后续逻辑,发生数据不一致问题。
- 除了gc,如果出现时钟漂移,例如几个redis实例时间跳跃,导致锁提前到期了,也可能会造成client抢到了锁。
2. Redis实现分布式锁可能遇到的问题有哪些
- 业务未执行完,锁已到期
- 单点故障问题
- 主从问题不同步问题:Redis主节点获取到锁之后,还没同步到其他从节点,Redis宕机了。
- 网络分区问题:网络不稳定的情况下,客户端和Redis的连接可能中断,如果未设置锁的过期时间,可能会导致锁无法正常释放。如果有多个锁,还可能引发锁的死锁问题。
- 时钟漂移问题:可以让所有节点的系统时钟通过NTP服务进行同步,减少时间漂移的影响。
- 锁的可重入性问题
- 误释放锁问题
3. Redis中的缓存击穿、 缓存穿透和缓存雪崩是什么
缓存击穿:指某个 热点数据在缓存中失效
,导致大量请求直接访问数据库。此时,由于瞬间的高并发,可能导致数据库崩溃。
缓存穿透:指 查询一个不存在的数据,缓存中没有相应的记录
,每次请求都会去数据库查询,造成数据库负担加重。
缓存雪崩:指 多个缓存数据在同一时间过期,导致大量请求同时访问数据库
,从而造成数据库瞬间负载激增。
解决方案:
- 缓存击穿:
- 使用互斥锁,确保同一时间只有一个请求查询数据库并更新缓存
- 热点数据永不过期
- 缓存穿透
- 使用布隆过滤器,过滤掉不存在的请求,避免直接访问数据库
- 对查询结果进行缓存,即使是不存在的数据,也可以缓存一个标识,减少对数据库的请求。
- 缓存雪崩
- 采用随机时间过期策略,避免大量数据同时过期
- 使用双缓存策略,将数据同时存储在两层缓存中,减少数据库直接请求。
4. Redis中如何保证缓存和数据库的一致性
- 先更新缓存,在更新数据库
- 先更新数据库,在更新缓存
- 先删除缓存,再更新数据库,后续等查询把数据库的数据回溯到缓存
- 先更新数据库,在删除缓存,后续等查询把数据库的数据回溯到缓存
- 缓存双删策略,更新数据库之前,删除一次缓存;更新完数据库后,在进行一次延迟删除。
- 使用binlog异步更新缓存,监听数据库的binlog变化, 通过异步方式更新Redis缓存。
以上是实现数据库与缓存一致性的六种方式,前三种不推荐使用。后面三种根据实际场景考虑
- 如果是考虑实时一致性的话,先写MySQL,再删除Redis是较为优的方案,虽然短期内数据可能不一致,但是能尽量保证数据的一致性。
- 如果考虑最终一致性的话,推荐使用binlog+消息队列的方式,这个方案有重试和顺序消费,能够最大限度保证缓存和数据库的最终一致性。
5. 如何使用Redis快速实现排行榜
使用Redis实现排行榜主要利用 Sorted Set(有序集合)
,他可以高效的存储、更新以及获取排名数据。
实现排行榜的主要步骤:
- 使用Sorted Set存储分数和成员
使用Redis的 zadd 命令,将用户和对应的分数添加到有序集合中。例如,zadd leaderboard 1000 user1- 获取排名
使用zrank命令获取某个用户的排名。zrank leaderboard user1- 获取前N名
使用zrevrange命令获取分数最高的前N名,例如:zrevrange leaderboard 0 9 withsocres- 更新分数
如果用户的分数需要更新,可以使用zincrby命令对其分数进行加减操作。例如:zincrby leaderboard 500 user1
Sorted Set的特点
- Sorted Set是Redis中的一个数据结构,内部使用
跳表
实现,提供按分数排序的功能,每个成员有一个唯一的分数,根据分数进行排序。- Redis的Sorted Set 通过O(logN) 的时间复杂度进行插入、更新、删除操作,且可以通过范围查找快速获取指定区间的数据。
- 使用Sorted Set可以确保成员唯一性,因为Redis的Sorted Set中每个成员都是唯一的,如果添加相同的成员,zadd将更新其分数而不是重复插入。
6. 如何使用Redis快速实现布隆过滤器
布隆过滤器是一种高效的数据结构,常用于检测一个元素是否在一个集合中,可以有效减少数据库的查询次数,解决缓存穿透问题。
可以通过使用位图或者使用Redis模块RedisBloom。
- 使用位图实现布隆过滤器
- 使用Redis位图结构setbit和getbit操作来实现布隆过滤器。位图本质上是一个比特数组,用于表示元素是否存在。
- 对于给定的数据,通过多个哈希函数计算位置索引,将位图中相应位置设置为1,表示该元素可能存在。
- 使用RedisBloom模块
- redis官方提供了一个redisBloom,封装了哈希函数,位图大小等操作,可以直接用于创建和管理布隆过滤器。
- 使用 bf.add 来向布隆过滤器添加元素,使用 bf.exists 来检查某个元素是否可能存在。
7. 你在项目中使用的Redis客户端是什么
- Jedis适用于简单的同步操作和单线程环境
- Lettuce适用于高并发、高性能和多线程环境,尤其是需要异步和响应式编程的场景
- Redission适用于复杂的分布式系统,提供丰富的分布式对象和服务,简化开发
8. Redis字符串类型的最大值大小是多少
Redis字符串的最大容量是512M。无论是网络传输、内存分配还是字符串操作,大字符串都会增加Redis服务器的负载。
且过大的字符串在get、set、append等操作都会导致性能瓶颈
所以官方给字符串的大小做了限制,防止单个键值对占用过多的内存,影响整体性能和稳定性。
9. Redis性能瓶颈时如何处理
如果Redis无法承受当前负载的话,可以考虑以下解决方法
首先是 扩容
,比如增加Redis的配置,容纳更多的内存。
如果超过单机配置了,那么可以上 redis主从,通过从服务分担读取数据的压力
,利用哨兵自动进行故障转移。
还可以利用 redis集群进行数据分片
,比如redis cluster。
也可以增加本地内存,通过 多级缓存
分担redis的压力。
10. Redis中原生批处理命令(MSET、MEGT)和pipeline的区别是什么
原生批处理命令(mset、mget)和pipeline都可以用于一次性处理多个命令,但是他们在实现方式和应用场景上有所不同。
- mset/mget(原生批处理命令)
- mset和mget是redis提供的原生批处理命令,用于批量设置和获取多个键值。
他们是单个命令
,可以一次操作多个键值对,因此,只需要进行一次网络往返,适合对多个键值进行原子性的读写操作。
- pipeline
- pipeline是Redis提供的一种机制,
允许客户端一次发送多个命令
,Redis会批量处理这些命令,然后将结果依次返回。Pipeline可以大幅度减少网络延迟,因为他一次性发送多个命令,避免了每次命令都等待回复的网络往返时间。 - pipeline并不是一个单一的redis命令,而是一种机制,适用于任意类型的redis操作,非原子性。
注意事项
- mset/mget的局限性:他们只能用于批量的写入和读取键值对,无法用于执行其他类型的redis操作。
- pipeline的内存消耗:当使用pipeline时,如果命令数量特别大,可能会导致redis服务端和客户端的内存消耗增加,因为pipeline会将所有的命令暂存在内存中等待发送或者处理。
- 错误处理:在pipeline中,如果某些命令失败,开发者需要通过返回值判断哪些命令执行成功,哪些失败。由于pipeline是将多个命令批量发送,因此无法在中途停止执行。