《PHP應用:詳解PHP使用Redis存儲session時的一個Warning定位》要點:
本文介紹了PHP應用:詳解PHP使用Redis存儲session時的一個Warning定位,希望對您有用。如果有疑問,可以聯系我們。
PHP實例1. 問題現象
PHP實例系統頁面刷新的時候,偶爾會報錯下面的Warnning,但是不經常出現:
PHP實例Warning: Unknown: Failed to write session data (Redis). Please verify that the current setting of session.save_path is correct (tcp://x.x.x.x:6379?auth=yyy) in Unknown on line 0
PHP實例看網絡有人說是redis版本的問題、但是沒有具體結論,那么本著學習的態度,自己試試看看能不能捉出這個bug.
PHP實例定位問題:
PHP實例查看PHP文件是否有設置session的地方,發現沒有
PHP實例繼續檢查php配置文件,發現配置了session存儲到redis里面
PHP實例
[Session]
session.save_handler = redis
session.save_path = "tcp://x.x.x.x:6379?auth=yyyy"
session.use_cookies = 1
PHP實例1、繼續查看php Session擴展源代碼,定位出錯提示語在函數php_session_save_current_state中
PHP實例檢查session擴展文件中出錯提示:
PHP實例
static void php_session_save_current_state(TSRMLS_D) /* {{{ */
{
int ret = FAILURE;
//是否session數組
IF_SESSION_VARS() {
if (PS(mod_data) || PS(mod_user_implemented)) {
char *val;
int vallen;
//變量編碼
val = php_session_encode(&vallen TSRMLS_CC);
if (val) {
//保存session數據
ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, vallen TSRMLS_CC);
efree(val);
} else {
//清空session
ret = PS(mod)->s_write(&PS(mod_data), PS(id), "", 0 TSRMLS_CC);
}
}
//看出錯提示語在這里
if (ret == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write session data (%s). Please "
"verify that the current setting of session.save_path "
"is correct (%s)",
PS(mod)->s_name,
PS(save_path));
}
}
if (PS(mod_data) || PS(mod_user_implemented)) {
PS(mod)->s_close(&PS(mod_data) TSRMLS_CC);
}
}
static void php_session_flush(TSRMLS_D){
如果 (PS(session_status) == php_session_active)
session_status = none
這里調用...
php_session_save_current_state
}
PHP實例下面兩個函數調用:php_session_flush()
PHP實例
static PHP_FUNCTION(session_write_close)
{
php_session_flush(TSRMLS_C);
}
static PHP_FUNCTION(session_register_shutdown){
}
PHP實例由上面可以看到,php_session_save_current_state是在 php_session_flush中調用,即在session保存、清空等刷新寫session的時候會產生.
PHP實例由php seesion源碼沒有發現什么問題,突然想到會不會是Redis本身有沒有啥問題,導致的寫出錯.因而繼續從redis里面找問題:
PHP實例Redis問題定位
PHP實例1. 首先查看Redis日志文件:
PHP實例看到如下每5分鐘會刷新一下如下log:
PHP實例
[16723] 04 Jul 15:15:01.987 # Server started, Redis version 2.8.9
[16723] 04 Jul 15:15:01.987 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
[16723] 04 Jul 15:15:01.996 * DB loaded from disk: 0.008 seconds
[16723] 04 Jul 15:15:01.996 * The server is now ready to accept connections on port 6379
PHP實例懷疑這就是問題的PHP寫日志失敗的原因了.那么Redis為啥會5分鐘重啟呢?繼續追查!
PHP實例2. 是系統內存不夠、Redis core了?
PHP實例查看系統和Redis內存使用狀態:
PHP實例系統內存狀態:
PHP實例
$ free -m
total used free shared buffers cached
Mem: 3516 3171 345 0 684 1680
-/+ buffers/cache: 806 2709
Swap: 2055 724 1330
PHP實例Redis服務器占用的內存狀態:
PHP實例
used_memory:2841648
used_memory_human:2.71M
used_memory_rss:3710976
used_memory_peak:2877576
used_memory_peak_human:2.74M
used_memory_lua:33792
mem_fragmentation_ratio:1.31
mem_allocator:jemalloc-3.2.0
PHP實例可以看到Redis其實內存占用非常少.redis重啟原因暫且不明.
PHP實例3. 定時腳本
PHP實例因為重啟日志5分鐘一次、非常規律,因而懷疑是不是別的原因導致Redis重啟,比如定時腳本.
PHP實例因為本人沒有root corntab權限,找老板提權,看到赫然存在著一個crontab,5分鐘監控一次redis.
PHP實例如下:
PHP實例
/5 * * * /data/scripts/check_redis.sh >/dev/null 2>&1 ##check_redis.tag.1
PHP實例查看腳本內容
PHP實例
PORT='6379'
ETH1_ADDR=`/sbin/ifconfig eth1 | awk -F ':' '/inet addr/{print $2}' | sed 's/[a-zA-Z ]//g'`
retval=`nmap --system-dns -sT -p ${PORT} ${ETH1_ADDR} | grep open`
if [ "${retval}X" = "X" ]; then
/sbin/service redis restart >/dev/null 2>&1
fi
PHP實例這是一個檢查Redis端口是否提供服務的腳本,如果檢查不成功,就拉起Redis.
PHP實例可以看到這個腳本本來沒有什么問題.
PHP實例但是:通過手動執行這個命令發現:
PHP實例這臺機器沒有安裝nmap 這個命令,
PHP實例所以這個腳本最后總是執行失敗!然后Redis重啟.
PHP實例因為問題根源找到了,找運維安裝相關命令,問題解決.
PHP實例以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持維易PHP.
轉載請注明本頁網址:
http://www.snjht.com/jiaocheng/528.html