赞
踩
Redis缓存是一种常用的缓存技术,可以提高系统性能和响应速度。然而,如果不采取适当的过期策略,缓存可能会占据大量内存,并且数据也可能会过期并失效。
一、Redis缓存过期策略的基础知识
了解Redis缓存过期策略的前提是必须掌握Redis内存模型以及数据结构,在此我们不再赘述。Redis缓存过期策略的核心思想是根据key的过期时间来决定key是否被删除的。当一个key的过期时间到达指定时间后,Redis会自动将其删除。这个过程是由Redis内部负责的,程序员只需要设定好key的过期时间即可。
二、Redis缓存过期策略常见的类型以及如何实现
1)TTL(Time-To-Live)
TTL是Redis最简单的过期策略之一,它需要程序员手动为每个key设置过期时间。当key的过期时间到达后,Redis会自动将其删除。我们可以使用TTL命令获取key的剩余时间或者使用EXPIRE命令设置key的过期时间。例如:
- # 设置 key 为 value, 并将过期时间设置为 10 秒钟
- SET key value EX 10 # 获取 key 的剩余过期时间 TTL key
2)惰性删除
惰性删除策略也是Redis默认的过期策略之一。它不会把所有的过期 key 都删除掉,而是等到有客户端来查询这个 key 的时候才检查该 key 是否已过期,并在发现过期的情况下删除该 key。因此惰性删除存在缺陷:如果有大量的过期 key 没有被查询,就会占用过多的内存空间。所以在某些场景中,需要结合其他策略来使用惰性删除。
3)定期删除
定期删除是与惰性删除相对应的一种过期策略,它会每隔一段时间主动检查过期 key,并删除过期的 key 。Redis会启动一个专门负责删除过期 key 的线程,并且可以通过配置文件指定清除频率(redis.conf文件中,default-db-deletion-size配上db * rows-per-second * 3600 )。与惰性删除不同,定期删除会消耗一定的CPU资源和IO资源,但相对惰性删除而言,它可以更快的将大量过期 key 删除掉。
二、Redis如何处理超时key
当一个key过期后,程序员无需干预,Redis会自动开始进行以下两个操作:
1)简单地将该key打上过期标记,并不立即从内存中删除;
2)通过惰性删除或定期删除策略,在之后的某个时间从内存中清除带有过期标记的key。
需要注意的是,Redis并不能保证所有过期的key都能在第一时间被后台线程清理掉。为了避免缓存泄漏和数据更新问题,应用程序在使用Redis缓存时,最好添加逻辑判断,比如在获取value之前先检查key是否存在或者手动删减过期key 。
三、基于时间的过期策略
1. 设置过期时间
在Redis中,可以使用EXPIRE和PEXPIRE命令为键设置生存时间,以秒或毫秒为单位。例如:
// 设置键为mykey的值,确保它在30秒之后过期
- redisTemplate.opsForValue().set("mykey", "Hello, Redis!");
- redisTemplate.expire("mykey", 30, TimeUnit.SECONDS);
2. 查看剩余生存时间
可以使用TTL命令或PTTL命令来查看键的剩余生存时间(以秒或毫秒为单位)。例如:
- // 查看mykey的生存时间(以秒为单位)
- redisTemplate.ttl("mykey");
-
- // 查看mykey的生存时间(以毫秒为单位)
- redisTemplate.pttl("mykey");
3. 取消过期时间
可以使用PERSIST命令来取消键的生存时间,使其永久保存。例如:
- // 取消mykey的生存时间
- redisTemplate.persist("mykey");
四、基于LRU算法的淘汰机制
1. 设置最大内存
可以使用maxmemory和maxmemory-policy两个配置参数设置Redis的最大内存和相应的淘汰策略。例如:
- # 设置Redis最大内存为100MB
- maxmemory 100mb
-
- # 设置淘汰策略为LRU
- maxmemory-policy allkeys-lru
2. 修改默认淘汰策略
除了使用maxmemory-policy命令来设置全局的淘汰策略外,也可以通过将某些键标记为VOLATILE来单独设置LRU淘汰策略。例如:
- // 将mykey的生存时间设置为10秒,并标记为VOLATILE
- redisTemplate.expire("mykey", 10, TimeUnit.SECONDS);
- redisTemplate.execute(new RedisCallback<Boolean>() {
- @Override
- public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
- // 将mykey标记为VOLATILE
- connection.setEx(redisTemplate.getKeySerializer().serialize("mykey"), 10000L,
- redisTemplate.getValueSerializer().serialize("Hello, Redis!"));
- return true;
- }
- });
3. 查看Redis内存使用情况
可以使用INFO命令或redis-cli工具来查看Redis的内存使用情况。例如:
# 使用INFO命令查看Redis内存使用情况
- redisTemplate.execute(new RedisCallback<String>() {
- @Override
- public String doInRedis(RedisConnection connection) throws DataAccessException {
- return connection.info();
- }
- });
- # 使用redis-cli工具查看Redis内存使用情况
- $ redis-cli info memory
五、通过Java代码演示实操
以下是一个通过Java Redis API演示基于时间的过期策略和LRU淘汰机制的示例程序。
-
- public class CacheDemo {
- private static finalStringRedisTemplate redisTemplate = new StringRedisTemplate();
-
- static {
- // 设置Redis服务器的主机名和端口号
- RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("localhost", 6379);
- // 创建连接池
- LettuceConnectionFactory factory = new LettuceConnectionFactory(config);
- factory.afterPropertiesSet();
- // 设置RedisTemplate的连接工厂
- redisTemplate.setConnectionFactory(factory);
- redisTemplate.afterPropertiesSet();
- }
-
- public static void main(String[] args) {
- // 设置键值对缓存
- redisTemplate.opsForValue().set("key1", "value1");
- redisTemplate.opsForValue().set("key2", "value2");
-
- // 设置key1的生存时间为10秒,并标记为VOLATILE
- redisTemplate.expire("key1", 10, TimeUnit.SECONDS);
- redisTemplate.execute(new RedisCallback<Boolean>() {
- @Override
- public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
- connection.setEx(redisTemplate.getKeySerializer().serialize("key1"), 10000L,
- redisTemplate.getValueSerializer().serialize("value1"));
- return true;
- }
- });
-
- // 查看key1的剩余生存时间
- System.out.println(redisTemplate.getExpire("key1"));
-
- // 设置Redis的最大内存为10MB,淘汰策略为LRU
- redisTemplate.execute(new RedisCallback<String>() {
- @Override
- public String doInRedis(RedisConnection connection) throws DataAccessException {
- connection.getConfig("maxmemory");
- connection.getConfig("maxmemory-policy", "allkeys-lru");
- return null;
- }
- });
-
- // 查看Redis内存使用情况
- System.out.println(redisTemplate.execute(RedisServerCommands::info).get("used_memory"));
- }
- }
六、总结
Redis缓存的过期策略是保证缓存可靠性和性能的关键之一。基于时间的过期策略通过设置生存时间来实现,而基于LRU算法的淘汰机制则根据访问频率和时间排序来删除最近没有使用的key。在实际使用中,可以结合两种策略来避免出现缓存占据大量内存和过期失效等问题。在Java中,可以使用RedisTemplate来对Redis进行操作。通过设置键值对缓存、设置过期时间、取消过期时间、修改默认淘汰策略和查看Redis内存使用情况等操作,可以实现对缓存的控制和管理。
需要注意的是,在设置缓存过期时间和淘汰机制时,应根据业务场景和数据类型来选择合适的时间和策略。如果需要缓存的数据变化频繁,建议采用基于LRU算法的淘汰机制;如果数据比较固定或重要性较高,可以使用基于时间的过期策略。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。