PHP使用Redis存储session时的一个Warning定位

news/2024/6/29 12:18:01 标签: session, redis, php

1. 问题现象

系统页面刷新的时候,偶尔会报错下面的Warnning,但是不经常出现:

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

看网络有人说是redis版本的问题、但是没有具体结论,那么本着学习的态度,自己试试看看能不能捉出这个bug.

定位问题:

  1. 查看php文件是否有设置session的地方,发现没有

  2. 继续检查php配置文件,发现配置了session存储到redis里面

[Session]
session.save_handler = redis
session.save_path = "tcp://x.x.x.x:6379?auth=yyyy"
session.use_cookies = 1

  1. 继续查看php Session扩展源代码,定位出错提示语在函数php_session_save_current_state中

检查session扩展文件中出错提示:


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_session_flush()
static PHP_FUNCTION(session_write_close)
{
    php_session_flush(TSRMLS_C);
}


static PHP_FUNCTION(session_register_shutdown){

}

由上面可以看到,php_session_save_current_state是在 php_session_flush中调用,即在session保存、清空等刷新写session的时候会产生。

  1. php seesion源码没有发现什么问题,突然想到会不会是Redis本身有没有啥问题,导致的写出错。因而继续从redis里面找问题:

redis问题定位">Redis问题定位

redis日志文件">1. 首先查看Redis日志文件:

看到如下每5分钟会刷新一下如下log:

[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写日志失败的原因了。那么Redis为啥会5分钟重启呢?继续追查!

redis-core了">2. 是系统内存不够、Redis core了?

查看系统和Redis内存使用状态:

系统内存状态:

$ free -m
             total       used       free     shared    buffers     cached
Mem:          3516       3171        345          0        684       1680
-/+ buffers/cache:        806       2709
Swap:         2055        724       1330

Redis服务器占用的内存状态:

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

可以看到Redis其实内存占用非常少。redis重启原因暂且不明。

3. 定时脚本

因为重启日志5分钟一次、非常规律,因而怀疑是不是别的原因导致Redis重启,比如定时脚本。
因为本人没有root corntab权限,找老板提权,看到赫然存在着一个crontab,5分钟监控一次redis
如下:
/5 * * * /data/scripts/check_redis.sh >/dev/null 2>&1 ##check_redis.tag.1

查看脚本内容

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

这是一个检查Redis端口是否提供服务的脚本,如果检查不成功,就拉起Redis。
可以看到这个脚本本来没有什么问题。

但是:通过手动执行这个命令发现:
这台机器没有安装nmap 这个命令,

所以这个脚本最后总是执行失败!然后Redis重启。

因为问题根源找到了,找运维安装相关命令,问题解决。


http://www.niftyadmin.cn/n/739359.html

相关文章

MATALB中信号的阈值去噪

摘自http://blog.chinaaet.com/detail/3083.html MATLAB中实现了信号的阈值去噪,主要包括阈值去噪和阈值获取两方面。 1.阈值获取MATLAB中实现阈值获取的函数有ddencmp、thselect、wbmpen和wwdcbm,下面对它们的用法进行简单的说明。 ddencmp的调用格式…

HTTP POST提交数据方式不同引起的躺坑记

HTTP POST提交数据方式不同引起的躺坑记 jasonye 2017-08-12 问题现象: PHP代码中调用curl POST提交的数据,在Go Server端一直用PostFormValue读不到,但是用curl -d命令提交的数据可以读取到。 定位问题: 在试图采用postman…

Effecitve C++读书笔记(一)

最近工作中开始又使用C了,而且应用软件的开发C语言确实有了一定的局限。所以还是准备多看一些关于C的书籍,总结下。 视C为一个语言联盟,我个人觉得这是一个绝妙的想法。因为C和C的纠葛不清,但是又因为是一门高级的面向对象的语言…

go语言包管理

包名字可以和目录名字 可以不一样, 但是推荐一样,便于快速查找识别到包,否则容易误解一个目录中只包含一个包、包含多个包会报错一个包可以放在多个文件中、包文件只放在src文件目录下,通过GOPATH引用、否则引用不到。import只要引…

WIN7无线网卡开软AP的方法

l 实现方式一: l 无线网卡的软AP模式,对于经常出差以及学生宿舍等没有无线路由器的场合,不仅能解决燃眉之急,而且也很方便实用。不过在WindowsXP下,需要使用 网卡的驱动程序将无线网卡设置为AP模式,费时费力…

dns应该怎么设置

摘自http://jingyan.baidu.com/article/e8cdb32b87deaa37052bad91.html 有时候DNS无法获取只能通过手动设置,有时候手动设置了DNS反而造成无法上网的问题,这时候又要修改DNS为自动获取,下面我就来介绍一下怎么获取DNS并设置成固定的dns。分为…

团队代码合丢问题回顾

近期服务端这边出现了几次代码合并丢失的问题,结果导致一次线上P1故障,一次推迟试验结果出数据,问题很严重。所以回顾一下,期望以后不要再躺在了同样的坑里面。 近期丢代码事件 A同学误操作将测试中dev分支合并到master&#xf…

WIFI基本知识

摘自http://blog.chinaunix.net/uid-9525959-id-3326047.html 这里对wifi的802.11协议中比较常见的知识做一个基本的总结和整理,便于后续的学习。因为无线网络中涉及术语很多,并且许多协议都是用英文描述,所以有些地方翻译出来会有歧义&#…