Redis内存管理中的LRU算法
在讨论Redis内存管理中的LRU算法之前,先简单说一下LRU算法:
LRU算法:即Least Recently Used,表示最近最少使用页面置换算法。是为虚拟页式存储管理服务的,是根据页面调入内存后的使用情况进行决策了。由于无法预测各页面将来的使用情况,只能利用“最近的过去”作为“最近的将来”的近似,因此,LRU算法就是将最近最久未使用的页面予以淘汰,类似于末尾淘汰制。
比如:
如输入以下序列时:4,7,0,7,1,0,1,2,1,2,6
可以用一个特殊的栈来保存当前正在使用的各个页面的页面号。当一个新的进程访问某页面时,便将该页面号压入栈顶,其他的页面号往栈底移,如果内存不够,则将栈底的页面号移除。这样,栈顶始终是最新被访问的页面的编号,而栈底则是最近最久未访问的页面的页面号。
用java代码实现LRU算法如下:
1 import java.util.ArrayList; 2 import java.util.List; 3 4 5 public class LRU { 6 /** 7 * 内存块的个数 8 */ 9 public static final int N = 5; 10 /** 11 * 内存块数组 12 */ 13 Object[] array = new Object[N]; 14 private int size; 15 16 public LRU() { 17 } 18 /** 19 * 判断内存区是否为空 20 * @return 21 */ 22 public boolean isEmpty() { 23 if(size == 0) { 24 return true; 25 } else { 26 return false; 27 } 28 } 29 /** 30 * 判断内存区是否达到最大值 31 * @return 32 */ 33 public boolean isOutOfBoundary() { 34 if(size >=N) { 35 return true; 36 } else { 37 return false; 38 } 39 } 40 /** 41 * 查找元素o在数组中的位置 42 * @param o 43 * @return 44 */ 45 public int indexOfElement(Object o) { 46 for(int i=0; i<N; i++) { 47 if(o == array[i]) { 48 return i; 49 } 50 } 51 return -1; 52 } 53 /** 54 * 有新的数据o需要申请内存 55 * @param o 56 * @return 移出内存区的数据 57 */ 58 public Object push(Object o) { 59 int t = -1; 60 if(!isOutOfBoundary() && indexOfElement(o) == -1){ 61 array[size] = o; 62 size ++; 63 } else if(isOutOfBoundary() && indexOfElement(o) == -1){ 64 for(int i=0; i<size-1; i++) { 65 array[i] = array[i+1]; 66 } 67 array[size-1] = o; 68 } else { 69 t = indexOfElement(o); 70 for(int i=t; i<size-1; i++) { 71 array[i] = array[i+1]; 72 } 73 array[size-1] = o; 74 } 75 if( -1 == t) { 76 return null; 77 } else { 78 return array[t]; 79 } 80 } 81 /** 82 * 输出内存区中的各数据 83 */ 84 public void showMemoryBlock() { 85 for(int i=0; i<size; i++) { 86 System.out.print(array[i] + "\t"); 87 } 88 } 89 90 /** 91 * @param args 92 */ 93 public static void main(String[] args) { 94 Integer iter[] = {4,7,0,7,1,0,1,2,1,2,6}; 95 LRU lru = new LRU(); 96 for(int i=0; i<iter.length; i++) { 97 lru.push(iter[i]); 98 lru.showMemoryBlock(); 99 System.out.println(); 100 } 101 } 102 103 }
LRU算法也可以用于一些实际的应用中,如你要做一个浏览器,或类似于淘宝客户端的应用的就要用到这个原理。大家都知道浏览器在浏览网页的时候会把下载的图片临时保存在本机的一个文件夹里,下次再访问时就会,直接从本机临时文件夹里读取。但保存图片的临时文件夹是有一定容量限制的,如果你浏览的网页太多,就会一些你最不常使用的图像删除掉,只保留最近最久使用的一些图片。这时就可以用到LRU算法 了,这时上面算法里的这个特殊的栈就不是保存页面的序号了,而是每个图片的序号或大小;所以上面这个栈的元素都用Object类来表示,这样的话这个栈就可以保存的对象了。
Redis的数据淘汰机制
Redis提供了5种数据淘汰策略:
- volatile-lru:使用LRU算法进行数据淘汰(淘汰上次使用时间最早的,且使用次数最少的key),只淘汰设定了有效期的key
- allkeys-lru:使用LRU算法进行数据淘汰,所有的key都可以被淘汰
- volatile-random:随机淘汰数据,只淘汰设定了有效期的key
- allkeys-random:随机淘汰数据,所有的key都可以被淘汰
- volatile-ttl:淘汰剩余有效期最短的key
一般来说,推荐使用的策略是volatile-lru,并辨识Redis中保存的数据的重要性。
对于那些重要的,绝对不能丢弃的数据(如配置类数据等),应不设置有效期,这样Redis就永远不会淘汰这些数据。
对于那些相对不是那么重要的,并且能够热加载的数据(比如缓存最近登录的用户信息,当在Redis中找不到时,程序会去DB中读取),可以设置上有效期,这样在内存不够时Redis就会淘汰这部分数据。
配置方法: maxmemory-policy volatile-lru #默认是noeviction,即不进行数据淘汰 Over...
参考:
2. LRU算法