一台redis伺服器,4核,16g記憶體且沒有任何硬體上的問題。持續高壓執行了大約3個月,儲存了大約14g的資料,設定了比較完備的s**e引數。而就是這台主機,在一次重起之後,丟失了大量的資料,14g的資料最終只恢復了幾百兆而已。
正常情況下,像redis這樣定期回寫磁碟的記憶體資料庫,丟失幾個資料也是在情理之中,可超過80%資料丟失率實在太離譜。排除了誤操作的可能性之後,開始尋找原因。
重啟動時的日誌:
[26641] 21 dec 09:46:34 * sl**e ask for synchronization
[26641] 21 dec 09:46:34 * starting bgs**e for sync
[26641] 21 dec 09:46:34 # can』t s**e in background: fork: cannot allocate memory
[26641] 21 dec 09:46:34 * replication failed, can』t bgs**e
[26641] 21 dec 09:46:34 # received sigterm, scheduling shutdown…
[26641] 21 dec 09:46:34 # user requested shutdown…
很明顯的乙個問題,系統不能在後台儲存,fork程序失敗。
翻查了幾個月的日誌,發覺系統在頻繁報錯:
[26641] 18 dec 04:02:14 * 1 changes in 900 seconds. s**ing…
[26641] 18 dec 04:02:14 # can』t s**e in background: fork: cannot allocate memory
系統不能在後台儲存,fork程序時無法指定記憶體。
對原始碼進行跟蹤,在src/rdb.c中定位了這個報錯:
int rdbs**ebackground(char *filename) else資料丟失的問題總算搞清楚了!} else
redislog(redis_notice,"background s**ing started by pid %d",childpid);
server.bgs**echildpid = childpid;
updatedictresizepolicy();
return redis_ok;
}return redis_ok; /* unreached */
}
redis的資料回寫機制分同步和非同步兩種,
同步回寫即s**e命令,主程序直接向磁碟回寫資料。在資料大的情況下會導致系統假死很長時間,所以一般不是推薦的。
非同步回寫即bgs**e命令,主程序fork後,複製自身並通過這個新的程序回寫磁碟,回寫結束後新程序自行關閉。由於這樣做不需要主程序阻塞,系統不會假死,一般缺省會採用這個方法。
個人感覺方法2採用fork主程序的方式很拙劣,但似乎是唯一的方法。記憶體中的熱資料隨時可能修改,要在磁碟上儲存某個時間的記憶體映象必須要凍結。凍結就會導致假死。fork乙個新的程序之後等於複製了當時的乙個記憶體映象,這樣主程序上就不需要凍結,只要子程序上操作就可以了。
在小記憶體的程序上做乙個fork,不需要太多資源,但當這個程序的記憶體空間以g為單位時,fork就成為一件很恐怖的操作。何況在16g記憶體的主機上fork 14g記憶體的程序呢?肯定會報記憶體無法分配的。更可氣的是,越是改動頻繁的主機上fork也越頻繁,fork操作本身的代價恐怕也不會比假死好多少。
找到原因之後,直接修改核心引數vm.overcommit_memory = 1
linux核心會根據引數vm.overcommit_memory引數的設定決定是否放行。
如果 vm.overcommit_memory = 1,直接放行
vm.overcommit_memory = 0:則比較 此次請求分配的虛擬記憶體大小和系統當前空閒的物理記憶體加上swap,決定是否放行。
vm.overcommit_memory = 2:則會比較 程序所有已分配的虛擬記憶體加上此次請求分配的虛擬記憶體和系統當前的空閒物理記憶體加上swap,決定是否放行。
記一次資料提取過程
某次需要乙個中文電碼本,然而網上搜到的要麼收費,要麼不行,所以打算自己做乙份,但是看了下資料量實在太大只能放棄,那麼怎麼辦呢。收到乙個軟體teleccodetool 可以查詢漢字對應的電碼,隨即準備提取,過程記錄如下。無關的檔案已經刪除了,只剩三個核心檔案 乙個個看,第乙個配置檔案開啟沒啥有用的訊息...
一次Windows資料丟失後的亡羊補牢
事件描述 2016.11.14一早,禪道 bug管理系統 啟動不了了。經過一天各種折騰都不能正常啟動服務,找到資料庫目錄和備份目錄,都是空的。這是伺服器在祝我31歲生日快樂嗎,不帶這麼玩的。下圖為正常狀態 下圖為啟動失敗狀態 自身存在的問題 由於一直沒把禪道放在心上,伺服器的備份策略從來沒有檢查過。...
記一次資料越界的事
最近在作乙個基於聯盛德的 w600晶元進行ayla雲移植時,用到了作業系統的tick獲取,獲取函式如下 u32 clock ms void else return ms 測試 現了奇怪的問題,系統走著走著就不發心跳包了,最後跟蹤後發現是上面這個函式返回的值突然變零 我們預想上面的返回值會一直增加,至...