衡阳派盒市场营销有限公司

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Redis的LRU實現(xiàn)和應用

馬哥Linux運維 ? 來源:稀土掘金技術社區(qū) ? 2023-12-15 09:24 ? 次閱讀

編程中,計數(shù)器是一種基本但強大的工具,用于跟蹤和管理數(shù)據(jù)和資源。本文將深入探討不同類型的計數(shù)器的應用,從Redis的LRU(最近最少使用)緩存淘汰算法的實現(xiàn),到如何在內存受限的環(huán)境中有效地使用計數(shù)器,再到普通計數(shù)器的巧妙應用。

1. Redis的LRU實現(xiàn)

Redis,作為一個高性能的鍵值存儲系統(tǒng),使用LRU算法來決定淘汰哪些數(shù)據(jù)以釋放內存。這個算法的關鍵在于跟蹤每個對象最后一次被訪問的時間,但為了節(jié)約內存,Redis并不使用完整的時間戳。相反,它采用了一種巧妙的方法:

時間戳精度的簡化:Redis通過將時間戳除以一個固定的分辨率(例如1000毫秒)來降低其精度。

位數(shù)限制:Redis進一步使用固定位數(shù)(例如24位)來存儲這些簡化的時間戳。

按位與操作:通過使用按位與操作確保計數(shù)器在達到最大值后自動從零開始,有效避免溢出。

這種方法在減少內存占用和保持時間戳更新效率之間取得了平衡,從而使LRU算法的實現(xiàn)既高效又節(jié)省空間。

Redis計算LRU時間的源碼如下(6.0.6)


#define LRU_BITS 24
#define LRU_CLOCK_MAX ((1<lru */
#define LRU_CLOCK_RESOLUTION 1000 




 * in a reduced-bits format that can be used to set and check the
 * object->lru field of redisObject structures. */
unsigned int getLRUClock(void) {
    return (mstime()/LRU_CLOCK_RESOLUTION) & LRU_CLOCK_MAX;
}

在Redis的LRU算法實現(xiàn)中,使用24位來存儲時間戳是一種權衡內存使用和精度的方法。下面我們分析這種方法的具體細節(jié):

24位時間戳的最大值:

首先,24位可以表示的最大值是 (2^{24} - 1),即16777215。這是因為每個二進制位有兩個可能的值(0或1),所以24位可以表示 (2^{24}) 個不同的值,從0開始計數(shù),最大值就是 (2^{24} - 1)。

精度

Redis中,時間戳的精度被降低到秒。這意味著每個時間戳表示從某個固定點(通常是Unix紀元,即1970年1月1日0000 UTC)開始的秒數(shù)。

相對時間點

使用24位存儲時間戳,意味著能夠表示的最大秒數(shù)是16777215秒。換算成更直觀的時間單位:

天數(shù):194天

小時數(shù): 4655小時

因此,24位時間戳可以表示從某個起始點開始的大約194天內的任意秒。

位運算和精度

當時間戳的值超過24位可以表示的最大值時,由于按位與操作(與16777215按位與),時間戳將自動回繞到0。這意味著每過194天左右,時間戳就會重置。重置后的時間戳值是從0開始的,但這并不影響Redis LRU算法的有效性,因為該算法主要關心的是對象相對于彼此的“最近使用”狀態(tài),而不是絕對的時間點。

總結

所以,在Redis的LRU算法中,雖然時間戳的精度仍然是秒,但由于使用24位存儲,它只能表示大約194天的時間跨度。一旦超過這個時間跨度,時間戳就會回繞。這種設計在維持足夠精度的同時,大幅減少了每個對象的內存占用,非常適合于內存受限的高效緩存系統(tǒng)。

2. 內存效率和時間戳的近似表示

除了Redis的應用,固定位數(shù)的計數(shù)器在其他許多場景中也非常有用,特別是在需要以內存高效的方式存儲大量數(shù)據(jù)時。以下是兩個具體的應用示例:

2.1 內存效率的例子

假設你正在開發(fā)一個高性能的日志處理系統(tǒng),該系統(tǒng)需要跟蹤數(shù)百萬條日志記錄的時間戳。如果使用完整的64位時間戳(精確到毫秒),對于每個日志記錄,時間戳將占用8字節(jié)的存儲空間。這在大量數(shù)據(jù)的情況下會導致巨大的內存消耗。

為了提高內存效率,你可以選擇使用24位來表示時間戳。雖然這會減少時間的精度,但對于很多日志分析任務來說,這種精度已經足夠。在這種情況下,每個時間戳只占用3字節(jié)的存儲空間。

通過這種方法,你可以顯著減少內存使用,同時仍然保留了足夠的信息來進行有效的日志分析。

不節(jié)省內存情況

使用標準的64位時間戳(精確到毫秒)。

