<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
長時間不使用的快取
很多人瞭解了Redis的好處之後,於是把任何資料都往Redis中放,如果使用不合理很容易導致資料超過Redis的記憶體,這種情況會出現什麼問題呢?
所以遇到這類問題的時候,我們一般有幾種方法。
在實際生產環境中,伺服器不僅僅只有Redis,為了避免Redis記憶體使用過多對其他程式造成影響,我們一般會設定最大記憶體。Redis預設的最大記憶體 maxmemory=0 ,表示不限制Redis記憶體的使用。我們可以修改 redis.conf 檔案,設定Redis最大使用的記憶體。
# 單位為byte maxmemory <bytes> 2147483648(2G)
如何檢視當前Redis最大記憶體設定呢,進入到Redis-Cli控制檯,輸入下面這個命令。
config get maxmemory
當Redis中儲存的記憶體超過maxmemory時,會怎麼樣呢?下面我們做一個實驗
在redis-cli控制檯輸入下面這個命令,把最大記憶體設定為1個位元組。
config set maxmemory 1
通過下面的命令儲存一個string型別的資料
set name mvp
此時,控制檯會得到下面這個錯誤資訊
(error) OOM command not allowed when used memory > 'maxmemory'.
設定了maxmemory的選項,redis記憶體使用達到上限。可以通過設定LRU演演算法來刪除部分key,釋放空間。預設是按照過期時間的,如果set時候沒有加上過期時間就會導致資料寫滿maxmemory。Redis中提供了一種記憶體淘汰策略,當記憶體不足時,Redis會根據相應的淘汰規則對key資料進行淘汰。Redis一共提供了8種淘汰策略,預設的策略為noeviction,當記憶體使用達到閾值的時候,所有引起申請記憶體的命令會都會報錯。
字首為volatile-和allkeys-的區別在於二者選擇要清除的鍵時的字典不同,volatile-字首的策略代表從redisDb中的expire字典中選擇鍵進行清除;allkeys-開頭的策略代表從dict字典中選擇鍵進行清除。
記憶體淘汰演演算法的具體工作原理是:
LRU是Least Recently Used的縮寫,也就是表示最近很少使用,也可以理解成最久沒有使用。也就是說當記憶體不夠的時候,每次新增一條資料,都需要拋棄一條最久時間沒有使用的舊資料。標準的LRU演演算法為了降低查詢和刪除元素的時間複雜度,一般採用Hash表和雙向連結串列結合的資料結構,hash表可以賦予連結串列快速查詢到某個key是否存在連結串列中,同時可以快速刪除、新增節點,如下圖所示。
雙向連結串列的查詢時間複雜度是O(n),刪除和插入是O(1),藉助HashMap結構,可以使得查詢的時間複雜度變成O(1)。
Hash表用來查詢在連結串列中的資料位置,連結串列負責資料的插入,當新資料插入到連結串列頭部時有兩種情況。
這樣,經過多次Cache操作之後,最近被命中的快取,都會存在連結串列頭部的方向,沒有命中的,都會在連結串列尾部方向,當需要替換內容時,由於連結串列尾部是最少被命中的,我們只需要淘汰連結串列尾部的資料即可。
java程式碼實現簡單的LRU演演算法
import java.util.HashMap; public class LRUCache { private Node head; private Node tail; private final HashMap<String,Node> nodeHashMap; private int capacity; //容量 public LRUCache(int capacity) { this.capacity = capacity; nodeHashMap=new HashMap<>(); tail=new Node(); head=new Node(); head.next=tail; tail.prev=head; } //移除節點 private void removeNode(Node node){ if(node==tail){ tail=tail.prev; tail.next=null; }else if(node==head){ head=head.next; head.prev=null; }else{ node.prev.next=node.next; node.next.prev=node.prev; } } private void addNodeToHead(Node node){ node.next=head.next; head.next.prev=node; node.prev=head; head.next=node; } private void moveNodeToHead(Node node){ removeNode(node); addNodeToHead(node); } public String get(String key){ Node node=nodeHashMap.get(key); if(node==null){ return null; } //重新整理當前key的位置 moveNodeToHead(node); return node.value; } public void put(String key,String value){ Node node=nodeHashMap.get(key); if(node==null){ //如果不存在,則新增到連結串列 if(nodeHashMap.size()>=capacity){ //大於容量,則需要移除老的資料 removeNode(tail); //移除尾部節點(tail節點是屬於要被淘汰資料) nodeHashMap.remove(tail.key); //從hashmap中移除 } node=new Node(key,value); nodeHashMap.put(key,node); addNodeToHead(node); }else{ node.value=value; moveNodeToHead(node); } } class Node{ private String key; private String value; Node prev; Node next; public Node(){} public Node(String key,String value){ this.key=key; this.value=value; } } }
實際上,Redis使用的LRU演演算法其實是一種不可靠的LRU演演算法,它實際淘汰的鍵並不一定是真正最少使用的資料,它的工作機制是:
這5個key是預設的個數,具體的數值可以在redis.conf中設定
maxmemory-samples 5
當近似LRU演演算法取值越大的時候就會越接近真實的LRU演演算法,因為取值越大獲取的資料越完整,淘汰中的資料就更加接近最少使用的資料。這裡其實涉及一個權衡問題,如果需要在所有的資料中搜尋最符合條件的資料,那麼一定會增加系統的開銷,Redis是單執行緒的,所以耗時的操作會謹慎一些。為了在一定成本內實現相對的LRU,早期的Redis版本是基於取樣的LRU,也就是放棄了從所有資料中搜尋解改為取樣空間搜尋最優解。Redis3.0版本之後,Redis作者對於基於取樣的LRU進行了一些優化:
如下圖所示,首先從目標字典中採集出maxmemory-samples個鍵,快取在一個samples陣列中,然後從samples陣列中一個個取出來,和回收池中的鍵進行鍵的空閒時間比較,從而更新回收池。在更新過程中,首先利用遍歷找到的每個鍵的實際插入位置x,然後根據不同情況進行處理。
這樣做的目的是能夠選出最真實的最少被存取的key,能夠正確選擇不常使用的key。因為在Redis3.0之前是隨機選取樣本,這樣的方式很有可能不是真正意義上的最少存取的key。LRU演演算法有一個弊端,假如一個key值存取頻率很低,但是最近一次被存取到了,那LRU會認為它是熱點資料,不會被淘汰。同樣,經常被存取的資料,最近一段時間沒有被存取,這樣會導致這些資料被淘汰掉,導致誤判而淘汰掉熱點資料,於是在Redis 4.0中,新加了一種LFU演演算法。
LFU(Least Frequently Used),表示最近最少使用,它和key的使用次數有關,其思想是:根據key最近被存取的頻率進行淘汰,比較少存取的key優先淘汰,反之則保留。LFU的原理是使用計數器來對key進行排序,每次key被存取時,計數器會增大,當計數器越大,意味著當前key的存取越頻繁,也就是意味著它是熱點資料。 它很好的解決了LRU演演算法的缺陷:一個很久沒有被存取的key,偶爾被存取一次,導致被誤認為是熱點資料的問題。LFU的實現原理如下圖所示,LFU維護了兩個連結串列,橫向組成的連結串列用來儲存存取頻率,每個存取頻率的節點下儲存另外一個具有相同存取頻率的快取資料。具體的工作原理是:
新增元素時,存取頻率預設為1,隨著存取次數的增加,頻率不斷遞增。而當前被存取的元素也會隨著頻率增加進行移動。
到此這篇關於深入理解Redis記憶體淘汰策略的文章就介紹到這了,更多相關Redis記憶體淘汰內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45