溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

PHP如何使用Redis存儲(chǔ)session時(shí)的一個(gè)Warning定位

發(fā)布時(shí)間:2021-08-06 10:01:36 來(lái)源:億速云 閱讀:202 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹了PHP如何使用Redis存儲(chǔ)session時(shí)的一個(gè)Warning定位,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

1. 問(wèn)題現(xiàn)象

系統(tǒng)頁(yè)面刷新的時(shí)候,偶爾會(huì)報(bào)錯(cuò)下面的Warnning,但是不經(jīng)常出現(xiàn):

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

看網(wǎng)絡(luò)有人說(shuō)是redis版本的問(wèn)題、但是沒(méi)有具體結(jié)論,那么本著學(xué)習(xí)的態(tài)度,自己試試看看能不能捉出這個(gè)bug.

定位問(wèn)題:

查看PHP文件是否有設(shè)置session的地方,發(fā)現(xiàn)沒(méi)有

繼續(xù)檢查php配置文件,發(fā)現(xiàn)配置了session存儲(chǔ)到redis里面

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

1、繼續(xù)查看php Session擴(kuò)展源代碼,定位出錯(cuò)提示語(yǔ)在函數(shù)php_session_save_current_state中

檢查session擴(kuò)展文件中出錯(cuò)提示:

static void php_session_save_current_state(TSRMLS_D) /* {{{ */
{
  int ret = FAILURE;

  //是否session數(shù)組
  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數(shù)據(jù)
        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);
      }
    }


    //看出錯(cuò)提示語(yǔ)在這里
    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

    這里調(diào)用...
    php_session_save_current_state
}

下面兩個(gè)函數(shù)調(diào)用: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中調(diào)用,即在session保存、清空等刷新寫(xiě)session的時(shí)候會(huì)產(chǎn)生。

由php seesion源碼沒(méi)有發(fā)現(xiàn)什么問(wèn)題,突然想到會(huì)不會(huì)是Redis本身有沒(méi)有啥問(wèn)題,導(dǎo)致的寫(xiě)出錯(cuò)。因而繼續(xù)從redis里面找問(wèn)題:

Redis問(wèn)題定位

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

看到如下每5分鐘會(huì)刷新一下如下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

懷疑這就是問(wèn)題的PHP寫(xiě)日志失敗的原因了。那么Redis為啥會(huì)5分鐘重啟呢?繼續(xù)追查!

2. 是系統(tǒng)內(nèi)存不夠、Redis core了?

查看系統(tǒng)和Redis內(nèi)存使用狀態(tài):

系統(tǒng)內(nèi)存狀態(tài):

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

Redis服務(wù)器占用的內(nèi)存狀態(tài):

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其實(shí)內(nèi)存占用非常少。redis重啟原因暫且不明。

3. 定時(shí)腳本

因?yàn)橹貑⑷罩?分鐘一次、非常規(guī)律,因而懷疑是不是別的原因?qū)е翿edis重啟,比如定時(shí)腳本。

因?yàn)楸救藳](méi)有root corntab權(quán)限,找老板提權(quán),看到赫然存在著一個(gè)crontab,5分鐘監(jiān)控一次redis。

如下:

/5 * * * /data/scripts/check_redis.sh >/dev/null 2>&1 ##check_redis.tag.1

查看腳本內(nèi)容

PORT='6379'
ETH1_ADDR=`/sbin/ifconfig eth2 | 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

這是一個(gè)檢查Redis端口是否提供服務(wù)的腳本,如果檢查不成功,就拉起Redis。

可以看到這個(gè)腳本本來(lái)沒(méi)有什么問(wèn)題。

但是:通過(guò)手動(dòng)執(zhí)行這個(gè)命令發(fā)現(xiàn):

這臺(tái)機(jī)器沒(méi)有安裝nmap 這個(gè)命令,

所以這個(gè)腳本最后總是執(zhí)行失??!然后Redis重啟。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“PHP如何使用Redis存儲(chǔ)session時(shí)的一個(gè)Warning定位”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI