php session的鎖和並發,phpsession_PHP教程

來源:互聯網
上載者:User

php session的鎖和並發,phpsession


本文分享PHP的session在使用過程中的鎖和並發的問題,與之相關的現象有請求阻塞、session資料丟失、session資料讀不到。

我登入不了了
某天,我準備登入我們一個後台系統,前去解決一個bug,在賬戶密碼驗證碼都準確輸入的情況下,我登入不上,經過多次實驗發現主要有兩個錯誤資訊:

  • csrf驗證失敗
  • 驗證碼錯誤【我對碼神起誓我用半形輸入了我看到的驗證碼,且順序一致,無多加字元】

我們的系統
我們的系統是基於phalcon 2.0.8 開發的,如你所見,我們在表單網域加入了防止csrf攻擊的域。也啟用了驗證碼。

 

我首先對這兩個組件進行查閱,發現他們都是將資料存於session:

# phalcon/security.zep# Security::getToken()let session =  dependencyInjector->getShared("session"); session->set(this->_tokenValueSessionID, token); $this->session->set('admin_get_captcha_action', $captcha);

然後我又查閱了我們session的實現,發現是將資料存放區於redis的。

找啊找
什麼問題導致我登入不上呢?既然是資料驗證上出現問題,就從資料著手吧,我登陸我們測試環境的redis機器,執行 redis-cli monitor,然後走一遍登入流程,發現輸出如下(意思意思):

  • GET sessionId
  • GET sessionId
  • SETEX sessionId 3600 csrf=xxxx
  • SETEX sessionId 3600 captcha=abcd

我們可以看到:

1、這裡存在兩次請求,一次是表單載入,一次是產生驗證碼的。
2、存在“並發”的情況,這兩個請求應該是表單載入渲染後才請求驗證碼的,也就是session順序應該是get->set->get->set,看起來怎麼是並發請求了。
3、後面那個SETEX沒有csrf的內容,也就是覆蓋掉前面的資料了
整個世界都不好了,不過也稍微明白是什麼問題了。什麼問題呢,說來話長,要從PHP的session資料的存取說起。

php的session資料的存取
session的資料是經過編碼成字串儲存在儲存空間【file、db、redis、memcache等】的,在我們使用session的時候,是什麼時候去儲存器取資料的?又是什麼時候將資料寫入儲存空間的?

這個問題的答案可能和一些朋友想的不一樣,一個請求裡面,PHP只會讀取一次儲存空間,在session_start的時候,然後也只會寫入一次儲存空間,在請求結束的時候,或調用session_write_close的時候,將資料刷回儲存空間,關閉session。

那麼問題來了:

1、如果一個會話,同時出現兩個讀寫session請求,沒有保證擷取1-寫入1-擷取2-寫入2,同時沒有cas版本管理機制的情況下,這些並發請求就會彼此讀取不到對方的寫入,最後寫入的會把前面請求寫入的session覆蓋掉。
2、如果請求是串列的,像登入頁面的表單和驗證碼,也有可能前面的請求已經輸出內容了,但是session還沒寫入,後面的請求就已經發起了。
鎖與不鎖
解決這種資源的並發一般會通過鎖或版本管理來處理。但是版本管理我看不到好的方法。就聊聊鎖吧。

其實鎖是不大適合,有弊端的。

php的session,預設是用檔案儲存體的,在開啟session的時候,會對檔案加獨佔鎖,這樣,其它請求就無法擷取鎖了,只能等待直到前面的鎖解了。

這樣保證了 讀取-寫入,讀取-寫入的順序。

其它儲存空間,例如mysql,可以藉助select for update進行行鎖。redis可以通過一個自增鍵,返回1的擷取到鎖等來實現。

這個實現的話,對資料流來說很理想,但是,對於目前這種頁面大量應用ajax的情況,所有請求排隊處理,將大大加大頁面展現的耗時,甚至出現請求逾時等不可用故障。

沒有解決的解決
不建議過多使用session,其一次讀取一次寫入的機制所引發的問題,會造成坑的存在。
在模版渲染前,或請求輸出前調用session_write_close

# 立刻回寫session,避免session覆蓋$eventManager = $this->view->getEventsManager();if (!$eventManager) {   $eventManager = new Manager();  $this->view->setEventsManager($eventManager);}$eventManager->attach("view:afterRender",function(){  session_write_close();});return $this->view; 
if($login) {   # 立刻回寫session,避免session讀取不到  $eventManager = $this->dispatcher->getEventsManager();  if (!$eventManager) {    $eventManager = new Manager();    $this->dispatcher->setEventsManager($eventManager);  }  $eventManager->attach('dispatch:afterDispatchLoop',function(){    session_write_close();  });  return $this->response->setHeader('Location', '/');}

以上就是關於php session的鎖和並發,希望對大家的學習有所協助。

您可能感興趣的文章:

  • 多php伺服器實現多session並發運行
  • PHP 解決session死結的方法
  • PHP中session變數的銷毀
  • PHP錯誤WARNING: SESSION_START() [FUNCTION.SESSION-START]解決方案
  • ThinkPHP的模版中調用session資料的方法
  • php中實現精確設定session到期時間的方法
  • ThinkPHP中Session用法詳解
  • PHP session檔案獨佔鎖引起阻塞問題解決方案
  • PHP中Session可能會引起並發問題
  • 淺析PHP中Session可能會引起並發問題

http://www.bkjia.com/PHPjc/1094746.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/1094746.htmlTechArticlephp session的鎖和並發,phpsession 本文分享PHP的session在使用過程中的鎖和並發的問題,與之相關的現象有請求阻塞、session資料丟失、session資料...

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.