Redis的常用淘汰策略以及算法实现
一、Redis的内存配置
1,Redis配置内存为多少合适?
默认:如果不设置最大内存大小或者设置最大内存大小为0,在64为操作系统下不限制内存大小,在32位操作系统下最多使用3GB内存。
极限情况:留出一倍内存。比如你的redis数据占用了8G内存,那么你还需要再预留8G空闲内存。也就是内存需求是16G。内存占用率低于50%是最安全的。
普通情况:正常情况下,在序列化周期内,不会更改所有数据,只会有部分数据更改,那么,预留出可能产生的更改部分的空间,就行。如果实在要说一个数据的话,一般推荐Redis设置内存为最大物理内存的75%都是安全的。
2,如何修改内存
a)配置文件修改
redis.conf中
#设置为100M,单位是byte
maxmemory 104857600
b)命令行修改
config set maxmemory 104857600
3,查看最大内存
config get maxmemory
#或者使用
info memory
二、Redis的内存淘汰策略
1,Redis 过期策略是:定期删除+惰性删除。
所谓定期删除,指的是 Redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 key,检查其是否过期,如果过期就删除。
假设 Redis 里放了 10w 个 key,都设置了过期时间,你每隔几百毫秒,就检查 10w 个 key,那 Redis 基本上就死了,cpu 负载会很高的,消耗在你的检查过期 key 上了。注意,这里可不是每隔 100ms 就遍历所有的设置过期时间的 key,那样就是一场性能上的灾难。实际上 Redis 是每隔 100ms 随机抽取一些 key 来检查和删除的。
惰性删除:数据到达过期时间,不做处理。等下次访问该数据时,如果未过期,返回数据;发现已过期,删除,返回不存在。
但是实际上这还是有问题的,如果定期删除漏掉了很多过期 key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期 key 堆积在内存里,导致 Redis 内存块耗尽了,咋整?实际上会走:内存淘汰机制。
2,内存淘汰机制
Redis内存淘汰机制有以下几个:
- noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了。
- allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)。
- allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的 key 给干掉啊。
- volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 key(这个一般不太合适)。
- volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 key。
- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 key 优先移除。
- allkeys-lfu: 对所有key使用LFU算法进行删除。LFU:最不经常使用,如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小。
- volatile-lfu: 对所有设置了过期时间的key使用LFU算法进行删除。
三、手写LRU算法
1,采用LinkedHashMap实现
public class Demo015_LRUCacheLinkedHashMap {
private int capacity;
private LinkedHashMap<Integer, Integer> linkedHashMap;
public Demo015_LRUCacheLinkedHashMap(int capacity) {
this.capacity = capacity;
/**
* 三个参数:capacity为容量,0.75位扩容因子,true为按照访问排序false为按照插入排序
* 重写删除尾结点的方法,一旦发现当前linkhashmap的长度大于总容量就需要删除*/
linkedHashMap = new LinkedHashMap<Integer, Integer>(capacity,0.75F,true){
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
return super.size() > capacity;
}
};
}
public void put(int key, int value) {
linkedHashMap.put(key, value);
}
public int get(int key) {
Integer value = linkedHashMap.getOrDefault(key,-1);
return value;
}
}
2,自定义双向链表
- 定义Node节点:key,val,next和prev
- 定义DoubleLinkedNode管理Node结点组成头尾结点的双向链表
- 定义hashmap存储每个结点
- 插入时判断当前值是否已经存在hashmap中
- 如果存在就更改当前值,删除双向链表中原来的这个值,添加新值到链表头结点并修改hashmap中当前值
- 如果不存在当前值,判断当前容器是否满了,如果满了就删除链表尾部删除hashmap中数据。并添加新结点到链表头部和hashmap中
- 获取时,直接从hashmap中获取。如果不存在直接返回-1,如果存在就删除链表尾部数据,更新链表头部数据为当前node
public class Demo015_LRUCache {
class Node<K, V> {
K key;
V val;
Node next;
Node prev;
public Node(){
next = prev = null;
}
public Node(K key, V val) {
this.key = key;
this.val = val;
next = prev = null;
}
}
class DoubleLinkedNode<K,V>{
Node head;
Node tail;
public DoubleLinkedNode() {
head = new Node();
tail = new Node();
head.next = tail;
tail.prev = head;
}
public void addHead(Node<K,V> node) {
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
public void remove(Node<K,V> node) {
if (node.prev == null || node.next==null) {
return;
}
node.prev.next = node.next;
node.next.prev = node.prev;
node.next = null;
node.prev = null;
}
public Node<K,V> getLast() {
if (tail.prev == head) {
return null;
}
return tail.prev;
}
}
private int capacity;
private HashMap<Integer, Node<Integer,Integer>> hashMap;
private DoubleLinkedNode<Integer, Integer> doubleLinkedNode;
public Demo015_LRUCache(int capacity) {
this.capacity = capacity;
hashMap = new HashMap<>();
doubleLinkedNode = new DoubleLinkedNode<>();
}
public int get(int key) {
Node<Integer,Integer> node = hashMap.get(key);
if (node == null) {
return -1;
}
doubleLinkedNode.remove(node);
doubleLinkedNode.addHead(node);
return node.val;
}
public void put(int key, int value) {
Node<Integer, Integer> node = hashMap.get(key);
if (node == null) { //没有添加过
if (hashMap.size() == capacity) { //达到最大值状态
//删除最后结点
Node<Integer, Integer> last = doubleLinkedNode.getLast();
doubleLinkedNode.remove(last);
hashMap.remove(last.key);
}
//添加头结点
node = new Node<>(key, value);
hashMap.put(key,node);
doubleLinkedNode.addHead(node);
}else {
//如果添加过,删除双向链表的该节点,将其修改值之后添加到头节点
doubleLinkedNode.remove(node);
node.val = value;
doubleLinkedNode.addHead(node);
hashMap.put(key, node);
}
}
}
Redis的常用淘汰策略以及算法实现的更多相关文章
- Redis的内存淘汰策略(八)
一:Redis的AOF是什么? 以日志的形式来记录每个写操作(读操作不记录),将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构 ...
- redis六种内存淘汰策略学习
当客户端会发起需要更多内存的申请,Redis检查内存使用情况,如果实际使用内存已经超出maxmemory,Redis就会根据用户配置的淘汰策略选出无用的key; 当前Redis3.0版本支持的淘汰策略 ...
- Redis的内存淘汰策略
Redis占用内存大小 我们知道Redis是基于内存的key-value数据库,因为系统的内存大小有限,所以我们在使用Redis的时候可以配置Redis能使用的最大的内存大小. 1.通过配置文件配置 ...
- Redis 内存满了怎么办? Redis的内存淘汰策略
https://juejin.im/post/5d674ac2e51d4557ca7fdd70 Redis占用内存大小 我们知道Redis是基于内存的key-value数据库,因为系统的内存大小有限, ...
- Redis过期key淘汰策略
Redis采用惰性+定期的key淘汰策略 1. Redis配置项hz定义了serverCron任务的执行周期,默认为10,即CPU空闲时每秒执行10次; 2. 每次过期key清理的时间不超过CPU时间 ...
- Redis:缓存淘汰策略
将redis用做缓存是一种非常常见的手段,然而由于内存大小的限制,会导致redis在内存空间满了以后需要处理继续存入的数据.总计有以下几种策略: volatile-ttl:在设置了过期时间的数据集里, ...
- Redis数据缓存淘汰策略【FIFO 、LRU、LFU】
FIFO.LFU.LRU FIFO:先进先出算法 FIFO(First in First out),先进先出.在FIFO Cache设计中,核心原则就是:如果一个数据最先进入缓存中,则应该最早淘汰掉. ...
- Redis系列之----Redis的过期设置及淘汰策略
Redis的过期时间机制和内存淘汰策略 Redis的数据是存储在内存中的,而服务器的内存大小是有限制的,除非宕机,否则这些数据会一直存在,对于一些不再使用的key,也应当进行删除,否则会浪费内存 ...
- Redis++:Redis 内存爆满 之 淘汰策略
前言: 我们的redis使用的是内存空间来存储数据的,但是内存空间毕竟有限,随着我们存储数据的不断增长,当超过了我们的内存大小时,即在redis中设置的缓存大小(maxmeory 4GB),redis ...
随机推荐
- LINUX - 获取本地ip
Linux编程获取本机IP地址的几种方法 参考: https://blog.csdn.net/zhongmushu/article/details/89944990 https://www.cnblo ...
- 使用SignTool对软件安装包进行数字签名(一)--制作证书
一.制作根证书 1.开始菜单-运行-输入cmd,弹出命令行窗体. 2.输入命令:cd /d F:\SignTool,将当前工作目录修改到SignTool路径下. 3.使用makecert命令制作证书, ...
- 多线程(四) AQS底层原理分析
J.U.C 简介 Java.util.concurrent 是在并发编程中比较常用的工具类,里面包含很多用来在并发 场景中使用的组件.比如线程池.阻塞队列.计时器.同步器.并发集合等等.并 发包的作者 ...
- Redis五大类型及底层实现原理
目录 简单动态字符串链表字典跳跃表整数集合压缩列表对象 对象的类型与编码字符串对象列表对象哈希对象 集合对象有序集合对象类型检查与命令多态内存回收对象共享对象的空转时长 简单动态字符串 导读 Red ...
- js group objects in an array
js group objects in an array js group objects in an array var groupBy = function(xs, key) { return x ...
- echarts手机端,数据多时可以滚动
<div id="container" style="height: 400px"></div> <script type=&qu ...
- 从微信小程序到鸿蒙js开发【11】——页面路由
目录: 1.router.push()&wx.navigateTo() 2.router.replace()&wx.redirectTo() 3.router.back()&w ...
- 生成类库项目时同时生成的pdb文件是什么东东?
英文全称:Program Database File Debug里的PDB是full,保存着调试和项目状态信息.有断言.堆栈检查等代码.可以对程序的调试配置进行增量链接.Release 里的PDB是p ...
- 自己写的一个抢票加速的Python小程序源码分享-----纯属娱乐
最近这段时间频频看到微信群里发什么 抢票加速,智行.携程.飞猪.美团,对于我这能坐客车就不坐火车的人来说,无所谓靠谱不靠谱 突发奇想的整理了下整个抢票加速的逻辑,写了这个小程序,代码很low,拒绝批评 ...
- 你真的了解URLEncode吗?
使用浏览器进行Http网络请求时,若请求query中包含中文,中文会被编码为 %+16进制+16进制形式,但你真的深入了解过,为什么要进行这种转义编码吗?编码的原理又是什么? 例如,浏览器中进行百度搜 ...