搜尋
首頁資料庫Redis詳解Redis的LRU演算法

詳解Redis的LRU演算法

Aug 27, 2020 pm 01:33 PM
redis

下面由Redis教學專欄給大家詳解Redis的LRU演算法,希望對需要的朋友有幫助!

詳解Redis的LRU演算法

Redis的LRU演算法

LRU演算法背後的想法在電腦科學中無所不在,它與程式的"局部性原理"很相似。在生產環境中,雖然有Redis記憶體使用警告,但是了解Redis的快取使用策略還是很有好處的。以下是生產環境下Redis使用策略:最大可用記憶體限制為4GB,採用 allkeys-lru 刪除策略。所謂刪除策略:當redis使用已經達到了最大內存,例如4GB時,如果這時候再往redis裡面添加新的Key,那麼Redis將選擇一個Key刪除。那如何選擇適合的Key刪除呢?

CONFIG GET maxmemory

  1. "maxmemory"
  2. "4294967296"

#CONFIG GET maxmemory-policy

  1. #"maxmemory-policy"
  2. "allkeys-lru"

在官方文件Using Redis as an LRU cache描述中,提供了好幾種刪除策略,如allkeys-lru、volatile-lru等。在我看來按選擇時考慮三個因素:隨機、Key最近被訪問的時間、Key的過期時間(TTL)

例如:allkeys-lru,"統計一下所有的"Key歷史訪問的時間,把"最老"的那個Key移除。注意:我在這裡加了引號,其實在redis的具體實作中,要統計所有的Key最近的訪問時間代價是很大的。想想,如何做到呢?

evict keys by trying to remove the less recently used (LRU) keys first, in order to make space for the new data added.

再例如:allkeys- random,就是隨機選擇一個Key,將之移除。

evict keys randomly in order to make space for the new data added.

再例如:volatile-lru,它只移除那些使用expire 指令設定了過期時間的Key,根據LRU演算法來移除。

evict keys by trying to remove the less recently used (LRU) keys first, but only among keys that have an expire set, in order to make space for the new dataspace for the new data added.

再例如:volatile-ttl,它只移除那些使用expire 指令設定了過期時間的Key,哪個Key的存活時間(TTL KEY 越小)越短,就優先移除。

evict keys with an expire set, and try to evict keys with a shorter time to live (TTL) first, in order to make space for the new data added.

volatile 策略(eviction methods) 作用的Key 是那些設定了過期時間的Key。在redisDb結構體中,定義了一個名為expires 字典(dict)保存所有的那些用expire指令設定了過期時間的key,其中expires字典的鍵指向redis 資料庫鍵空間(redisServer-- ->redisDb--->redisObject)中的某個鍵,而expires字典的值則是這個鍵的過期時間(long型別整數)。
額外提一下:redis 資料庫鍵空間是指:在結構體redisDb中定義的一個名為"dict",類型為hash字典的一個指針,它用來保存該redis DB中的每一個鍵物件、以及對應的值物件。

既然有這麼多策略,那我用哪個好呢?這就涉及到Redis中的Key的訪問模式了(access-pattern),access-pattern與代碼業務邏輯相關,比如說符合某種特徵的Key經常被訪問,而另一些Key卻不怎麼用到。如果所有的Key都可能機會均等地被我們的應用程式訪問,那麼它的訪問模式服從均勻分佈;而大部分情況下,訪問模式服從冪指分佈(power-law distribution),另外Key的存取模式也有可能是隨著時間變化的,因此需要一種合適的刪除策略能夠catch 住(捕獲住)各種情形。而在冪指分佈下,LRU是一種很好的策略:

While caches can't predict the future, they can reason in the following way: keys that are likely to be requested again are keys that were recently requested often. Since usually access patterns don't change very suddenly, this is an effective strategy.

Redis中LRU策略的實現

##最直觀的想法:LRU啊,記錄下每個key 最近一次的訪問時間(例如unix timestamp),unix timestamp最小的Key,就是最近未使用的,把這個Key移除。看下來一個HashMap就能搞定啊。是的,但是首先需要儲存每個Key和它的timestamp。其次,還要比較timestamp得到最小值。代價很大,不切實際啊。

