PHP函數session_start()中的session鎖

1、Session locking: Non-blocking read-only sessions in PHPphp

當時網上看的一篇文章html

https://www.leaseweb.com/labs/2014/08/session-locking-non-blocking-read-sessions-php/?utm_source=leaseweblabs.com&utm_medium=referral&utm_campaign=redirectweb

中文譯文大體以下:ajax

什麼是session鎖?
爲了明白這點,咱們首先要知道web server不是經過一個單線程運行你的php代碼,他是多個工做線程同時運行,而後處理請求。
通常,瀏覽網頁的用戶請求是被序列化的,這也是爲何http長鏈接起到的做用。經過保持給請求頁面的全部資源鏈接的打開,能夠避免鏈接的開銷。
瀏覽器很是聰明,而且老是試圖對HTML頁面的請求進行序列化。對於頁面上的資產(圖像、腳本等),還有另外一種策略。
瀏覽器會從它所看到的HTML中所引用的每一個惟一的主機名中並行下載多個資源。
它能夠經過打開多個TCP鏈接或管道來實現這一點。
當一個瀏覽器任務它正在下載資源,它可能並行的下載這些資源給一個單一的瀏覽用戶。
會話鎖定避免這種併發性(經過阻塞)在這種狀況下提供對會話數據的可靠訪問。json

session鎖如何工做
這個很是簡單:當你使用‘session_start()’,php就是阻塞(等待)直到上一個請求的腳本經過‘session_write_close()’進行釋放。在Linux主機上,它是依靠‘flock()’方法實現。這是一個警告鎖機制,直到這個阻塞被釋放。
注意:這部分上鎖的時間不會計算在php中的「max_execution_time」配置項,「max_execution_time」詳見set_time_limit()
爲何session鎖是必須的瀏覽器

session鎖防止在用以存儲session數據的共享內存出現競爭條件。每個PHP進程都會讀取整個session的儲存,並寫回數據在它關閉以前。
這意味要可靠地儲存一個登陸進來的用戶信息(一般在會話數據session中完成),你必須確保沒有其餘進程已經讀取這個session數據,否則將在寫入後覆蓋掉你保存的數據(由於最後一次寫入數據爲準)
sesion的只讀
許多網站使用AJAX調用來加載數據。在檢索這些數據時,咱們想知道用戶是否在須要時登陸來拒絕訪問。此外,咱們不但願將此AJAX數據加載到會話鎖定中,這將減慢網站的速度。這就是下面(多是髒)代碼的地方。它將容許您得到對會話數據的只讀訪問(調用它而不是「sessionstart()」)。經過這種方式,您能夠在AJAX調用中檢查權限,但不須要鎖定,所以不會阻塞和序列化請求。它能夠顯著提升你的PHP AJAX網站的速度!bash

function session_readonly()
    {
        $session_name = preg_replace('/[^\da-z]/i', '', $_COOKIE[session_name()]);
        $session_data = file_get_contents(session_save_path().'/sess_'.$session_name);

        $return_data = array();
        $offset = 0;
        while ($offset < strlen($session_data)) {
            if (!strstr(substr($session_data, $offset), "|")) break;
            $pos = strpos($session_data, "|", $offset);
            $num = $pos - $offset;
            $varname = substr($session_data, $offset, $num);
            $offset += $num + 1;
            $data = unserialize(substr($session_data, $offset));
            $return_data[$varname] = $data;
            $offset += strlen(serialize($data));
        }
        $_SESSION = $return_data;
    }

2、測試模擬session

1.首先,咱們打開php-fpm的慢日誌記錄併發

request_slowlog_timeout = 4s
slowlog = /var/log/slow.log

2.而後,首先纔是默認狀況下,寫入數據後沒session_write_close();的狀況函數

test_sessom.php

<?php
/**
 * Created by PhpStorm.
 * User: tjj
 * Date: 17-6-23
 * Time: 下午4:01
 */

session_start();
$_SESSION['latestRequestTime'] = time();
//session_write_close();
sleep(1);
$twitterId = $_SESSION['latestRequestTime'];
echo json_encode($twitterId);

test.html

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<img src="./test_session.php?v=1">
<img src="./test_session.php?v=2">
<img src="./test_session.php?v=3">
<img src="./test_session.php?v=4">
<img src="./test_session.php?v=5">
<img src="./test_session.php?v=6">
<img src="./test_session.php?v=7">
<img src="./test_session.php?v=8">
<img src="./test_session.php?v=9">
<img src="./test_session.php?v=10">
<img src="./test_session.php?v=11">
<img src="./test_session.php?v=12">
<img src="./test_session.php?v=13">
<img src="./test_session.php?v=14">
<img src="./test_session.php?v=15">
</body>
</html>

訪問test.html的結果:

能夠看出每個請求的時間幾乎都是疊加前面的等待時間,因爲都要等待前面的請求完成釋放。

而後看看php的慢日誌記錄狀況,能夠看到超過4s的都記錄了,並且報的是session_start()這個函數的問題。

再看看 test_session.php中session_write_close()註釋打開後的請求狀況。

明顯沒有形成阻塞,請求響應時間基本正常。


總結:涉及到的ajax接口不須要用session的就不session_start(),不須要寫入session的就在session_start()後直接加入session_write_close(),須要寫入session的,寫入session後加入session_write_close()。

相關文章
相關標籤/搜索