
我将围绕Redis在Java中的常见面试问题,结合实际应用场景与代码示例,为你全面梳理Redis相关知识,希望能助力你应对面试及实际开发需求。
Redis支持多种数据类型,包括String、List、Set、SortedSet、Hash、Bitmap等。以Jedis为例,在Java中操作Redis数据类型示例如下:
import redis.clients.jedis.Jedis;
public class RedisExample {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
// String类型操作
jedis.set("stringKey", "stringValue");
String stringValue = jedis.get("stringKey");
System.out.println("String value: " + stringValue);
// List类型操作
jedis.rpush("listKey", "value1", "value2", "value3");
System.out.println("List values: " + jedis.lrange("listKey", 0, -1));
// Set类型操作
jedis.sadd("setKey", "value1", "value2", "value3");
System.out.println("Set values: " + jedis.smembers("setKey"));
// Hash类型操作
jedis.hset("hashKey", "field1", "value1");
jedis.hset("hashKey", "field2", "value2");
System.out.println("Hash values: " + jedis.hgetAll("hashKey"));
// SortedSet类型操作
jedis.zadd("sortedSetKey", 1, "value1");
jedis.zadd("sortedSetKey", 2, "value2");
System.out.println("SortedSet values: " + jedis.zrange("sortedSetKey", 0, -1));
jedis.close();
}
}Redis单线程却具备高性能,主要原因如下:
Redis采用惰性删除和定期删除相结合的键过期删除策略:
Jedis jedis = new Jedis("localhost", 6379);
jedis.setex("expireKey", 10, "expireValue");// 设置键10秒后过期
// 模拟等待10秒以上
try {
Thread.sleep(11000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String expiredValue = jedis.get("expireKey");
System.out.println("Expired value: " + expiredValue);
jedis.close();在Java中使用Jedis设置键过期可以通过setex方法,该方法用于设置一个带有过期时间(单位为秒)的键值对。例如:
Jedis jedis = new Jedis("localhost", 6379);
jedis.setex("keyWithExpire", 60, "value");// 设置键60秒后过期
jedis.close();也可以通过set方法设置键值后,再使用expire方法单独设置过期时间:
Jedis jedis = new Jedis("localhost", 6379);
jedis.set("anotherKey", "anotherValue");
jedis.expire("anotherKey", 30);// 设置键30秒后过期
jedis.close();Redis的内存淘汰策略在内存不足时发挥作用,与过期键相互配合。当内存达到设置的最大内存限制(通过maxmemory配置)时,Redis会根据设置的内存淘汰策略(如volatile - lru、allkeys - lru、volatile - ttl等)来删除键,以释放内存。其中,volatile相关的策略只会从设置了过期时间的键中进行淘汰,而allkeys相关的策略则会从所有键(无论是否设置过期时间)中进行淘汰。例如,当使用volatile - lru策略时,Redis会从设置了过期时间的键中,选择最近最少使用的键进行删除,即使这些键还未过期,以此来腾出内存空间。
在Redis主从模式中,主节点负责处理所有写操作,包括键的过期删除。当主节点发现某个键过期时,会删除该键,并将删除操作同步给从节点。从节点本身不会主动检查和删除过期键,而是依赖主节点的同步指令(DEL命令)来更新自身的数据状态。因此,在Java代码中操作过期键时,需要确保在主节点上进行操作,以保证整个集群中数据状态的一致性。例如在使用Jedis进行集群操作时,要确保连接到主节点执行设置键过期等相关操作,否则可能会出现从节点数据不一致的问题。
在Java中可以借助Jedis实现一个简单的分布式锁:
import redis.clients.jedis.Jedis;
public class DistributedLock {
private static final String LOCK_KEY = "distributed_lock";
private static final String LOCK_VALUE = System.currentTimeMillis() + "_" + Thread.currentThread().getId();
private static final int EXPIRE_TIME = 10000; // 锁过期时间,单位毫秒
public static boolean tryLock(Jedis jedis) {
String result = jedis.set(LOCK_KEY, LOCK_VALUE, "NX", "EX", EXPIRE_TIME / 1000);
return "OK".equals(result);
}
public static void unlock(Jedis jedis) {
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, LOCK_KEY, LOCK_VALUE);
}
}使用时:
Jedis jedis = new Jedis("localhost", 6379);
if (DistributedLock.tryLock(jedis)) {
try {
// 执行业务逻辑
} finally {
DistributedLock.unlock(jedis);
}
}
jedis.close();在Spring Boot项目中,可以通过在配置文件application.yml中进行如下配置来设置Redis缓存的默认过期时间:
spring:
redis:
host: localhost
port: 6379
lettuce:
pool:
max - active: 8
max - idle: 8
min - idle: 0
max - wait: -1ms
cache:
cache - names: defaultCache
time - to - live: 3600000 # 过期时间,单位毫秒,这里设置为1小时也可以在代码中通过@Cacheable注解的expire属性针对不同的缓存方法设置不同的过期时间:
@Service
public class UserService {
@Cacheable(value = "userCache", key = "#id", expire = 1800000) // 设置该缓存2小时过期
public User getUserById(Long id) {
// 从数据库查询用户信息逻辑
}
}Redis事务可以将多个命令打包成一个原子操作,通过MULTI、EXEC、DISCARD等命令实现。事务中的命令要么全部执行成功,要么全部不执行。但事务不支持回滚,一旦事务中的某个命令执行失败,后续命令仍会继续执行。
Lua脚本则提供了更强大的功能,它可以在Redis服务器端执行一段Lua代码。Lua脚本具有原子性,在执行过程中不会被其他命令打断。相比事务,Lua脚本可以实现更复杂的业务逻辑,并且由于在服务器端执行,减少了网络开销。例如,在实现分布式锁的释放操作时,使用Lua脚本可以确保在判断锁的持有者和删除锁这两个操作的原子性,避免出现并发问题。
大Key(例如包含大量元素的List、Hash、Set等)过期删除时可能会导致Redis主线程阻塞,影响性能。解决方法如下:
UNLINK命令代替DEL命令,将大Key的删除操作放到后台线程执行,避免阻塞主线程。在Java中使用Jedis时,可以这样调用:Jedis jedis = new Jedis("localhost", 6379);
jedis.unlink("bigKey");
jedis.close();可以通过监控Redis的expired_keys指标来了解过期键的情况。在Redis客户端中,可以使用INFO stats命令获取相关统计信息,其中expired_keys表示累计过期的键的数量。在Java中,可以通过Jedis获取该指标:
Jedis jedis = new Jedis("localhost", 6379);
String info = jedis.info("stats");
String[] lines = info.split("\n");
for (String line : lines) {
if (line.startsWith("expired_keys")) {
System.out.println("Expired keys: " + line.split(":")[1]);
break;
}
}
jedis.close();也可以使用一些监控工具,如Prometheus结合Redis Exporter,将Redis的各项指标收集起来进行可视化监控,实时了解过期键的变化趋势,以便及时发现和处理过期键相关的性能问题。
以上内容有没有覆盖到你想要重点了解的Redis面试知识呢?要是你希望深入探讨某个具体问题,或者想补充新的面试题,都能随时告诉我。
Java,Redis, 面试题,Redis 数据类型,Redis 持久化,Redis 集群,Redis 缓存穿透,Redis 缓存雪崩,Redis 缓存击穿,Redis 事务,Redis 主从复制,Redis 哨兵模式,Redis 性能优化,Redis 分布式锁,Redis 淘汰策略
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。