故障簡(jiǎn)介
早上查看Redis日志的時(shí)候發(fā)現(xiàn)Redis一直在報(bào)錯(cuò)
[1524] 24 Mar 10:00:56.037 * 1 changes in 900 seconds. Saving...
[1524] 24 Mar 10:00:56.037 # Can't save in background: fork: Cannot allocate memory
Redis數(shù)據(jù)回寫機(jī)制
數(shù)據(jù)回寫分同步和異步兩種方式
- 同步回寫(
SAVE
), 主進(jìn)程直接向磁盤回寫數(shù)據(jù). 在數(shù)據(jù)量大的情況下會(huì)導(dǎo)致系統(tǒng)假死很長(zhǎng)時(shí)間 - 異步回寫(
BGSAVE
), 主進(jìn)程fork后, 復(fù)制自身并通過這個(gè)新的進(jìn)程回寫磁盤, 回寫結(jié)束后新進(jìn)程自行關(guān)閉.
由于 BGSAVE
不需要主進(jìn)程阻塞, 系統(tǒng)也不會(huì)假死, 一般會(huì)采用 BGSAVE
來實(shí)現(xiàn)數(shù)據(jù)回寫.
故障分析
在小內(nèi)存的進(jìn)程上做fork, 不需要太多資源. 但當(dāng)這個(gè)進(jìn)程的內(nèi)存空間以G為單位時(shí), fork就成為一件很恐怖的操作.
在16G內(nèi)存的足跡上fork 14G的進(jìn)程, 系統(tǒng)肯定Cannot allocate memory
.
主機(jī)的Redis 改動(dòng)的越頻繁 fork進(jìn)程也越頻繁, 所以一直在Cannot allocate memory
解決方案
直接修改內(nèi)核參數(shù) vm.overcommit_memory = 1, Linux內(nèi)核會(huì)根據(jù)參數(shù)vm.overcommit_memory參數(shù)的設(shè)置決定是否放行酥泛。
vm.overcommit_memory = 1恢暖,直接放行
vm.overcommit_memory = 0:則比較 此次請(qǐng)求分配的虛擬內(nèi)存大小和系統(tǒng)當(dāng)前空閑的物理內(nèi)存加上swap蔬捷,決定是否放行。
vm.overcommit_memory = 2:則會(huì)比較進(jìn)程所有已分配的虛擬內(nèi)存加上此次請(qǐng)求分配的虛擬內(nèi)存和系統(tǒng)當(dāng)前的空閑物理內(nèi)存加上swap,決定是否放行。
源碼如下:
/* 在/etc/sysctl.conf文件里面加入或者直接刪除也可以,因?yàn)樗笔≈稻褪?*/
sudo echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
sudo sysctl -p