每個時間戳占用8字節(jié)。

總內存使用量 = 100萬個事件 × 8字節(jié)/事件 = 800萬字節(jié)(約7.63 MB)。

節(jié)省內存情況

使用24位時間戳(精確到某個更大的時間單位,比如分鐘)。

每個時間戳占用3字節(jié)。

總內存使用量 = 100萬個事件 × 3字節(jié)/事件 = 300萬字節(jié)(約2.86 MB)。

節(jié)省效果

節(jié)省了約4.77 MB的內存。

對于某些應用(如日志分析),精確到分鐘可能已足夠,因此這種方法既節(jié)省內存又能提供所需的時間信息。

2.2 時間戳的近似表示

考慮一個網站緩存系統(tǒng),它需要記錄每個頁面最后一次被訪問的時間。通過將Unix時間戳轉換為以10分鐘為單位的近似值,可以減少存儲需求,同時仍然提供足夠的信息來有效管理緩存。

下面是一個舉例說明:

完整精度情況

使用完整的32位Unix時間戳(精確到秒)。

時間戳示例:1617181723(代表2021年3月31日1423 UTC)。

近似精度情況

使用簡化的20位時間戳(以10分鐘為單位)。

假設我們以2021年1月1日為基準,計算從那時起經過的10分鐘間隔的數(shù)量。

時間戳示例:對于2021年3月31日14:15的時間,計算得到的20位時間戳可能是99000(這是一個假設的值,具體取決于基準日期和計算方法)。

精度對比

完整精度時間戳能精確到秒。

近似精度時間戳精確到10分鐘,對于緩存淘汰決策而言,這通常是足夠的。例如,它可以用來判斷一個頁面是在最近一小時內被訪問過,還是在更久之前。

3. 循環(huán)計數(shù)器的實際應用

利用固定位數(shù)和按位與操作實現(xiàn)高效的循環(huán)計數(shù)器

在編程中,經常需要跟蹤特定的事件或狀態(tài)的次數(shù),尤其是在資源受限(如內存或存儲空間有限)的環(huán)境中。傳統(tǒng)的方法可能會涉及檢查計數(shù)器是否達到某個值,然后手動將其重置。然而,這種方法既繁瑣又容易出錯。幸運的是,有一種更優(yōu)雅、高效的方法可以實現(xiàn)同樣的目標:使用固定位數(shù)的計數(shù)器結合按位與操作。

固定位數(shù)計數(shù)器的原理

固定位數(shù)計數(shù)器的概念很簡單。就是選擇一個特定的位數(shù)(比如16位、24位或32位)來存儲計數(shù)器的值。這個選擇直接決定了計數(shù)器的最大值,計數(shù)器的最大值為 (2^{位數(shù)} - 1)。例如,一個24位計數(shù)器的最大值是 (2^{24} - 1 = 16777215)。

為何選擇按位與操作

按位與操作 (&) 是一種基本的位運算,它對兩個數(shù)的每一位進行比較,只有當相同位置的兩個位都為1時,結果的那位才為1。在這種用法中,它的作用是確保計數(shù)器值在達到其最大值后自動歸零。

實現(xiàn)步驟

確定位數(shù):首先,確定你需要的計數(shù)器位數(shù)。這將取決于你的特定應用和所需的最大計數(shù)范圍。

計算掩碼值:計算掩碼值,即計數(shù)器的最大值。對于一個N位計數(shù)器,掩碼值為 (2^N - 1)。

應用按位與:在增加計數(shù)器值時使用按位與操作,以確保計數(shù)器在達到最大值后自動回繞。

示例代碼

假設我們使用一個16位計數(shù)器:


#include 


#define COUNTER_BITS 16
#define COUNTER_MAX ((1 << COUNTER_BITS) - 1)


