您好,登錄后才能下訂單哦!
本篇內容主要講解“Redis持久化時內存不足怎么處理”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Redis持久化時內存不足怎么處理”吧!
# Java錯誤日志: redis.clients.jedis.exceptions.JedisDataException: MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error. # Redis錯誤日志: Can't save in background: fork: Resource temporaily unavailable # 或 Can’t save in background: fork: Cannot allocate memory
Redis
在個默認情況下,如果在RDB snapshots
持久化過程中出現問題,Redis
不允許用戶進行任何更新操作;即:stop-writes-on-bgsave-error yes
。
臨時解決方案是通過命令:config set stop-writes-on-bgsave-error no
設置這個選項為false
,讓程序忽略了這個異常,使得程序能夠繼續往下運行,但寫硬盤仍然是失敗的!
Redis
在進行持久化的時候,有的時候可以在日志中看到fork進程失敗的提示,一般是系統可用的內存空間不夠導致,這需要我們對fork
原理明白,才能更好的進行參數調整。
一般來說Redis
在進行RDB
的時候,會fork
出一個子進程,子進程和父進程會共享一個地址空間,在fork
子進程的時候,會檢查當前機器可用的內存是否滿足fork
出一個子進程的要求,一般由操作系統overcommit_memory
(系統內存分配策略)決定。
Redis
的數據回寫機制分同步和異步兩種,
同步回寫即SAVE
命令,主進程直接向磁盤回寫數據。在數據大的情況下會導致系統假死很長時間,所以一般不是推薦的。
異步回寫即BGSAVE
命令,主進程fork
后,復制自身并通過這個新的進程回寫磁盤,回寫結束后新進程自行關閉。由于這樣做不需要主進程阻塞,系統不會假死,一般默認會采用這個方法。
Redis
默認采用異步回寫,所以如果我們要將數據刷到硬盤上,這時Redis
分配內存不能太大,否則很容易發生內存不夠用無法fork
的問題; 設置一個合理的寫磁盤策略,否則寫頻繁的應用,也會導致頻繁的fork
操作,對于占用了大內存的Redis
來說,fork
消耗資源的代價是很大的;
Linux
對大部分申請內存的請求都回復yes
,以便能跑更多更大的程序。
因為申請內存后,并不會馬上使用內存,將這些不會使用的空閑內存分配給其它程序使用,以提高內存利用率,這種技術叫做Overcommit
。
一般情況下,當所有程序都不會用到自己申請的所有內存時,系統不會出問題,但是如果程序隨著運行,需要的內存越來越大,在自己申請的大小范圍內,不斷占用更多內存,直到超出物理內存,當Linux
發現內存不足時,會發生OOM killer(OOM=out-of-memory)
。
OOM killer
會選擇殺死一些進程,以便釋放內存。當發生OOM killer
時,會記錄在系統日志中/var/log/messages
。
用戶態進程,非內核線程,占用內存越多和運行時間越短的進程越有可能被殺掉。
在Linux
下有個vm內核參數:CommitLimit
用于限制系統應用使用的內存資源;執行grep -i commit /proc/meminfo
,看到CommitLimit
和Committed_As
參數。
CommitLimit
是一個內存分配上限,CommitLimit = 物理內存 * overcommit_ratio(/proc/sys/vm/overcmmit_ratio,默認50,即50%) + swap大小
Committed_As
是已經分配的內存大小(應用程序要申請的內存 + 系統已經分配的內存)。
vm.overcommit_memory
文件指定了內核針對內存分配的策略,其值可以是0、1、2
。
0
:啟發策略(默認);表示內核將檢查是否有足夠的可用內存供應用進程使用;如果有足夠的可用內存,內存申請允許;否則,內存申請失敗,并把錯誤返回給應用進程。系統在為應用進程分配虛擬地址空間時,會判斷當前申請的虛擬地址空間大小是否超過剩余內存大小,如果超過,則虛擬地址空間分配失敗。因此,也就是如果進程本身占用的虛擬地址空間比較大或者剩余內存比較小時,fork
、malloc
等調用可能會失敗。 0
即是啟發式的overcommitting handle
,會盡量減少swap
交換分區的使用,root
可以分配比一般用戶略多的內存。
1
:允許overcommit
;表示內核允許分配所有的物理內存,而不管當前的內存狀態如何,允許超過CommitLimit
,這種情況下,避免了fork
可能產生的失敗,但由于malloc
是先分配虛擬地址空間,而后通過異常陷入內核分配真正的物理內存,在內存不足的情況下,這相當于完全屏蔽了應用進程對系統內存狀態的感知,即malloc
總是能成功,一旦內存不足,會引起系統OOM
殺進程,應用程序對于這種后果是無法預測的。 直至內存用完為止。在數據庫服務器上不建議設置為1,從而盡量避免使用swap
交換分區。
2
:禁止overcommit
;表示不允許超過CommitLimit
值。由于很多情況下,進程的虛擬地址空間占用遠大于其實際占用的物理內存,這樣一旦內存使用量上去以后,對于一些動態產生的進程(需要復制父進程地址空間)則很容易創建失敗,如果業務過程沒有過多的這種動態申請內存或者創建子進程,則影響不大,否則會產生比較大的影響 。這種情況下系統所能分配的內存不會超過上面提到的CommitLimit
大小,如果這么多資源已經用光,那么后面任何嘗試申請內存的行為都會返回錯誤,這通常意味著此時沒法運行任何新程序。
我們可以通過設置overcommit_memory=1
的優化,減少操作系統內存,提高Redis
的fork
成功率,因為fork
后的進程和父進程共享一個數據空間,持久化要新增的內存空間都會小于父進程已經使用的空間,具體有三種方式修改內核參數,但要有root
權限:
編輯/etc/sysctl.conf
,改vm.overcommit_memory=1
,然后sysctl -p
使配置文件生效;
命令:sysctl vm.overcommit_memory=1
;
命令:echo 1 > /proc/sys/vm/overcommit_memory
;
當Redis
持久化fork
子進程后,占用內存大小和父進程等同,由于Linux
在寫時有copy-on-write
機制,父子進程共享相同的物理內存頁,當父進程處理寫請求的時候會把要修改的頁創建副本,而子進程在fork
過程中共享整個父進程的內存快照。如果我們要減少創建的副本的大小,就涉及操作系統的另外一個概念Huge Pages
(大頁)。
在Redhat Linux
中,內存都是以頁的形式劃分的,默認情況下每頁是4K
,這就意味著如果物理內存很大,則映射表的條目將會非常多,會影響CPU
的檢索效率。因為內存大小是固定的,為了減少映射表的條目,可采取的辦法只有增加頁的尺寸。Linux Kernel
在2.6.38
內核中增加了THP
(Transparent Huge Pages)的特性,支持大內存頁(2MB
)分配,默認開啟。當開啟后可以加快fork
子進程的速度,但fork
操作之后,每個內存頁從原來的4KB
變成了2MB
,會大幅增加重寫期間父進程內存消耗,同時每次寫命令引起的復制內存頁單位放大了512
倍,會拖慢寫操作的執行時間,因此在使用Redis
的時候Redis
建議關閉THP
,方法為:echo never > /sys/kernel/mm/transparent_hugepage/enabled
。為了讓機器重啟該參數仍然生效,建議在/etc/rc.local
中追加echo never > /sys/kernel/mm/transparent_hugepage/enabled
,避免失效。當大頁被關閉后,可以看到同等操作下,RDB
備份時候的copy-on-write
變化內存空間會減少。
綜上分析,我們可以操作系統物理內存和Redis
內存之間的一些關系,尤其Redis
在持久化的時候fork
進程會隨操作系統的參數不同,需要的內存也有所不同,為了加快fork
子進程的速度以及主備之間的文件傳輸同步,一般我們建議一個Redis
節點的最大內存在10G-15G
左右,操作系統的內存適當冗余,盡量控制同一臺機器的多個Redis
節點在同一個時間點進行RDB
備份(可以通過緩存中心定時備份),導致內存同一時刻增加避免內存空間不足導致的fork
失敗,最安全保險的情況是內存為Redis
的2倍
,但是在vm.overcommit_memory=1和大頁關閉的情況下,可以根據實際使用,降低操作系統的整個內存大小 。
參考文章:
https://www.jianshu.com/p/785ee3bea266
https://www.cnblogs.com/wjoyxt/p/3777042.html
到此,相信大家對“Redis持久化時內存不足怎么處理”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。