redis过期键的策略
一、过期时间设置:
- 127.0.0.1:6379> expire key seconds //设置键的过期时间为多少秒
- 127.0.0.1:6379> setex key seconds value
注意一下哟:
- 除了字符串自己独有设置过期时间的方法外,其他方法都需要依靠 expire 方法来设置时间
- 如果没有设置时间,那键是永不过期的,一直留在内存中
- 如果设置了过期时间,之后又想让缓存永不过期,使用 persist key
二、Redis 所有的数据结构都可以设置过期时间,时间一到,就会自动删除。你可以想象 Redis 内部有一个死神,时刻盯着所有设置了过期时间的 key,寿命一到就会立即收割。Redis的过期键的过期时间都是保存在过期字典中,过期键的删除策略有三种,分别是定时删除、惰性删除和定期删除。redis 会将每个设置了过期时间的 key 放入到一个独立的字典中,以后会定时遍历这个字典来删除到期的 key。除了定时遍历之外,它还会使用惰性策略来删除过期的 key,所谓惰性策略就是在客户端访问这个 key 的时候,redis 对 key 的过期时间进行检查,如果过期了就立即删除。定时删除是集中处理,惰性删除是零散处理。
定时删除
定时删除策略,是指在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间到的时候,立即执行对键的删除操作。
定时删除策略的优点:
对内存友好,通过定时器可以保证过期键能尽可能快地被删除,并释放过期键占用的空间。
定时删除策略的缺点
1.对CPU不友好。在过期键较多的情况下,删除过期键可能会占用相当一部分的CPU执行时间。在内存不紧张而CPU紧张的情况下,将CPU资源用在删除和当前任务无关的过期键上,无疑也会对服务器的响应时间和吞吐量造成影响。
2.创建定时器需要Redis服务器中的时间事件,而现在时间事件的实现方式是无序链表,查找一个事件的事件复杂度为O(N),并不能高效地处理大量时间事件。
惰性删除
惰性删除策略,是指放任键过期不管,每次从键空间获取键的时候才去检查取得的键是否过期,如果过期的话,就删除该键,如果不过期,就返回该键。
惰性删除策略的优点
对CPU友好,程序只在取出键时才对键进行过期检查,删除的目标进行预当前处理的键。
惰性删除策略的缺点
惰性删除策略对内存不友好,当数据库中有大量的过期键,而这些键又没有被访问到,那么它们可能因为永远都不会被进行过期检查而被删除。
定期删除
定期删除策略,是指每隔一段时间,程序就会对数据库进行一次检查,删除里面的过期键。至于删除多少过期键,以及检查多少数据库,都由算法来决定。
定期删除策略的难点
1.如果删除操作太频繁,或者执行时间过长,定期删除策略就会退化成定时删除策略。
2.如果删除操作执行得太少,或者执行时间太短,定期删除策略又会和惰性删除策略一样,出现内存浪费的现象。
Redis 过期策略实际使用的是惰性删除+定期删除两种策略的一个配合使用。
三、AOF 和 RDB对过期键的处理
1、RDB对过期key的处理
过期key对RDB没有任何影响
- 从内存数据库持久化数据到RDB文件
- 持久化key之前,会检查是否过期,过期的key不进入RDB文件
- 从RDB文件恢复数据到内存数据库
- 数据载入数据库之前,会对key先进行过期检查,如果过期,不导入数据库(主库情况)
2、AOF对过期key的处理
过期key对AOF没有任何影响
- 从内存数据库持久化数据到AOF文件:
- 当key过期后,还没有被删除,此时进行执行持久化操作(该key是不会进入aof文件的,因为没有发生修改命令)
- 当key过期后,在发生删除操作时,程序会向aof文件追加一条del命令(在将来的以aof文件恢复数据的时候该过期的键就会被删掉)
- AOF重写
- 重写时,会先判断key是否过期,已过期的key不会重写到aof文件
三、Redis中的内存淘汰机制:
内存淘汰机制 redis.conf 中配置:
- # maxmemory-policy noeviction
参数 | 描述 |
volatile-lru | 从已设置过期时间 的数据集中挑选最近最少使用 的数据淘汰 |
volatile-lfu | 从已设置过期时间的数据集中挑选最不经常 使用的数据淘汰 |
volatile-ttl | 从已设置过期时间的数据集中挑选将要过期 的数据淘汰 |
volatile-random | 从已设置过期时间的数据集中挑选任意数据 淘汰 |
allkeys-lru | 当内存不足写入新数据时淘汰最近最少使用的Key |
allkeys-random | 当内存不足写入新数据时随机选择key淘汰 |
allkeys-lfu | 当内存不足写入新数据时移除最不经常使用的Key |
no-eviction | 当内存不足写入新数据时,写入操作会报错,同时不删除数据 |
- volatile 为前缀的策略都是从已过期的数据集中进行淘汰。
- allkeys 为前缀的策略都是面向所有key进行淘汰。
- LRU (least recently used)最近最少用到的。
- LFU (Least Frequently Used)最不常用的。
- 它们的触发条件都是 Redis 使用的内存达到阈值时。
1、手写LRU缓存
- public class LRUCache {
- private Map<Integer, Integer> map;
- private final int capacity;
- public LRUCache(int capacity) {
- this.capacity = capacity;
- //定义了迭代顺序(true)
- map = new LinkedHashMap<Integer, Integer>(capacity,0.75f,true){
- @Override
- protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
- //当map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据
- return size() > capacity;
- }
- };
- }
- public int get(int key) {
- return map.getOrDefault(key, -1);
- }
- public void put(int key, int value) {
- map.put(key, value);
- }
- }
对于 LinkedHashMap 而言:
- public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
底层使用哈希表与双向链表来保存所有元素。
LinkedHashMap 中的 Entry 集成与 HashMap 的 Entry,但是其增加了 before 和 after 的引用,指的是上一个元素和下一个元素的引用
- static class Entry<K,V> extends HashMap.Node<K,V> {
- Entry<K,V> before, after;
- Entry(int hash, K key, V value, Node<K,V> next) {
- super(hash, key, value, next);
- }
- }
初始化:
在 LinkedHashMap 的构造方法中,实际调用了父类 HashMap 的相关构造方法来构造一个底层存放的 table 数组,但额外可以增加 accessOrder 这个参数,如果不设置,默认为 false,代表按照插入顺序进行迭代;当然可以显式设置为 true,代表以访问顺序进行迭代。
- public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
- super(initialCapacity, loadFactor);
- this.accessOrder = accessOrder;
- }
2.手写 LFU 算法
- public class LFUCache<K,V> {
- private Map<K, LinkNode> cache ;
- private Map<Integer, DoubleLinkList<K,V>> freq ;
- private int maxSize;
- private int size;
- public LFUCache(int maxSize) {
- this.maxSize = maxSize;
- this.cache = new HashMap<>(maxSize*4/3);
- this.freq = new HashMap<>();
- }
- public V get(K key){
- LinkNode node = cache.get(key);
- if(node==null){
- return null;
- }
- changeNodeFreq(node);
- return (V) node.value;
- }
- private void changeNodeFreq(LinkNode node) {
- freq.get(node.freq).remove(node);
- node.freq = node.freq + 1;
- if (!freq.containsKey(node.freq)) {
- freq.put(node.freq, new DoubleLinkList<>());
- }
- freq.get(node.freq).addNodeToTail(node);
- }
- public void put(K key,V value){
- LinkNode node = cache.get(key);
- if(node!=null){
- node.value = value;
- changeNodeFreq(node);
- return;
- }
- if(node==null){
- node = new LinkNode(key,value);
- cache.put(key,node);
- if(!freq.containsKey(node.freq)){
- freq.put(node.freq,new DoubleLinkList<>());
- }
- freq.get(node.freq).addNodeToTail(node);
- size++;
- if(size>maxSize){
- int minFreq = getMinFreq();
- LinkNode remove = freq.get(minFreq).removeFromHead();
- cache.remove(remove.key);
- size--;
- }
- return;
- }
- }
- public int getMinFreq(){
- int min = Integer.MAX_VALUE;
- for (Map.Entry<Integer, DoubleLinkList<K, V>> entry : freq.entrySet()) {
- Integer freq = entry.getKey();
- min = freq<min ? freq : min;
- if(min==1){
- break;
- }
- }
- return min;
- }
- public static void main(String[] args) {
- LFUCache<String,String> lfuCache = new LFUCache<>(4);
- lfuCache.put("1","1");
- lfuCache.put("2","2");
- lfuCache.put("3","3");
- lfuCache.put("4","4");
- lfuCache.get("1");
- lfuCache.get("2");
- lfuCache.put("5","5");
- System.out.println(lfuCache.get("3"));
- }
- }
redis过期键的策略的更多相关文章
- 一文了解:Redis过期键删除策略
Redis过期键删除策略 Redis中所有的键都可以设置过期策略,就像是所有的键都可以上"生死簿",上了生死簿的键到时间后阎王就会叉掉这个键.同一时间大量的键过期,阎王就会忙不过来 ...
- Redis 过期键删除策略
Redis 中数据库键的过期时间都保存在过期字典中,当一个键过期了,Redis 存在三种不同的删除策略:定时删除.惰性删除和定期删除 定时删除 定义 在设置键的过期时间的同时创建一个计时器,让定时器在 ...
- redis过期键删除策略以及大key删除方法
今天遇到了一个前同事挖的坑,刷新缓存中商品信息时先让key过期,然后从数据库里取最新数据然后再放到缓存中,他是这样写的 redisTemplate.expire(CacheConst.GOOGS_PR ...
- redis中key的过期键删除策略
Redis过期键删除策略 Redis key过期的方式有三种: 被动删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key 主动删除:由于惰性删除策略无法保证冷数据被及时删 ...
- redis学习笔记——Redis过期键的删除策略
Redis过期键的删除策略 对于过期键一般有三种删除策略 定时删除:在设置键的过期时间的同时,创建一个定时器(timer),让定时器在键的过期时间来临时,立即执行对键的删除操作: 惰性删除:放任键过期 ...
- Redis系列(五):Redis的过期键删除策略
本篇博客是Redis系列的第5篇,主要讲解下Redis的过期键删除策略. 本系列的前4篇可以点击以下链接查看: Redis系列(一):Redis简介及环境安装 Redis系列(二):Redis的5种数 ...
- Redis的过期键删除策略
文章首发于公众号:蘑菇睡不着,欢迎来看看 前言 Redis 中都是键值对的存储形式,键都是字符串类型的,而值有很多种类型,如 string.list.hash.set.sorted set等类型.当设 ...
- 【Redis】过期键删除策略和内存淘汰策略
Redis 过期键策略和内存淘汰策略 目录 Redis 过期键策略和内存淘汰策略 设置Redis键过期时间 Redis过期时间的判定 过期键删除策略 定时删除 惰性删除 定期删除 Redis过期删除策 ...
- Redis 过期键的设置、获取和删除过期时间
Redis 过期键的设置.获取和删除过期时间 转自http://blog.51cto.com/littledevil/1813956 设置过期 默认情况下键是没有生存时间的,也就是永不过期,除非清空内 ...
随机推荐
- SourceTree 配置 GitLab
生成SSH 创建SSH,执行ssh-keygen -t rsa -C "youremail@example.com",会在.ssh目录下生成id_rsa.id_rsa.pub两个私 ...
- CELF算法原理
影响力传播模型中的独立层叠模型(independent cascading model,IC模型),影响力传播过程中,种子的影响力具备子模性(submodularity),即种子的边际影响力增量会呈现 ...
- 03.Django-ORM
ORM 1. 数据库配置 配置使用sqlite3,mysql,oracle,postgresql等数据库 sqlite3数据库配置 DATABASES = { 'default': { # 默认使用的 ...
- 从汉堡加料说起——浅谈C#中的Decorator模式
相信大家都在都在汉堡店吃过汉堡,有些汉堡店很有特色,推出了汉堡订制服务,即,可以在汉堡中加料,加肉饼,加生菜之类(有点类似我们本地的肥肠粉里面加冒结子).更是让不少吃货大快朵颐,大呼过瘾,加6,7层肉 ...
- Java实现 LeetCode 780 到达终点(逻辑题)
780. 到达终点 从点 (x, y) 可以转换到 (x, x+y) 或者 (x+y, y). 给定一个起点 (sx, sy) 和一个终点 (tx, ty),如果通过一系列的转换可以从起点到达终点,则 ...
- Java实现 LeetCode 777 在LR字符串中交换相邻字符(分析题)
777. 在LR字符串中交换相邻字符 在一个由 'L' , 'R' 和 'X' 三个字符组成的字符串(例如"RXXLRXRXL")中进行移动操作.一次移动操作指用一个"L ...
- (Java实现) 洛谷 P1036 选数
输入输出格式 输入格式: 键盘输入,格式为: n,k x1,x2,x3-xn 输出格式: 屏幕输出,格式为: 11个整数(满足条件的种数). 输入输出样例 输入样例#1: 4 3 3 7 12 19 ...
- Java实现 蓝桥杯 算法训练 My Bad(暴力)
试题 算法训练 My Bad 问题描述 一个逻辑电路将其输入通过不同的门映射到输出,在电路中没有回路.输入和输出是一个逻辑值的有序集合,逻辑值被表示为1和0.我们所考虑的电路由与门(and gate, ...
- Java实现蓝桥杯模拟递增的数
问题描述 一个正整数如果任何一个数位不大于右边相邻的数位,则称为一个数位递增的数,例如1135是一个数位递增的数,而1024不是一个数位递增的数. 给定正整数 n,请问在整数 1 至 n 中有多少个数 ...
- Java实现 LeetCode 324 摆动排序 II
324. 摆动排序 II 给定一个无序的数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]- 的顺序. 示例 1: 输入: n ...