Redis刪除大量key後,佔用的系統記憶體卻沒有釋放?

雨瀟先生發表於2020-11-13

我們首先來看看官方關於Redis記憶體管理的說明。

原文如下:https://redis.io/topics/memory-optimization#memory-allocation

Memory allocation

To store user keys, Redis allocates at most as much memory as the setting enables (however there are small extra allocations possible).maxmemory

The exact value can be set in the configuration file or set later via CONFIG SET (see Using memory as an LRU cache for more info). There are a few things that should be noted about how Redis manages memory:

Redis will not always free up (return) memory to the OS when keys are removed. This is not something special about Redis, but it is how most malloc() implementations work. For example if you fill an instance with 5GB worth of data, and then remove the equivalent of 2GB of data, the Resident Set Size (also known as the RSS, which is the number of memory pages consumed by the process) will probably still be around 5GB, even if Redis will claim that the user memory is around 3GB. This happens because the underlying allocator can't easily release the memory. For example often most of the removed keys were allocated in the same pages as the other keys that still exist.

The previous point means that you need to provision memory based on your peak memory usage. If your workload from time to time requires 10GB, even if most of the times 5GB could do, you need to provision for 10GB.However allocators are smart and are able to reuse free chunks of memory, so after you freed 2GB of your 5GB data set, when you start adding more keys again, you'll see the RSS (Resident Set Size) stay steady and not grow more, as you add up to 2GB of additional keys. The allocator is basically trying to reuse the 2GB of memory previously (logically) freed.Because of all this, the fragmentation ratio is not reliable when you had a memory usage that at peak is much larger than the currently used memory. The fragmentation is calculated as the physical memory actually used (the RSS value) divided by the amount of memory currently in use (as the sum of all the allocations performed by Redis). Because the RSS reflects the peak memory, when the (virtually) used memory is low since a lot of keys / values were freed, but the RSS is high, the ratio will be very high.RSS / mem_used If is not set Redis will keep allocating memory as it finds fit and thus it can (gradually) eat up all your free memory. Therefore it is generally advisable to configure some limit. You may also want to set to (which is not the default value in some older versions of Redis).maxmemorymaxmemory-policynoeviction.It makes Redis return an out of memory error for write commands if and when it reaches the limit - which in turn may result in errors in the application but will not render the whole machine dead because of memory starvation.

翻譯如下:

 

記憶體分配

為了儲存使用者金鑰,Redis最多分配設定允許的記憶體(但是也有少量的額外分配),確切的值可以在配置檔案中設定,也可以在以後通過配置集進行設定(有關更多資訊,請參閱將記憶體用作LRU快取)。

關於Redis如何管理記憶體,需要注意以下幾點:當金鑰被移除時,Redis並不總是將記憶體釋放(返回)給作業系統。這並不是Redis的獨特之處,它是大多數malloc()實現的工作方式。例如,如果您用5GB的資料填充一個例項,然後刪除相當於2GB的資料,則駐留集大小(Resident Set Size)(也稱為RSS,即程式消耗的記憶體頁數)可能仍將在5GB左右,即使Redis會聲稱使用者記憶體約為3GB。發生這種情況是因為底層分配器無法輕鬆釋放記憶體。例如,通常大多數被移除的鍵與仍然存在的其他鍵分配在同一頁中。前一點意味著您需要根據峰值記憶體使用情況來配置記憶體。如果您的工作負載不時需要10GB,即使大多數情況下5GB都可以,您也需要為10GB進行調配。不過,分配器是智慧的,能夠重用空閒記憶體塊,因此,當您釋放了2GB的5GB資料集後,當您再次開始新增更多金鑰時,您將看到RSS(駐留集大小)保持穩定,而不會增加,因為您新增了2GB的額外金鑰。分配器基本上是在嘗試重用先前(邏輯上)釋放的2GB記憶體。

正因為如此,當記憶體使用率峰值遠大於當前使用的記憶體時,碎片率是不可靠的。碎片計算為實際使用的實體記憶體(RSS值)除以當前使用的記憶體量(作為Redis執行的所有分配的總和)。因為RSS反映了峰值記憶體,當(實際上)使用的記憶體很低,因為釋放了很多鍵/值,但是RSS很高,那麼這個比率會非常高。如果RSS/mem_used沒有設定,Redis將繼續分配它認為合適的記憶體,因此它可以(逐漸)吃掉你所有的空閒記憶體。因此,通常建議配置一些限制。您可能還需要設定為(這不是某些舊版本的Redis的預設值)

它使Redis在達到限制時返回write命令的記憶體不足錯誤-這反過來可能導致應用程式出錯,但不會因為記憶體不足而導致整個機器當機。

綜上所述(官方說明),我們不用再擔心這個問題了。其實這樣也有個好處,就是如果再有key寫入,則無需再去申請系統記憶體,來減少記憶體申請操作。如果非要把這些Redis空閒空間返還作業系統可以執行命令MEMORY PURGE來進行空間整理,或者開啟activedefrag,進行熱碎片整理(該操作在主執行緒執行,會佔用CPU,可以設定CPU佔用率)。

相關文章