<span id="ubbei"><video id="ubbei"></video></span>
<span id="ubbei"></span>
<span id="ubbei"><video id="ubbei"></video></span>
<strike id="ubbei"><video id="ubbei"></video></strike><th id="ubbei"></th>
<span id="ubbei"><video id="ubbei"></video></span><span id="ubbei"></span><span id="ubbei"><video id="ubbei"></video></span>
<th id="ubbei"><video id="ubbei"><span id="ubbei"></span></video></th>
<span id="ubbei"></span>
<th id="ubbei"><video id="ubbei"><span id="ubbei"></span></video></th><strike id="ubbei"><dl id="ubbei"><ruby id="ubbei"></ruby></dl></strike>
<span id="ubbei"></span>
<th id="ubbei"></th>
<span id="ubbei"></span>
<th id="ubbei"></th>
<span id="ubbei"></span>
<span id="ubbei"></span>
<span id="ubbei"></span>
<span id="ubbei"><video id="ubbei"><strike id="ubbei"></strike></video></span>
<strike id="ubbei"><video id="ubbei"></video></strike>

  • <output id="ubbei"></output>
          1. <li id="ubbei"><s id="ubbei"><strong id="ubbei"></strong></s></li>
          2. Redis 內存管理賞析

            聲明:本文是對 4.0.6版本 Redis的 內存管理部分的(xuexi)總結,有些YY的成分,作者本意不想誤導, 如有錯誤, 敬請諒解。

            一、凡事先問個為什么

            Redis是互聯網公司主流的分布式緩存解決方案,緩存的本質是“ 就近暫存 ”,解決的是“ 減少去較遠的地方拿我想要的東西要耗費較大成本 ”的問題。本小節我們要探究的不是為什么要用緩存,而是Redis為什么要做內存管理這件事情。決定一件事情做不做的理由 絕對不是 “這件事情可以做”,我認為Redis做內存管理的主要原因是: 內存(RAM)資源寶貴,內存管理讓內存的使用情況可控

            二、遵循底線、條條大路通羅馬

            那么怎么做內存管理呢?管理包括對個體的管理和對總體的管理,個體上比如對Redis中存儲的每個對象的大小,質量等進行管理;Redis的做法遵循 簡單原則 ,在內存使用的總量上劃一道“ 允許最大使用內存量 ”這條底線。為了遵循這條底線,Redis在實現上是這么做的:當使用內存量高于這條底線的時候,所有的寫操作將會直接失敗,絕不手軟,但是這個時候仍然理智地支持讀操作。在底線的基礎之上Redis提供的管理手段是“淘汰機制”,注意 淘汰機制是管理的一種手段 。那么怎么淘汰呢?按大小?按年齡?Redis提供以下幾種選擇淘汰KEY的策略:

            LRU: 看看哪個KEY最長時間沒有被使用啦,就選你吧,你看你這么長時間都沒被使用了,就別站著地方了。

            LFU: 如果說上面的方法較為片面,那這里就加上一個期限,看看哪個KEY在一段時間內訪問的頻率最低好吧,誰最低,淘汰誰。

            RANDOM: 不想那么多了,整個世界都是隨機的,隨機的世界就隨機選擇一個KEY吧,愛咋咋地。

            TTL: 選擇最近即將過期的KEY進行淘汰。

            最后一種比較有意思,那就是—— 不淘汰 ,哈哈, 對于一個問題不去解決往往也是一種解決方案

            三、難易相成、長短相形

            在主從模式且主庫開啟maxmemory策略的情況下,對于與主庫來說,如果用于從庫同步的緩沖區也被作為內存使用量計算進來,在某些極端情況下,比如:主從之間網絡出現異常,這個時候內存使用又達到閾值,顯然Redis此時會進行eviction操作,eviction操作本身會產生大量的DELs操作日志用于同步給從庫,這部分日志有會填充在主從同步緩存中,由于這部分內存會被計算進內存使用量,因此又會觸發eviction操作,然后繼續惡性循環……,直至最后內存被清空。 引入一種方案時長會伴隨著引入新的問題和憂患,這需要我們提高警惕 ,那么怎么解決這個問題呢?Redis的做法很簡單,就是用于從庫同步的緩沖區內存大小不作為使用內存計算的,這樣就不會存在上述問題了。在實際使用中,當以主從模式使用Redis且開啟了maxmemory策略的時候,建議maxmemory這個值設置稍微小一些,預留一部分給主動同步緩沖區使用。

            四、損有余、補不足

            在實際實現LRU、LFU和最小TTL算法的時候面臨一些問題,比如LRU算法要求淘汰最長時間沒有使用的KEY,如果要精準滿足“ 最長時間沒有使用 ”這個條件,我們必須要遍歷所有的KEY然后才能根據其上次使用的時間計算出哪個KEY是最長時間沒有被訪問的。問題來了,實際上Redis中可能存在成千上萬個KEY,每次都要挨個遍歷豈不是要瘋了? 實際想一想精確真的是我們想要的嗎? 實際Redis實現的LRU、LFU和最小TTL算法都是基于近似算法計算的,用 精確度換時間 (擴展一下hyperloglog是用準確性換空間),關鍵算法是:默認情況下Redis每次只隨機選擇5(可以通過maxmemory-samples參數設置,maxmemory-samples越大的時候越消耗內存,maxmemory-samples越小的時候越快,但是越不精確)個KEY,然后從這5個KEY中找到最符合條件的,這個思想其實也類似選擇擇局部最優,放棄全局最優的貪心算法。

            五、精益求精、追求卓越

            無論是LRU、LFU還是TTL都是基于系統時間的,在一般操作系統中,讀取系統的當前時間需要進行system call,system call意味著操作系統需要陷入內核態,陷入內核態意味著用戶態與內核態的上下文切換,上下文切換意味著成本……。為了實現內存淘汰,Redis需要為每個KEY都維護著一個這樣的時間,而且在KEY被訪問的時候需要讀取操作系統當前時間將其更新,試想一下,在上W QPS的應用場景下,每次都要去system call在高性能的場景下是一件多么恐怖的事情。實際Redis是怎么處理的呢?這里有個背景,Redis所謂的單線程指的是Redis對于客戶端讀寫的處理和內部的一些日常事務處理都是由一個eventloop線程來處理的,這里的日常事務包括一項:每次讀取當前系統時間記錄在一個變量里面。一般情況Redis所讀取的時間都是從這里讀取的,也就是由于eventloop線程提前計算好的,當然如果eventloop的loop頻率比較低的話這個值將會具有一定延遲。

            我來評幾句
            登錄后評論

            已發表評論數()

            相關站點

            +訂閱
            熱門文章
            陕西高频十一选五