昨日,公司php調用redis報錯:read error on connection 2015-01-29 23:59:050.13330000,redis存放的是用戶session。
在網上查詢,大家說法都比較一致,說是php.ini文件中的一個配置項導致:
default_socket_timeout = 60
由於redis擴展也是基於php 的socket方式實現,因此該參數值同樣會起作用。
解決方法是:
1、直接修改php.ini,將其設置為我們想要的值(這個不推薦)
2、在我們的腳本中通過以下方式設置,這樣就比較靈活,不對其他腳本產生影響
ini_set('default_socket_timeout', -1); //不超時
但是,一看,修改的兩個參數,一個是php的全局參數,一個是redis的超時操作,都應該按照實際情況來修改,而且,設置超長超時時間或者不超時都是不合理的;
繼續檢查redis發現,/usr/local/redis_16379/src/redis-cli -p 16379 info(服務器配置的redis端口為16379,分配內存為8000M)
used_memory_human:7.49G,占用內存已經7.49G
db10:keys=53090286,鍵值5000多萬
竟然是鍵值占滿了內存,檢查php的調用代碼,發現php竟然沒有設置redis的鍵值過期時間,修改php代碼,對鍵值設置過期時間
設置完之后,發現之前的鍵值因為沒有設置過期時間,程序不會自動刪除,於是用腳本刪除主redis上對應的session,
/usr/local/redis_16379/src/redis-cli -p 16379 -n 10 keys "PHPSESSION_wc*" | xargs /usr/local/redis_16379/src/redis-cli -p 16379 -n 10 del
將大部分過期數據刪除掉,刪除一定數量的數據之后,報錯消失,redis連接正常。
但是,發現redis主從,在這樣刪除之后,從數據竟然沒有同步,主的數據和從數據差距有400多萬不一致,也沒有再發現bgsave操作,查看從日志Trying a partial resynchronization,發現因為過濾keys占用太多資源,造成服務器負載飆升,slave斷開與主機的連接,需要從積壓空間中找回斷開期間的數據更新記錄。但是因為刪除數據太多,斷開的時間足夠長,master 拒絕 slave 的部分同步請求,從而 slave 只能進行全同步。
至此,在slave上對數據進行全量同步,數據恢復正常,業務正常。
需要注意幾點:
1.redis數據,正常情況下,設置過期時間,否則可能出現,存儲鍵值過多,占用完了預設內存,導致新的鍵值無法存儲,調用redis失敗的;
2.超時時間必須根據實際業務來設置;
3.如果slave一直連接不上master,可能需要進行全量同步。