Web提速:避免php session拖慢運行速度

來源:互聯網
上載者:User
Web提速:避免php session拖慢運行速度

一、WHAT--並發訪問,阻塞執行
1.1 不使用session

檔案index.php:

 


檔案ajax.php、ajax2.php、ajax3.php的內容都是

   

  每個請求都sleep 1s,jq的ajax請求是非同步,也就是說這三個請求基本上是同時發出的,理論上最好的情況是瀏覽器等待1s,3個介面全部返回。

訪問http://localhost,在chrome下查看測試結果:

圖 1.1 不使用session測試結果

  測試結果基本上跟理論一致

1.2 使用session

現在我們把檔案ajax.php、ajax2.php、ajax3.php都改為

   


這樣做會什麼有什麼區別嗎?我們直接看測試結果:

圖 1.2 使用session測試結果

不是每個請求只執行1s鐘嗎?為什麼ajax2.php消耗了2s,ajax3.php消耗3s?

二、WHO -- Session鎖

session鎖的官方定義:

Session data is usually stored after your script terminated without the need to call session_write_close(), but as session data is locked to prevent concurrent writes only one script may operate on a session at any time.

  大致的意思是: 從調用session_start()開始,直到顯示調用session_write_close()或指令碼結束,session的資料都會被鎖起來,屆時同一個SESSIONID使用者的請求會被阻塞。

從圖1.2的測試結果看到,ajax2.php與ajax3.php分別多執行了1s和2s,很明顯session_start()操作造成了阻塞。

  當index.php同時訪問ajax.php、ajax2.php、ajax3.php,ajax.php首先執行,此時ajax2.php與ajax3.php都在等在ajax.php釋放session鎖,都消耗1s。

  當ajax.php執行完成,釋放了session鎖,ajax2.php與ajax3.php再次競爭session鎖,同理ajax3.php又等待了1s鐘。所以我們得到的結果:

  ajax.php 消耗1s

  ajax2.php 消耗2s

  ajax3.php 消耗3s

三、WHEN -- 什麼時候會觸發Session鎖

  在章節二中,session鎖定義為session_start()開始即會觸發session鎖,所以對於現有大部分php架構(使用原生php session的情況下)存在session鎖造成的使用者請求阻塞的問題。試想,有2個請求,其中請求A需要3s鐘才能返回結果,另外請求B僅需要10ms即能返回,前端同時請求這兩個介面,假如後台先處理了A請求,那麼B請求就要等待3s後再執行10ms才能返回結果。但是最優的情況是,同時發起請求,10ms後收到B請求返回,3s後收到A請求返回。

四、WHY -- Session內部執行機制

  預設情況下php session採用檔案為服務端儲存介質。在php session模組的源碼中,有一個比較重要的結構體:


圖4.1 php session模組結構體 ps_module_struct

  該結構體裡面的幾個函數指標分別對應了session操作的open、close、read、write、destory、gc回收等功能。看到這6個函數,是否想起了php的SessionHandlerInterface介面(版本>=php5.4)?

圖4.2 php SessionHandlerInterface介面

  用這個介面配合session_set_save_handler可以重寫session的這幾個關鍵操作。於是我們可以使用以下代碼來探探php session在一個請求的生命週期中的運行順序:

圖4.3 session運行已排序的測試代碼

測試結果:

  由測試結果可知一般的session執行順序,在session_start()調用時,php回去調用open和read操作,指令碼執行結束後(輸出了php script run),再會調用write和close操作。

現在我們不妨做一個大膽的猜想,php 在 session的open或者read操作時,開啟了session鎖,並write或close後釋放session鎖。這樣的猜想也符合我們在章節1的測試結果。

  為了驗證我們的猜想,就需要去php的源碼探個究竟了。在php源碼檔案/ ext / session / mod_files.c中可以看到預設session的6個重要操作的部分實現。在156行(點擊開啟連結),看到open操作有一個開啟檔案操作:flock(data->fd, LOCK_EX);該操作以互斥鎖定的方式開啟檔案。在110行關掉檔案close(data->fd);。

  看到這裡,我們應該得到的結論是:

在預設情況下,所謂的php session鎖其實就是檔案鎖

  所以,當我們使用session_set_save_handler來自定session操作,改用memcache或其他介質時,只要我們在SessionHandlerInterface的介面中沒有鎖的邏輯,那麼session鎖自然也不會存在。作者私下也做了這樣的實驗,實踐證明也的確如此。

五、HOW -- 如何避免Session鎖帶來的阻塞現象

  首先,session鎖不一定是壞事情,在一種情況下就非常好用,例如某介面對與同一個使用者的請求預設同一時刻只能執行一次。這種時候,就可以用seesion_start()和session_write_close()把要阻塞的代碼括起來。非常簡單暴力實用。

  但是大部分時候我們還是要避免這種鎖的存在,解決方案:

1、在用完session的時候就馬上session_write_close()掉,釋放session鎖

2、採用沒有鎖的session操作,如章節4中所說的用session_set_save_handler來自訂一個沒有鎖的session操作。

3、再使用預設php session時,個人比較中意的一個方案:大部分情況下,我們對session的操作基本上都是讀操作,寫操作一般都比較少。這種時候,我們可以自己寫一個session類。

建構函式:將session讀入cache,關閉session鎖

寫操作:開啟session鎖,寫入值,關閉session鎖

讀操作:直接讀cache

部分代碼如下:

//將session讀入全域變數$_SEESIONstatic private function init(){if(self::$not_init){ session_start(); session_write_close(); self::$not_init = false;}}


//讀sessionstatic public function get($name){self::init();return $_SESSION[$name];}


//寫sessionstatic public function set($name, $val){session_start();$_SESSION[$name] = $val;session_write_close();}


注意:如果是寫操作頻繁的操作,就不適合使用該方法。

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.