《:详解PHP使用Redis存储session时的一个Warning定位》要点:
本文介绍了:详解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实例 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),"",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实例看到如下每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实例系统内存状态:
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实例 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实例 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重启.