第二種方法:換個角度,不記錄具體的訪問時間點(unix timestamp),而是記錄idle time:idle time越小,意味著是最近被訪問的。

The LRU algorithm evicts the Least Recently Used key, which means the one with the greatest idle time.

如A、B、C 、D四個Key,A每5s訪問一次,B每2s訪問一次,C和D每10s訪問一次。 (一個波浪號代表1s),從上圖可看出:A的空閒時間是2s,B的idle time是1s,C的idle time是5s,D剛剛訪問了所以idle time是0s

這裡,用一個雙向鍊錶(linkedlist)把所有的Key鍊錶起來,如果一個Key被訪問了,將就這個Key移到鍊錶的表頭,而要移除Key時,直接從錶尾移除。

It is simple to implement because all we need to do is to track the last time a given key was accessed, or sometimes this is not even needed: we may just have all the objects is not even needed: we may just have all the obant towe evict linked in a linked list.

但是在redis中,並沒有採用這種方式實現,它嫌LinkedList佔用的空間太大了。 Redis並不是直接基於字串、鍊錶、字典等資料結構來實作KV資料庫,而是在這些資料結構上創建了一個物件系統Redis Object。在redisObject結構體中定義了一個長度24bit的unsigned類型的字段,用來儲存物件最後一次被命令程式存取的時間:

By modifying a bit the Redis Object structure I was able to make 24 bits of space. There was no room for linking the objects in a linked list (fat pointers!)

畢竟,並不需要一個完全準確的LRU演算法,就算移除了一個最近訪問過的Key,影響也不太。

To add another data structure to take this metadata was not an option, however since LRU is itself an approximation of what we want to achieve, what about #roximating LRU its#p? ##最初Redis是這樣實現的:

隨機選三個Key,把idle time最大的那個Key移除。後來,把3改成可設定的參數,預設為N=5:

maxmemory-samples 5

when there is to evict a key, select 3 random keys, and evict the one with the highest idle time

就是這麼簡單,簡單得讓人不敢相信了,而且十分有效。但它還是有缺點的:每次隨機選擇的時候,並沒有利用

歷史資訊
。在每一回合移除(evict)一個Key時,隨機從N個裡面選一個Key,移除idle time最大的那個Key;下一輪又是隨機從N個裡面選一個Key...有沒有想過:在上一輪移除Key的過程中,其實是知道了N個Key的idle time的情況的,那我能不能在下一輪移除Key時,利用好上一輪知曉的一些資訊?

However if you think at this algorithm

across
its executions, you can see how we are trashing a lot of interesting data. Maybe when sampling the N keys, lotwe encounter a lotwe of good candidates, but we then just evict the best, and start from scratch again the next cycle.

start from scratch太傻了。於是Redis又做了改進:採用緩衝池(pooling)

當每一輪移除Key時,拿到了這個N個Key的idle time,如果它的idle time比pool 裡面的Key的idle time還要大,就把它加到pool裡面去。這樣一來,每次移除的Key並不僅僅是隨機選擇的N個Key裡面最大的,而且還是pool裡面idle time最大的,並且:pool 裡面的Key是經過多輪比較篩選的,它的idle time 在機率上比隨機取得的Key的idle time要大,可以這麼理解:pool 裡面的Key 保留了"歷史經驗資訊"。

Basically when the N keys sampling was performed, it was used to populate a larger pool of keys (just 16 keys by default). This pool has the keys sor by idle time, default enter the pool when they have an idle time greater than one key in the pool or when there is empty space in the pool.

#採用"pool",把一個全局排序問題轉化成為了局部的比較問題。 (儘管排序本質上也是比較,囧)。要知道idle time 最大的key,精確的LRU需要對全域的key的idle time排序,然後就能找出idle time最大的key了。但可以採用一種近似的思想,即隨機採樣(samping)若干個key,這若干個key就代表著全局的key,把samping得到的key放到pool裡面,每次採樣之後更新pool,使得pool裡面總是保存著隨機選擇過的key的idle time最大的那些key。需要evict key時,直接從pool裡面取出idle time最大的key,將之evict掉。這種想法是很值得借鏡的。

