文章插图
介绍
文章插图
redis是一个内存数据库,当Redis使用的内存超过物理内存的限制后,内存数据会和磁盘产生频繁的交换,交换会导致Redis性能急剧下降 。所以在生产环境中我们通过配置参数maxmemoey来限制使用的内存大小 。
当实际使用的内存超过maxmemoey后,Redis提供了如下几种可选策略 。
noeviction:写请求返回错误
volatile-lru:使用lru算法删除设置了过期时间的键值对 volatile-lfu:使用lfu算法删除设置了过期时间的键值对 volatile-random:在设置了过期时间的键值对中随机进行删除 volatile-ttl:根据过期时间的先后进行删除,越早过期的越先被删除
allkeys-lru:在所有键值对中,使用lru算法进行删除 allkeys-lfu:在所有键值对中,使用lfu算法进行删除 allkeys-random:所有键值对中随机删除
我们来详细了解一下lru和lfu算法,这是2个常见的缓存淘汰算法 。「因为计算机缓存的容量是有限的,所以我们要删除那些没用的数据,而这两种算法的区别就是判定没用的纬度不一样 。」
LRU算法「lru(Least recently used,最近最少使用)算法,即最近访问的数据,后续很大概率还会被访问到,即是有用的 。而长时间未被访问的数据,应该被淘汰」
lru算法中数据会被放到一个链表中,链表的头节点为最近被访问的数据,链表的尾节点为长时间没有被访问的数据
文章插图
「lru算法的核心实现就是哈希表加双向链表」 。链表可以用来维护访问元素的顺序,而hash表可以帮我们在O(1)时间复杂度下访问到元素 。
「至于为什么是双向链表呢」?主要是要删除元素,所以要获取前继节点 。数据结构图示如下
文章插图
使用双向链表+HashMap双向链表节点定义如下
public class ListNode<K, V> { K key; V value; ListNode pre; ListNode next; public ListNode() {} public ListNode(K key, V value) { this.key = key; this.value = value; }}
封装双向链表的常用操作public class DoubleList { private ListNode head; private ListNode tail; public DoubleList() { head = new ListNode(); tail = new ListNode(); head.next = tail; tail.pre = head; } public void remove(ListNode node) { node.pre.next = node.next; node.next.pre = node.pre; } public void addLast(ListNode node) { node.pre = tail.pre; tail.pre = node; node.pre.next = node; node.next = tail; } public ListNode removeFirst() { if (head.next == tail) { return null; } ListNode first = head.next; remove(first); return first; }}
封装一个缓存类,提供最基本的get和put方法 。「需要注意,这两种基本的方法都涉及到对两种数据结构的修改」 。public class MyLruCache<K, V> { private int capacity; private DoubleList doubleList; private Map<K, ListNode> map; public MyLruCache(int capacity) { this.capacity = capacity; map = new HashMap<>(); doubleList = new DoubleList(); } public V get(Object key) { ListNode<K, V> node = map.get(key); if (node == null) { return null; } // 先删除该节点,再接到尾部 doubleList.remove(node); doubleList.addLast(node); return node.value; } public void put(K key, V value) { // 直接调用这边的get方法,如果存在,它会在get内部被移动到尾巴,不用再移动一遍,直接修改值即可 if ((get(key)) != null) { map.get(key).value = value; return; } // 如果超出容量,把头去掉 if (map.size() == capacity) { ListNode listNode = doubleList.removeFirst(); map.remove(listNode.key); } // 若不存在,new一个出来 ListNode node = new ListNode(key, value); map.put(key, node); doubleList.addLast(node); }}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 当云服务器频繁被暴力破解时的防护措施--数据湾
- 在明朝,皇帝的第二代被称为 被康熙皇帝赞许为今日清宫第一的清代官员是
- 重庆|重庆职业打假人称被网暴再次索赔1千元,网友:当婊子还想立牌坊
- 三国杀谁厉害?三国里面谁最聪明被杀了_1
- 盲目购买恐被套牢,不可盲目饮用松针茶
- 蜀国被灭的时候东吴怎么不帮 东吴和蜀汉存在多少年
- 花蕊夫人为蜀国宠妃被后世称为 花蕊夫人被后世称为
- 曹操为什么没有杀死刘备 曹操被刘备打败了吗
- 翡翠|什么是翡翠的“翠性”?看完就不用担心被骗了
- 东汉云台二十八名将怎么没有马援?9为什么马援没有被列入云台二十八将中-