目录
Redis面试篇
1.什么是Redis?作用是什么?
Redis(Remote Dictionary Server)是一个基于内存的高性能 NoSQL 数据库,通常用于缓存、分布式存储 和 消息队列。它支持键值(key-value)存储,并且可以存储字符串、哈希、列表、集合、有序集合等多种数据结构
Redis 的主要作用
-
缓存(提高系统性能)
-
存储热点数据,减少数据库访问压力,提高查询速度。
-
例如:存储用户信息、文章内容、商品信息等,避免每次都查数据库。
-
-
分布式锁(保证并发安全)
-
在高并发场景下,多个线程/进程可能同时访问一个资源,Redis 的 SETNX、Redisson 可以实现分布式锁,防止数据冲突。
-
例如:限流、秒杀活动、库存扣减。
-
-
计数器和限流(防止系统被滥用)
-
适用于访问量统计、限流(如接口请求次数限制)。
-
例如:某接口 1 分钟内最多访问 10 次,超过就返回错误。
-
-
Session 共享(解决分布式会话问题)
-
在分布式系统中,多个服务器需要共享 Session(如用户登录状态),可以使用 Redis 统一存储。
-
-
消息队列(异步处理任务)
-
Redis 的
List
和Pub/Sub
可用于实现消息队列,提高系统吞吐量。 -
例如:订单系统 → 消息队列 → 异步处理支付、物流。
-
-
排行榜(游戏、社交场景)
-
Redis 的 有序集合(Sorted Set) 可以存储分数排名,如游戏积分榜、热搜榜。
-
2.什么是缓存穿透、缓存击穿、缓存雪崩
2.1缓存穿透
缓存穿透是指客户端频繁访问一些不存在的缓存数据,由于缓存中没有这些数据的记录,每次请求都直接访问数据库,导致数据库压力增大,但是数据库中也不存在(就是指大量请求不存在的资源,大量请求不存在的资源大概率就是被黑客攻击了......)
如何解决? 缓存空值:当查询一个不存在的key时,先访问缓存,缓存中没有访问数据库,数据库中也没有用的话就用redis做一个空标记 ,将空结果也写入缓存,并设置一个较短的过期时间 。下次再遇到相同的请求时判断是否存在空标记 key,存在这个空标记则直接返回缓存中的空值,避免再次查询数据库。(但这种标记过多的话会消耗资源,不推荐)
使用分布式锁:当请求发现缓存不存在时,可以使用分布式锁机制,避免多个相同的请求同时访问数据库。这样,只让一个请求去加载数据,其他请求等待,从而减轻数据库压力.
布隆过滤器:布隆过滤器是一种数据结构,在查询缓存和数据库之前,利用布隆过滤器来存储这个 key ,判断key是否存在,存在则直接放行.如果该key不存在则直接被拦截返回,不必查询缓存或数据库,节约存储空间。
对疯狂请求不存在数据的ip进行拉黑
缓存穿透无敌解决方法(能用上的方法全用上 ^_^ ) 布隆过滤器+空对象+分布式锁:
1.当缓存不存在时,先通过布隆过滤器进行初步筛选,
2.如果布隆过滤器判定数据可能存在,则检查是否存在空对象缓存。
3.如果空对象缓存不存在,再使用分布式锁防止多个相同请求同时访问数据库。
4.最后,如果数据库查询结果为空,将结果缓存为空对象,以防后续重复查询
2.2缓存击穿
缓存击穿是指某个热点数据在缓存中失效的瞬间有大量的并发请求同时访问该数据,由于该数据在缓存中失效,大量请求同时访问数据库,造成数据库压力骤增。这种情况通常发生在热点数据或访问频繁的数据上。
如何解决? 互斥锁机制:当缓存失效时,通过加锁的方式保证只有一个线程去查询数据库并更新缓存,其他线程等待缓存更新完成后再获取数据。
缓存不设置过期时间:对于极为重要的热点数据,可以设置其缓存永不过期,同时后台启动线程定期刷新该缓存,但如果重要的热点数据过多,不推荐此方法
监控热门数据,实时调整key的过期时长
2.3缓存雪崩
redis中大量key同时过期,导致大量请求直接访问数据库,瞬间引发数据库压力激增,甚至导致数据库崩溃。
如何解决? 缓存的过期时间使用随机值,这样减少了大量缓存同时过期的情况.
实时调整,监控哪些数据是热门数据,实时的调整key的过期时长.
使用锁机制,未获取锁的请求只能进行等待
3.redis如何持久化
Redis 是基于内存的数据库,但为了防止数据丢失,它提供了两种持久化机制:
-
RDB(Redis Database)—— 快照存储
-
AOF(Append Only File)—— 追加日志存储
1. RDB(快照存储)
原理:Redis 以二进制快照的形式将数据库的整个数据保存到磁盘文件(.rdb
)中,在发生故障时可以恢复。
特点:
✅ 适用于大规模数据的定期备份,恢复速度快。 ✅ 占用空间小,存储效率高。 ❌ 如果 Redis 意外崩溃,则最后一次快照之后的数据可能丢失。
2. AOF(追加日志)
原理:Redis 记录所有的写操作命令(如 SET
、DEL
),并将它们以日志形式(.aof
文件)追加到磁盘,Redis 重启时可重放这些命令恢复数据。
特点:
✅ 数据安全,即使 Redis 意外崩溃,AOF 也能最大限度减少数据丢失。 ✅ 适用于高实时性数据(例如:秒杀、交易系统)。 ❌ 日志文件较大,可能会影响 Redis 启动速度。
4.Redis 的过期策略和内存淘汰策略
Redis 作为内存数据库,存储空间是有限的,因此需要过期策略和内存淘汰策略来管理数据。
4.1 Redis 过期策略(如何删除过期数据)
Redis 允许设置键的过期时间(TTL),当键过期后,就会被删除。Redis 提供了 三种删除策略:
(1)定期删除(默认)
机制:Redis 每 100ms 进行一次过期键的扫描,随机检查一部分过期键,并删除过期的键。
✅ 优点:减少了系统负担,不会影响 Redis 性能。 ❌ 缺点:如果过期键过多,可能不会一次性删除完,导致内存占用增加。
(2)惰性删除
机制:当客户端访问一个键时,Redis 发现它已经过期,就会立刻删除这个键。
✅ 优点:仅在访问时删除,减少 CPU 负担。 ❌ 缺点:如果某些键一直不被访问,它们可能不会被删除,从而占用内存。
(3)定期删除 + 惰性删除(默认策略)
Redis 默认使用定期删除 + 惰性删除,既能避免频繁扫描,也能确保访问时自动删除过期键。
4.2Redis内存淘汰策略
如果 Redis 占满了可用内存,就需要删除一些数据来释放空间。Redis 提供了6 种内存淘汰策略:
策略名称 | 说明 | 适用场景 |
---|---|---|
noeviction(默认) | 不删除任何数据,直接报错(写入失败) | 适合持久化数据,不希望丢失 |
allkeys-lru | 删除最久未使用的键(全局 LRU) | 适用于缓存,需要高命中率 |
volatile-lru | 删除设置了过期时间的最久未使用键 | 适用于缓存+持久化混合场景 |
allkeys-random | 随机删除任何键 | 适用于无固定热点的场景 |
volatile-random | 只随机删除有过期时间的键 | 适用于部分数据需要持久化 |
volatile-ttl | 优先删除过期时间最短的键 | 适用于定期更新数据的场景 |
5.Redis的分布式锁
Redis 的分布式锁是一种基于 Redis 实现的分布式并发控制机制,用于保证多个进程或线程在分布式环境下对共享资源的互斥访问。
5.1 为什么需要分布式锁?
在分布式系统中,多个应用可能会同时操作同一个资源(如库存、订单等),导致数据不一致,这时就需要分布式锁来保证同一时间只有一个进程能执行操作。
示例问题
-
秒杀系统:多个用户同时抢购,导致库存超卖。
-
订单支付:用户 A 和 B 同时支付同一笔订单,可能出现重复扣款。
-
任务调度:多个服务器执行同一任务,可能导致任务被执行多次。
5.2 Redis 分布式锁的基本实现
使用 SETNX
(SET if Not Exists) 命令创建锁:
SETNX mylock "locked"
锁的基本实现
public boolean tryLock(String lockKey, String requestId, int expireTime) { String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime); return "OK".equals(result); }
✅ 解释:
-
lockKey
:锁的 key(比如"order_lock"
)。 -
requestId
:每个锁唯一的 ID,保证同一客户端能释放自己的锁。 -
"NX"
:只在 key 不存在 时才设置(保证互斥性)。 -
"PX expireTime"
:自动过期时间(避免死锁)。 -
"OK".equals(result)
:返回"OK"
表示加锁成功。
🔴 问题:
-
锁可能无法释放:如果服务崩溃,锁不会自动释放,导致死锁。
-
误删其他线程的锁:如果锁过期后被其他线程重新加锁,当前线程仍然认为自己持有锁,会误删别人的锁。
5.3分布式锁的优化
(1)设置锁的自动过期时间
防止死锁:
SET order_lock "locked" NX PX 10000
NX表示key不存在时才创建,保证互斥性
PX 10000 → 10 秒后自动释放锁
(2)使用 Redisson 实现分布式锁
Redisson 是 Redis 官方推荐的 Java 客户端,提供了高效的分布式锁实现:
RLock lock = redissonClient.getLock("order_lock"); try { lock.lock(10, TimeUnit.SECONDS); // 执行业务逻辑 } finally { lock.unlock();//释放锁 }
Redisson 优势:
自动续期(Watchdog 机制):如果持有锁的线程还在执行,Redisson 会自动延长锁的过期时间。 避免误删锁:保证释放的是自己的锁。
Redis 分布式锁核心要点:
-
使用
SETNX
+PX
设定锁的过期时间,避免死锁。 -
删除锁时使用 Lua 脚本,保证原子性。
-
使用 Redisson 进行优化,提供自动续期,避免误删锁。
-
适用于高并发场景(如秒杀、库存扣减),但可靠性不如 Zookeeper。
Redis 分布式锁虽然高效,但并非绝对可靠,建议使用 Redisson 或 Zookeeper 进行优化! 🚀