至此,基於LRU的移除策略就分析完了。 Redis裡面還有一個基於LFU(訪問頻率)的移除策略,後面還有時間再說。

JAVA 裡面的LRU實作

JDK中的LinkedHashMap實作了LRU演算法,使用以下建構方法,accessOrder 表示"最近最少未使用"的衡量標準。例如accessOrder=true,當執行java.util.LinkedHashMap#get元素時,就表示這個元素最近被存取了。

/**
     * Constructs an empty <tt>LinkedHashMap</tt> instance with the
     * specified initial capacity, load factor and ordering mode.
     *
     * @param  initialCapacity the initial capacity
     * @param  loadFactor      the load factor
     * @param  accessOrder     the ordering mode - <tt>true</tt> for
     *         access-order, <tt>false</tt> for insertion-order
     * @throws IllegalArgumentException if the initial capacity is negative
     *         or the load factor is nonpositive
     */
    public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

再重寫:java.util.LinkedHashMap#removeEldestEntry方法即可。

The {@link #removeEldestEntry(Map.Entry)} method may be overridden to impose a policy for removing stale mappings automatically when new mappings are added to the map.

為了確保線程安全,用Collections.synchronizedMap將LinkedHashMap物件包裝起來:

Note that this implementation is not synchronized. If multiple threads access a linked hash map concurrently, and at l east one of the least one of the least map concurrently, and at l east one of the least one of the least com threads modifies the map structurally, it must be synchronized externally.  This is typically accomplished by synchronizing on some object that naturally encapsulates the map.search. #

final Map<long> timeoutInfoHandlers =
        Collections.synchronizedMap(new LinkedHashMap<long>(100, .75F, true) {
            @Override
            protected boolean removeEldestEntry(Map.Entry eldest) {
                return size() > 100;
            }
        });</long></long>
當容量超過100時,開始執行LRU策略:將最近最少未使用的TimeoutInfoHolder 物件 evict 掉。

參考連結:

Random notes on improving the Redis LRU algorithm

Using Redis as an LRU cache
  • 最後,再扯一點與本文不相關的東西:關於數據處理的一些思考:
  • 5G有能力讓各種各樣的節點都接入網絡,就會產生大量的數據,如何高效地處理這些數據、挖掘數據(機器學習、深度學習)背後的隱藏的模式是一件非常有趣的事情,因為這些數據其實是人類行為的客觀反映。舉個例子,微信運動的計步功能,會讓你發現:哎,原來每天我的活動量大概維持在1萬步左右。再深入一步,以後各種工業設備、家用電器,都會產生各種各樣的數據,這些數據是社會商業活動的體現,也是人類活動的體現。如何合理地利用這些數據呢?現有的儲存系統能支撐這些資料的儲存嗎?有沒有一套高效率的運算系統(spark or tensorflow...)分析出資料中隱藏的價值?另外,基於這些資料訓練出來的演算法模型應用之後會不會帶來偏見?有沒有濫用數據?網路上買東西有演算法給你推薦,刷朋友圈會給你針對性的廣告,你需要藉多少錢,貸多少款也會有模型評估,看新聞、看娛樂八卦也有演算法推薦。你每天看到的東西、接觸的東西,有很多很多都是這些"數據系統"做的決策,它們真的公平嗎?現實中如果你犯了錯,有老師、朋友、家人給你回饋、糾正,你改了,一切還可以從頭開始。可在這些數據系統之下呢?有糾錯回饋機制嗎?會不會刺激人越陷越深?就算你很正直、有良好的信用,演算法模型也可能存在機率偏差,這是不是影響人類"公平競爭"的機會?這些都是數據開發人員值得思考的問題。
原文:https://www.cnblogs.com/hapjin/p/10933405.html

以上是詳解Redis的LRU演算法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:cnblogs。如有侵權,請聯絡admin@php.cn刪除
REDIS:探索其數據模型和結構REDIS:探索其數據模型和結構Apr 16, 2025 am 12:09 AM

Redis的數據模型和結構包括五種主要類型:1.字符串(String):用於存儲文本或二進制數據,支持原子操作。 2.列表(List):有序元素集合,適合隊列和堆棧。 3.集合(Set):無序唯一元素集合,支持集合運算。 4.有序集合(SortedSet):帶分數的唯一元素集合,適用於排行榜。 5.哈希表(Hash):鍵值對集合,適合存儲對象。

REDIS:對其數據庫方法進行分類REDIS:對其數據庫方法進行分類Apr 15, 2025 am 12:06 AM

Redis的數據庫方法包括內存數據庫和鍵值存儲。 1)Redis將數據存儲在內存中,讀寫速度快。 2)它使用鍵值對存儲數據,支持複雜數據結構,如列表、集合、哈希表和有序集合,適用於緩存和NoSQL數據庫。

