面試官:熟悉Redis嗎,項目中你是如何對Redis內存進行優化的

對於redis來說,什麼是最重要的?

毋庸置疑,是內存。

一、reids 內存分析

redis內存使用情況:info memory

示例:

可以看到,當前節點內存碎片率爲226893824/209522728≈1.08,使用的內存分配器是jemalloc。

used_memory_rss 通常情況下是大於 used_memory 的,因爲內存碎片的存在。

但是當操作系統把redis內存swap到硬盤時,memory_fragmentation_ratio 會小於1。redis使用硬盤作爲內存,因爲硬盤的速度,redis性能會受到極大的影響。

二、redis 內存使用

之前的文章 關於redis,你需要了解的幾點!中我們簡單介紹過redis的內存使用分佈:自身內存,鍵值對象佔用、緩衝區內存佔用及內存碎片佔用。

https://www.cnblogs.com/niejunlei/p/12896605.html

redis 空進程自身消耗非常的少,可以忽略不計,優化內存可以不考慮此處的因素。

1、對象內存

對象內存,也即真實存儲的數據所佔用的內存。

redis k-v結構存儲,對象佔用可以簡單的理解爲 k-size + v-size

redis的鍵統一都爲字符串類型,值包含多種類型:string、list、hash、set、zset五種基本類型及基於string的Bitmaps和HyperLogLog類型等。

在實際的應用中,一定要做好kv的構建形式及內存使用預期,可以參考 關於redis,你需要了解的幾點!中關於不同值類型不同形式下的內部存儲實現介紹。

2、緩衝內存

緩衝內存包括三部分:客戶端緩存、複製積壓緩存及AOF緩衝區。

1)客戶端緩存

接入redis服務器的TCP連接輸入輸出緩衝內存佔用,TCP輸入緩衝佔用是不受控制的,最大允許空間爲1G。輸出緩衝佔用可以通過client-output-buffer-limit參數配置。

redis 客戶端主要分爲從客戶端、訂閱客戶端和普通客戶端。

從客戶端連接佔用:也就是我們所說的slave,主節點會爲每一個從節點建立一條連接用於命令複製,緩衝配置爲:client-output-buffer-limit slave 256mb 64mb 60

主從之間的間絡延遲及掛載的從節點數量是影響內存佔用的主要因素。因此在涉及需要異地部署主從時要特別注意,另外,也要避免主節點上掛載過多的從節點(<=2);

訂閱客戶端內存佔用:發佈訂閱功能連接客戶端使用單獨的緩衝區,默認配置:client-output-buffer-limit pubsub 32mb 8mb 60。

當消費慢於生產時會造成緩衝區積壓,因此需要特別注意消費者角色配比及生產、消費速度的監控。

普通客戶端內存佔用:除了上述之外的其它客戶端,如我們通常的應用連接,默認配置:client-output-buffer-limit normal 1000。

可以看到,普通客戶端沒有配置緩衝區限制,通常一般的客戶端內存消耗也可以忽略不計。

但是當redis服務器響應較慢時,容易造成大量的慢連接,主要表現爲連接數的突增,如果不能及時處理,此時會嚴重影響redis服務節點的服務及恢復。

關於此,在實際應用中需要注意幾點:

  • maxclients最大連接數配置必不可少。

  • 合理預估單次操作數據量(寫或讀)及網絡時延ttl。

  • 禁止線上大吞吐量命令操作,如keys等。

高併發應用情景下,redis內存使用需要有實時的監控預警機制,

2)複製積壓緩衝區

v2.8之後提供的一個可重用的固定大小緩衝區,用以實現向從節點的部分複製功能,避免全量複製。配置單數:repl-backlog-size,默認1M。單個主節點配置一個複製積壓緩衝區。

3)AOF緩衝區

AOF重寫期間增量的寫入命令保存,此部分緩存佔用大小取決於AOF重寫時間及增量。

3、內存碎片內存佔用

關於redis,你需要了解的幾點!簡單介紹過redis的內存分配方式。(更多面試題,歡迎關注公衆號 Java面試題精選)

三、redis 子進程內存消耗

子進程即redis執行持久化(RDB/AOF)時fork的子任務進程。

1、關於linux系統的寫時複製機制:

父子進程會共享相同的物理內存頁,父進程處理寫請求時會對需要修改的頁複製一份副本進行修改,子進程讀取的內存則爲fork時的父進程內存快照,因此,子進程的內存消耗由期間的寫操作增量決定。

2、關於linux的透明大頁機制THP(Transparent Huge Page):

THP機制會降低fork子進程的速度;寫時複製內存頁由4KB增大至2M。高併發情境下,寫時複製內存佔用消耗影響會很大,因此需要選擇性關閉。

3、關於linux配置:

一般需要配置linux系統 vm.overcommit_memory=1,以允許系統可以分配所有的物理內存。防止fork任務因內存而失敗。

四、redis 內存管理

redis的內存管理主要分爲兩方面:內存上限控制及內存回收管理。

1、內存上限:maxmemory

目的:緩存應用內存回收機制觸發 + 防止物理內存用盡(redis 默認無限使用服務器內存) + 服務節點內存隔離(單服務器上部署多個redis服務節點)

在進行內存分配及限制時要充分考慮內存碎片佔用影響。

動態調整,擴展redis服務節點可用內存:config set maxmemory {}

2、內存回收

回收時機:鍵過期、內存佔用達到上限

1)過期鍵刪除:

redis 鍵過期時間保存在內部的過期字典中,redis採用惰性刪除機制+定時任務刪除機制。

惰性刪除:即讀時刪除,讀取帶有超時屬性的鍵時,如果鍵已過期,則刪除然後返回空值。這種方式存在問題是,觸發時機,加入過期鍵長時間未被讀取,那麼它將會一直存在內存中,造成內存泄漏。

定時任務刪除:redis內部維護了一個定時任務(默認每秒10次,可配置),通過自適應法進行刪除。

刪除邏輯如下:

需要說明的一點是,快慢模式執行的刪除邏輯相同,這是超時時間不同。

2)內存溢出控制

當內存達到maxmemory,會觸發內存回收策略,具體策略依據maxmemory-policy來執行。

  • noevication:默認不回收,達到內存上限,則不再接受寫操作,並返回錯誤。

  • volatile-lru:根據LRU算法刪除設置了過期時間的鍵,如果沒有則不執行回收。

  • allkeys-lru:根據LRU算法刪除鍵,針對所有鍵。

  • allkeys-random:隨機刪除鍵。

  • volatitle-random:速記刪除設置了過期時間的鍵。

  • volatilte-ttl:根據鍵ttl,刪除最近過期的鍵,同樣如果沒有設置過期的鍵,則不執行刪除。

動態配置:config set maxmemory-policy {}

在設置了maxmemory情況下,每次的redis操作都會檢查執行內存回收,因此對於線上環境,要確保所這隻的maxmemory>used_memory

另外,可以通過動態配置maxmemory來主動觸發內存回收。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章