int main() {
    unsigned int counter = 0;


    for(int i = 0; i < 70000; i++) {
        counter = (counter + 1) & COUNTER_MAX;
        // 可以在這里執(zhí)行其他操作
    }


    printf("Final counter value: %u
", counter);
    return 0;
}


在這個例子中,計數(shù)器將在65535之后回繞到0,這種方法適用于需要循環(huán)計數(shù)器的場景,如緩存淘汰、時間標記或狀態(tài)跟蹤。

結論

使用固定位數(shù)和按位與操作的循環(huán)計數(shù)器是一種節(jié)省資源、減少錯誤和提高代碼效率的強大工具。特別是在內存和存儲資源受限的情況下,這種方法顯得尤為重要。通過簡單的位運算,我們可以優(yōu)雅地實現(xiàn)計數(shù)器的自動回繞功能,從而使我們的代碼更加簡潔和健壯。

4. 如何有效存儲固定位數(shù)

在大多數(shù)編程環(huán)境中,基本的整型(如int)通常占用4字節(jié)(32位)。對于只需要3字節(jié)來存儲的情況,確實會面臨內存分配和管理的挑戰(zhàn)。有幾種方法可以處理這種情況:

使用位域結構體

在C或C++中,你可以使用位域(bit fields)在結構體中精確指定每個成員的位數(shù)。例如,你可以定義一個24位的位域來存儲時間戳:


struct Timestamp {
    unsigned int time: 24;
};

這種方法允許你以3字節(jié)的存儲空間存儲時間戳,但它可能會引起端對齊(endian)問題,因此在跨平臺時需要小心處理。

使用字節(jié)數(shù)組你也可以使用一個字節(jié)數(shù)組(如3個char或uint8_t)來存儲這個值。在這種情況下,你需要手動處理值的設置和解析:


uint8_t timestamp[3];


// 設置值(示例)
timestamp[0] = (value >> 16) & 0xFF; // 最高有效字節(jié)
timestamp[1] = (value >> 8) & 0xFF;  // 中間字節(jié)
timestamp[2] = value & 0xFF;         // 最低有效字節(jié)


// 解析值
uint32_t recovered_value = (timestamp[0] << 16) | (timestamp[1] << 8) | timestamp[2];

這種方法給予了你更多控制,但增加了代碼的復雜性。

使用內置類型并接受一些空間浪費

有時,簡單地使用標準的4字節(jié)整型(如int或uint32_t)可能是更實際的選擇,即使這意味著你不會完全利用所有的位。雖然這會浪費一些空間,但代碼會更簡單、更清晰,并且更容易維護。這在不是極度內存受限的環(huán)境下通常是可接受的。

選擇方法

選擇哪種方法取決于你的具體需求。如果內存效率至關重要,并且你能夠處理額外的復雜性,那么使用位域或字節(jié)數(shù)組可能是合適的。如果代碼的可讀性和維護性更重要,那么簡單地使用標準的整型類型可能是更好的選擇。

鏈接:https://juejin.cn/post/7312035412159528969

(版權歸原作者所有,侵刪)

原文標題:從Redis的LRU實現(xiàn)到內存效率和位操作

文章出處:【微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 算法
    +關注

    關注

    23

    文章

    4630

    瀏覽量

    93360
  • 內存
    +關注

    關注

    8

    文章

    3055

    瀏覽量

    74334
  • 計數(shù)器
    +關注

    關注

    32

    文章

    2261

    瀏覽量

    94986
  • Redis
    +關注

    關注

    0

    文章

    378

    瀏覽量

    10945

原文標題:從Redis的LRU實現(xiàn)到內存效率和位操作

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    LRU緩存模塊最佳實踐

    lru模塊,可以方便地實現(xiàn)LRU緩存。 基礎用法 Cargo.toml引入 lru 模塊 lru = "0.10.0" 創(chuàng)建一個
    的頭像 發(fā)表于 09-30 16:47 ?958次閱讀

    Redis Stream應用案例

    的基本使用介紹和設計理念可以看我之前的一篇文章(Redis Stream簡介)。Redis Stream本質上是在Redis內核上(非Redis Module)
    發(fā)表于 06-26 17:15

    Redis Cluster的基本原理及實現(xiàn)細節(jié)

    Redis Cluster的基本原理和架構 Redis Cluster是分布式Redis實現(xiàn)。隨著Redis版本的更替,以及各種已知bug
    發(fā)表于 09-28 19:09 ?0次下載
    <b class='flag-5'>Redis</b> Cluster的基本原理及<b class='flag-5'>實現(xiàn)</b>細節(jié)

    redis設計與實現(xiàn)

    redis
    發(fā)表于 06-20 14:44 ?0次下載

    談談Redis怎樣配置實現(xiàn)主從復制?

    之前總結過redis的持久化機制:深度剖析Redis持久化機制,持久化機制主要解決redis數(shù)據(jù)單機備份問題;redis的高可用需要考慮數(shù)據(jù)的多機備份,多機備份通過主從復制來
    發(fā)表于 01-31 11:31 ?685次閱讀

    Redis實現(xiàn)限流的三種方式分享

    當然,限流有許多種實現(xiàn)的方式,Redis具有很強大的功能,我用Redis實踐了三種的實現(xiàn)方式,可以較為簡單的實現(xiàn)其方式。
    的頭像 發(fā)表于 02-22 09:52 ?1134次閱讀

    設計并實現(xiàn)一個滿足LRU約束的數(shù)據(jù)結構

    LRUCache(int capacity)` 以 **「正整數(shù)」** 作為容量 `capacity` 初始化 `LRU` 緩存
    的頭像 發(fā)表于 06-07 17:05 ?1060次閱讀
    設計并<b class='flag-5'>實現(xiàn)</b>一個滿足<b class='flag-5'>LRU</b>約束的數(shù)據(jù)結構

    RedisLRU與LFU算法實現(xiàn)

    Redis是一款基于內存的高性能NoSQL數(shù)據(jù)庫,數(shù)據(jù)都緩存在內存里, 這使得Redis可以每秒輕松地處理數(shù)萬的讀寫請求。
    的頭像 發(fā)表于 07-11 09:48 ?1254次閱讀
    <b class='flag-5'>Redis</b>的<b class='flag-5'>LRU</b>與LFU算法<b class='flag-5'>實現(xiàn)</b>

    Redis工具集的實現(xiàn)和使用

    Redis 基本上是互聯(lián)網公司必備的工具了,Redis的應用場景實在太多了,但是有很多相似的功能如果每個項目都要實現(xiàn)一遍就顯得太麻煩了,所以為了方便,我打算開發(fā)一個基于 Redis
    的頭像 發(fā)表于 12-03 17:32 ?1286次閱讀
    <b class='flag-5'>Redis</b>工具集的<b class='flag-5'>實現(xiàn)</b>和使用

    Java redis鎖怎么實現(xiàn)

    在Java中實現(xiàn)Redis鎖涉及到以下幾個方面:Redis的安裝配置、Redis連接池的使用、Redis數(shù)據(jù)結構的選擇、
    的頭像 發(fā)表于 12-04 10:47 ?1214次閱讀

    redis的淘汰策略

    的寫入。 Redis的淘汰策略主要有以下幾種: LRU(Least Recently Used,最近最少使用): 這是Redis默認的淘汰策略。當內存空間不足時,Redis會選擇最近最
    的頭像 發(fā)表于 12-04 16:23 ?595次閱讀

    redis hash底層實現(xiàn)原理

    數(shù)據(jù)結構是如何實現(xiàn)的呢?本文將詳細介紹Redis哈希底層的實現(xiàn)原理。 在Redis中,每個哈希都是由一個類似于字典(Dictionary)的結構實現(xiàn)
    的頭像 發(fā)表于 12-04 16:27 ?621次閱讀

    redislru原理

    Redis是一種基于內存的鍵值數(shù)據(jù)庫,它使用了LRU(Least Recently Used)算法來進行緩存的數(shù)據(jù)淘汰。LRU算法的核心思想是最近最少使用的數(shù)據(jù)將會在未來也不常用,因此應該優(yōu)先
    的頭像 發(fā)表于 12-05 09:56 ?672次閱讀

    redis數(shù)據(jù)結構的底層實現(xiàn)

    Redis是一種內存鍵值數(shù)據(jù)庫,常用于緩存、消息隊列、實時數(shù)據(jù)分析等場景。它的高性能得益于其精心設計的數(shù)據(jù)結構和底層實現(xiàn)。本文將詳細介紹Redis常用的數(shù)據(jù)結構和它們的底層實現(xiàn)
    的頭像 發(fā)表于 12-05 10:14 ?665次閱讀

    關于LRU(Least Recently Used)的邏輯實現(xiàn)

    湊巧看到一個有關LRU(Least Recently Used)的邏輯實現(xiàn),其采用矩陣方式進行實現(xiàn),看起來頗有意思,但文章中只寫方法不說原理,遂來研究下。LRU(Least Rece
    的頭像 發(fā)表于 11-12 11:47 ?406次閱讀
    關于<b class='flag-5'>LRU</b>(Least Recently Used)的邏輯<b class='flag-5'>實現(xiàn)</b>
    库尔勒市| 娱百家乐官网下载| 菲彩线上娱乐| 澳门百家乐官网网上赌城| 百家乐在线娱乐可信吗| 香港六合彩开奖现场直播| 百家乐官网长龙太阳城| 大家旺百家乐娱乐城| 大发888游戏论坛| 百家乐官网赌场论坛| 新百家乐的玩法技巧和规则| 百家乐怎么玩呀| 六合彩开奖结果| CEO百家乐官网的玩法技巧和规则| 百家乐专打方法| 百家乐官网最新的投注方法| 有破解百家乐仪器| 新田县| 百家乐开户平台| 都江堰市| 在线百家乐博彩网| 海南省| 静宁县| 百家乐怎么玩呀| 台南县| 真人百家乐代理合作| 濉溪县| 永利百家乐娱乐场| 开心8百家乐官网娱乐城| 电子百家乐打法| 赌场百家乐官网玩法介绍| 博彩百家乐最新优惠| 澳门百家乐官网破解方法| 互联网百家乐的玩法技巧和规则| 百家乐官网桌颜色可定制| 全迅网百家乐的玩法技巧和规则 | 菲彩百家乐官网的玩法技巧和规则| 博彩行业| 怎么玩百家乐能赢钱| 网上百家乐官网有假的吗| 百家乐庄闲出现几|