為什麼要使用redis?利益和優勢為什麼要使用redis?利益和優勢Apr 14, 2025 am 12:07 AM

Redis是一個強大的數據庫解決方案,因為它提供了極速性能、豐富的數據結構、高可用性和擴展性、持久化能力以及廣泛的生態系統支持。 1)極速性能:Redis的數據存儲在內存中,讀寫速度極快,適合高並發和低延遲應用。 2)豐富的數據結構:支持多種數據類型,如列表、集合等,適用於多種場景。 3)高可用性和擴展性:支持主從復制和集群模式,實現高可用性和水平擴展。 4)持久化和數據安全:通過RDB和AOF兩種方式實現數據持久化,確保數據的完整性和可靠性。 5)廣泛的生態系統和社區支持:擁有龐大的生態系統和活躍社區,

了解NOSQL:Redis的關鍵特徵了解NOSQL:Redis的關鍵特徵Apr 13, 2025 am 12:17 AM

Redis的關鍵特性包括速度、靈活性和豐富的數據結構支持。 1)速度:Redis作為內存數據庫,讀寫操作幾乎瞬時,適用於緩存和會話管理。 2)靈活性:支持多種數據結構,如字符串、列表、集合等,適用於復雜數據處理。 3)數據結構支持:提供字符串、列表、集合、哈希表等,適合不同業務需求。

REDIS:確定其主要功能REDIS:確定其主要功能Apr 12, 2025 am 12:01 AM

Redis的核心功能是高性能的內存數據存儲和處理系統。 1)高速數據訪問:Redis將數據存儲在內存中,提供微秒級別的讀寫速度。 2)豐富的數據結構:支持字符串、列表、集合等,適應多種應用場景。 3)持久化:通過RDB和AOF方式將數據持久化到磁盤。 4)發布訂閱:可用於消息隊列或實時通信系統。

REDIS:流行數據結構指南REDIS:流行數據結構指南Apr 11, 2025 am 12:04 AM

Redis支持多種數據結構,具體包括:1.字符串(String),適合存儲單一值數據;2.列表(List),適用於隊列和棧;3.集合(Set),用於存儲不重複數據;4.有序集合(SortedSet),適用於排行榜和優先級隊列;5.哈希表(Hash),適合存儲對像或結構化數據。

redis計數器怎麼實現redis計數器怎麼實現Apr 10, 2025 pm 10:21 PM

Redis計數器是一種使用Redis鍵值對存儲來實現計數操作的機制,包含以下步驟:創建計數器鍵、增加計數、減少計數、重置計數和獲取計數。 Redis計數器的優勢包括速度快、高並發、持久性和簡單易用。它可用於用戶訪問計數、實時指標跟踪、遊戲分數和排名以及訂單處理計數等場景。

redis命令行怎麼用redis命令行怎麼用Apr 10, 2025 pm 10:18 PM

使用 Redis 命令行工具 (redis-cli) 可通過以下步驟管理和操作 Redis:連接到服務器,指定地址和端口。使用命令名稱和參數向服務器發送命令。使用 HELP 命令查看特定命令的幫助信息。使用 QUIT 命令退出命令行工具。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。