Spring集成Redis面试题库
生成时间:2026-05-22 22:28
【面试题】1. Redis的String类型底层编码有哪几种?什么条件下会转换?
【标准答案】 String类型有三种编码:int、embstr、raw。
- int:存储整数值且范围在long内(-2^63到2^63-1)
- embstr:字符串长度≤44字节,一次内存分配,obj和sds连续存放
- raw:字符串长度>44字节,两次内存分配,obj和sds分离
转换条件:整数运算结果超出long范围会转embstr;embstr做追加操作会转raw(因为embstr是只读的)。
面试加分点:Redis 3.2后embstr阈值从39改为44字节;int编码不完全是整数,要区分场景。
【面试题】2. Spring Data Redis中RedisTemplate和StringRedisTemplate有什么区别?生产中怎么选?
【标准答案】 核心区别:
- StringRedisTemplate继承自RedisTemplate<String, String>,强制String序列化
- RedisTemplate默认用JdkSerializationRedisSerializer,存入数据带类型信息,占用更大
生产选型:
- 推荐StringRedisTemplate,配合JSON序列化,跨语言通用
- 如果需要存复杂对象,自定义Jackson2JsonRedisSerializer
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}避坑:用默认JDK序列化,Redis-cli看到的是乱码,调试困难。
【面试题】3. Redis持久化RDB和AOF怎么选?线上怎么配置?
【标准答案】 RDB优点:文件小、恢复快、适合备份。缺点:可能丢数据(最后一次快照后的数据)。
AOF优点:数据更完整(默认每秒刷盘最多丢1秒)。缺点:文件大、恢复慢。
线上配置(推荐混合持久化):
save 900 1
save 300 10
save 60 10000
appendonly yes
aof-use-rdb-preamble yes
appendfsync everysec选型依据:
- 允许几分钟数据丢失:纯RDB
- 要求高可用、最多丢1秒:AOF或混合
- 纯缓存场景:可关闭持久化
面试加分:Redis 4.0后混合持久化成为默认推荐,兼顾恢复速度和数据完整性。
【面试题】4. Spring Cache的@Cacheable注解如何配置TTL?能动态设置吗?
【标准答案】 基础配置:
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(factory).cacheDefaults(config).build();
}动态TTL方案:
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
Map<String, RedisCacheConfiguration> cacheConfig = new HashMap<>();
cacheConfig.put("user", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)));
cacheConfig.put("product", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1)));
return RedisCacheManager.builder(factory)
.withInitialCacheConfigurations(cacheConfig)
.build();
}使用时指定cacheNames:@Cacheable(value = "user", key = "#id")
【面试题】5. 缓存穿透、缓存击穿、缓存雪崩分别是什么?怎么解决?
【标准答案】 缓存穿透:查询不存在的数据,请求直达数据库。
- 解决:布隆过滤器拦截、空值缓存(TTL设短)
缓存击穿:热点key过期瞬间大量请求打到数据库。
- 解决:互斥锁(只让一个线程查库)、逻辑过期(不删缓存,后台异步更新)
缓存雪崩:大量key同时过期或Redis宕机。
- 解决:TTL加随机值、多级缓存(本地+Redis)、熔断降级、Redis集群高可用
实战代码(互斥锁防击穿):
public String getWithMutex(String key) {
String value = redisTemplate.opsForValue().get(key);
if (value != null) return value;
String lockKey = "lock:" + key;
try {
boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (locked) {
value = queryFromDB(key);
redisTemplate.opsForValue().set(key, value, 30, TimeUnit.MINUTES);
} else {
Thread.sleep(50);
return getWithMutex(key); // 重试
}
} finally {
redisTemplate.delete(lockKey);
}
return value;
}【面试题】6. Redisson分布式锁的看门狗机制是什么?为什么要它?
【标准答案】 背景:锁设置过期时间后,如果业务执行超时,锁自动释放,其他线程获取锁,导致并发问题。
看门狗机制:Redisson默认锁30秒,后台线程每10秒检查一次,如果锁还被当前线程持有,自动续期到30秒。
核心源码逻辑:
RLock lock = redissonClient.getLock("myLock");
lock.lock(); // 默认30秒,自动续期
// 或
lock.lock(10, TimeUnit.SECONDS); // 手动指定时间,不续期避坑点:
- 手动指定leaseTime会关闭看门狗
- 看门狗在业务异常退出时也能正常释放(持锁线程数为0时删除锁)
- 程序崩溃时锁会在30秒后自动释放
面试加分:提Redisson实现是Lua脚本保证原子性,可重入锁用hash结构存线程ID和重入次数。
【面试题】7. Redis Cluster为什么用16384个槽位?节点通信用啥协议?
【标准答案】 为什么16384:
- 槽位太少:节点多时分配不均匀
- 槽位太多:节点握手时传递的槽位信息包太大(心跳包携带每个槽位归属)
- 16384是权衡值:支持最多1000节点,每个节点心跳包最大约1KB
节点通信协议:Gossip协议。
- 每个节点随机选部分节点交换信息
- 包含:节点状态、槽位映射、故障检测信息
- 频率:每秒10次,避免广播风暴
槽位迁移:
CLUSTER SETSLOT 1000 IMPORTING sourceNodeId
CLUSTER GETKEYSINSLOT 1000 100 # 获取槽位下的key
# 逐个迁移key
CLUSTER SETSLOT 1000 NODE targetNodeId面试加分:提CLUSTER ADDSLOTS分配槽位,MOVED重定向是客户端缓存槽位映射的原理。
【面试题】8. 用Redis实现限流,固定窗口、滑动窗口、令牌桶有什么区别?
【标准答案】 固定窗口:简单但临界问题(1秒末+下1秒初可能突发2倍流量)。
local count = redis.call('INCR', KEYS[1])
if count == 1 then redis.call('EXPIRE', KEYS[1], ARGV[1]) end
return count滑动窗口:精确但内存占用大,用ZSET存储每个请求时间戳,ZRANGEBYSCORE统计窗口内请求数。
local now = tonumber(ARGV[1])
redis.call('ZREMRANGEBYSCORE', KEYS[1], 0, now - tonumber(ARGV[2]))
local count = redis.call('ZCARD', KEYS[1])
redis.call('ZADD', KEYS[1], now, now)
redis.call('EXPIRE', KEYS[1], ARGV[2])
return count令牌桶:允许突发流量,更灵活。Redisson内置RRateLimiter。
选型:
- API限流:滑动窗口或令牌桶
- 简单场景:固定窗口
- 高性能场景:本地Guava限流 + Redis分布式限流结合
【面试题】9. Spring Session + Redis实现分布式Session共享的原理是什么?
【标准答案】 核心原理:
- Filter拦截请求,从Redis获取Session(按Session ID)
- 请求结束自动将Session变更写回Redis
- 多服务节点共享Redis,实现Session共享
配置:
@EnableRedisHttpSession
public class SessionConfig {
@Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory();
}
}存储结构:
- Key:
spring:session:sessions:sessionId - Hash结构存储:creationTime、lastAccessedTime、maxInactiveInterval、attrs
注意事项:
- Session对象需要序列化
- 配置TTL(maxInactiveIntervalInSeconds)
- 大流量场景注意Redis压力,可结合本地缓存
面试加分:提Spring Session支持多种存储(Redis/JDBC/Mongo),同时支持WebSocket。
【面试题】10. Redis的BigKey和HotKey问题怎么排查和解决?
【标准答案】 BigKey问题:
- 定义:String超过10KB,集合元素超过5000个
- 危害:内存不均衡、网络阻塞、删除时卡顿
排查:
redis-cli --bigkeys
MEMORY USAGE key解决:
- String类型:压缩(GZIP/Snappy)或拆分
- 集合类型:按业务维度拆分(如用户ID取模)
- 删除:UNLINK异步删除(4.0+)
HotKey问题:
- 定义:单Key访问量极高
- 危害:单节点压力过大、甚至超时
排查:
- 代理层统计(Twemproxy)
- 客户端统计
- Redis 4.0 hotspot功能(需开启)
解决:
- 本地缓存:Caffeine/Guava Cache
- 复制HotKey到多个节点(加后缀)
- 拆分为多个Key分散请求
实战:秒杀场景库存Key拆分为10份,用户随机路由。
共10题