1、什么是缓存穿透?
缓存穿透是指查询一个一定 不存在 的数据,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到 DB 去查询,可能导致DB 挂掉。这种情况大概率是遭到了攻击。解决方案的话,我们通常都会用布隆过滤器来解决它。
2、布隆过滤器是什么?
Redis 布隆过滤器(Bloom Filter)是一种数据结构,用于快速判断一个元素是否存在于一个集合中。布隆过滤器可以高效地判断一个元素是否可能存在于集合中,但无法确定元素是否一定存在于集合中。布隆过滤器通常用于减少在查询大型数据集时的IO操作,或者作为缓存等场景的一种辅助数据结构。
布隆过滤器的核心是一个位数组(bit array)和多个哈希函数。当一个元素被加入布隆过滤器时,将这个元素分别通过多个哈希函数计算出多个哈希值,并将位数组中对应的位置置为1。当判断一个元素是否存在于布隆过滤器中时,同样通过多个哈希函数计算出多个哈希值,并检查对应位置是否都为1,如果都为1,则认为元素可能存在于集合中;如果有任意一个位置不为1,则可以确定元素一定不存在于集合中。
布隆过滤器的优点是占用内存空间较少,并且判断效率高。但缺点是存在一定的误判率,即可能将不存在的元素误判为存在。误判率取决于位数组的大小和哈希函数的数量,可以通过调整这些参数来控制误判率。
Add:下面是一个代码举例:
import org.redisson.Redisson; import org.redisson.api.RBloomFilter; import org.redisson.api.RedissonClient; import org.redisson.config.Config; public class RedissonBloomFilterExample { public static void main(String[] args) { // 创建 Redisson 客户端连接 Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); // 创建布隆过滤器,预计容量为10000,误判率为0.01 RBloomFilter<String> bloomFilter = redisson.getBloomFilter("myBloomFilter"); bloomFilter.tryInit(10000L, 0.01); // 添加元素到布隆过滤器中 bloomFilter.add("element1"); bloomFilter.add("element2"); bloomFilter.add("element3"); // 判断元素是否存在于布隆过滤器中 System.out.println(bloomFilter.contains("element1")); // true System.out.println(bloomFilter.contains("element4")); // false // 关闭 Redisson 客户端连接 redisson.shutdown(); } }
3、什么是缓存击穿?
缓存击穿的意思是对于设置了过期时间的 key ,缓存在某个时间点过期的时 候,恰好这时间点对这个Key 有大量的并发请求过来,这些请求发现缓存过期一般都会从后端 DB 加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把 DB 压垮。
4、介绍
SETNX
命令的使用?下面举一个具体的例子:
import redis import time # 连接 Redis r = redis.Redis(host='localhost', port=6379, db=0) # 锁的名称 lock_name = 'my_lock' # 尝试获取锁,设置锁的超时时间为 10 秒 lock_acquired = r.setnx(lock_name, 'locked') r.expire(lock_name, 10) if lock_acquired: print('成功获取锁') # 这里可以进行一些需要加锁的操作 time.sleep(5) # 释放锁 r.delete(lock_name) print('释放锁') else: print('获取锁失败')
在这个示例中,如果第一个客户端执行时没有其他客户端持有锁,那么它将成功获取锁,并且设置了一个 10 秒的超时时间。在这段时间内,其他客户端尝试获取锁会失败。当锁不再需要时,客户端会删除该键,释放锁。
5、缓存穿透和缓存击穿有什么区别?
缓存穿透:是指查询一个不存在的数据,由于缓存无法命中,每次请求都直接访问数据库,导致数据库负载过大。缓存穿透通常是由于恶意攻击或者系统设计不当导致的,解决方式是在查询前进行参数校验或者使用布隆过滤器等技术来过滤掉无效的请求,从而避免直接访问数据库。
缓存击穿:是指一个存在的key在缓存失效的时刻,同时有大量的并发请求访问这个key,导致所有请求都穿透缓存,直接访问数据库,造成数据库负载过大。缓存击穿通常是由于缓存失效时未采取有效措施导致的,解决方式是在缓存失效时使用互斥锁或者热点数据预加载等方式来避免大量请求同时访问数据库。
6、Redis的数据过期策略有哪些?
定时删除(Eviction):当设置了过期时间的键在到达过期时间时,会被从数据库中删除。定时删除是 Redis 最基本的过期策略。
惰性删除(Lazy Expire):只有当获取某个键的时候才会检查其是否过期,如果过期则会被删除。惰性删除减少了不必要的检查,但可能导致过期键在一定时间内仍然存在于数据库中。
定期删除(Expiration):每隔一段时间,Redis 会随机抽取一些设置了过期时间的键进行检查,删除过期的键。定期删除通过限制删除操作的执行时长和频率,避免了在单次删除操作中删除大量过期键,减少了对 CPU 的影响。
过期键检查(Expired Keys):Redis 使用一个独立的线程来检查过期键,并删除过期的键。过期键检查将过期键的删除操作分摊到不同的时间段,避免了在定期删除时可能出现的大量删除操作。
7、Redis分布式锁如何实现 ?
获取锁:使用 SETNX 命令尝试将某个唯一标识符作为键设置到 Redis 中,作为获取锁的标识。如果返回值为 1,表示获取锁成功;如果返回值为 0,表示获取锁失败。
设置锁的过期时间:为了避免锁忘记释放而导致死锁,可以为锁设置一个过期时间。可以使用 EXPIRE 命令为锁设置一个适当的过期时间。
释放锁:使用 DEL 命令删除锁,释放资源。在释放锁时,需要确保只有持有锁的客户端才能释放锁,以避免误删其他客户端的锁。
下面是一个简单的 Java 示例代码,演示了如何使用 Redis 实现分布式锁:
import redis.clients.jedis.Jedis; public class RedisLock { private Jedis jedis; public RedisLock(Jedis jedis) { this.jedis = jedis; } public boolean tryLock(String lockKey, String requestId, int expireTime) { String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime); return "OK".equals(result); } public void unlock(String lockKey, String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; jedis.eval(script, 1, lockKey, requestId); } public static void main(String[] args) { Jedis jedis = new Jedis("localhost"); RedisLock lock = new RedisLock(jedis); String lockKey = "mylock"; String requestId = "request1"; int expireTime = 10000; // 过期时间为10秒 // 获取锁 boolean isLocked = lock.tryLock(lockKey, requestId, expireTime); if (isLocked) { System.out.println("获取锁成功"); // 执行业务逻辑 // 释放锁 lock.unlock(lockKey, requestId); } else { System.out.println("获取锁失败"); } jedis.close(); } }
8、redis的redisson框架介绍?
Redisson 是一个基于 Redis 的 Java 驱动框架,提供了许多方便易用的功能和特性,使得在 Java 应用中使用 Redis 变得更加简单和高效。Redisson 提供了许多功能,包括分布式对象、分布式集合、分布式锁、分布式调度器等,使得开发人员可以更轻松地利用 Redis 实现各种分布式应用。
Redisson 的主要特性包括:
- 分布式对象:Redisson 提供了一系列分布式对象,如分布式锁、分布式原子对象、分布式计数器等,可以帮助开发人员快速构建分布式应用。
- 分布式集合:Redisson 提供了一系列分布式集合,如分布式列表、分布式队列、分布式集合等,可以方便地进行集合操作。
- 分布式锁:Redisson 提供了可重入锁、公平锁、联锁等多种锁机制,可以帮助开发人员解决分布式环境下的并发控制问题。
- 分布式调度器:Redisson 提供了分布式调度器,可以方便地进行任务调度和执行。
- 支持哨兵模式和集群模式:Redisson 支持 Redis 的哨兵模式和集群模式,可以灵活地应对不同的部署环境。
- 支持异步操作:Redisson 提供了异步接口,可以方便地进行异步操作,提高系统性能和吞吐量。
总的来说,Redisson 是一个功能丰富、易用的 Redis Java 驱动框架,可以帮助开发人员更轻松地利用 Redis 构建分布式应用,并提高应用的性能和可靠性。
9、Redis集群有哪些方案?
在 Redis 中提供的集群方案总共有三种:主从复制、哨兵模式、Redis 分片集群。Add:下面介绍其中的哨兵模式:Redis 哨兵模式是用于监控 Redis 主从复制集群并在主节点下线时自动进行故障转移的一种机制。在 Redis 哨兵模式中,会有一组 Sentinel 运行,它们负责监控 Redis 主节点和从节点的状态,并在需要时执行故障转移操作。
主要特点包括:
监控:Sentinel 定期检查 Redis 主节点和从节点的状态,如主节点是否正常运行、从节点是否在正常复制等。
通知:当发现 Redis 的主节点下线或者有其他故障发生时,Sentinel 可以向管理员发送通知。
故障转移:如果主节点下线,Sentinel 会自动将一个从节点提升为主节点,并通知其他从节点切换复制源。
配置提供:Sentinel 可以在主节点下线后自动更新其他节点的配置,使其连接到新的主节点。
选举:Sentinel 使用选举算法选出新的主节点,确保整个集群在主节点故障后仍能正常工作。
通过 Redis 哨兵模式,可以实现 Redis 集群的高可用性和自动故障恢复,提高了 Redis 的可靠性和稳定性。