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