深入研究 PHP 的 SESSION 阻塞问题

栏目: PHP · 发布时间: 5年前

内容简介:最近在一个基于 Web 的 IM 项目中,我采用异步向服务器发起请求拉取最新的聊天内容,服务器端通过 PHP 处理拉取请求,拉取过程是用 10 次循环查询数据库是否有最新的聊天内容。如发现新内容,则立即向浏览器输出,并结束掉本次请求的进程。在这 10 次的循环中,每次查询数据库后,均通过 Sleep 函数让进程暂停 1 秒,那么这个 PHP 进程可能会在服务器端保持 10 秒。在测试过程中,我发现当这个拉取请求运行期间,其他向服务器端 PHP 发起的请求,均受到影响,响应变的非常慢。经过一系列的排查,问题

最近在一个基于 Web 的 IM 项目中,我采用异步向服务器发起请求拉取最新的聊天内容,服务器端通过 PHP 处理拉取请求,拉取过程是用 10 次循环查询数据库是否有最新的聊天内容。如发现新内容,则立即向浏览器输出,并结束掉本次请求的进程。在这 10 次的循环中,每次查询数据库后,均通过 Sleep 函数让进程暂停 1 秒,那么这个 PHP 进程可能会在服务器端保持 10 秒。

在测试过程中,我发现当这个拉取请求运行期间,其他向服务器端 PHP 发起的请求,均受到影响,响应变的非常慢。

经过一系列的排查,问题始终得不到解决,但当把代码中涉及到 SESSION 的部分全部跳过时,情况发生了变化,所有 PHP 进程都恢复正常的响应速度了。由此,联想到问题可能出在了 SESSION 阻塞机制上了。

关于 PHP 的 SESSION 阻塞机制,我们要先了解其工作状态,先看如下代码:

<?php
 
// 第 1 次打印 SESSION 状态
echo 'Status(1):' . session_status() . '<br>'; // 1
 
// 开启 SESSION
session_start();
 
// 第 2 次打印 SESSION 状态
echo 'Status(2):' . session_status() . '<br>'; // 2
 
$_SESSION['test'] = 'hello world';
 
// 等价于 write and close
session_commit();
 
echo $_SESSION['test'] . '<br>';
 
// 第 3 次打印 SESSION 状态
echo 'Status(3):' . session_status() . '<br>'; // 1
 
?>

上述代码输出的结果如下:

Status(1):1

Status(2):2

hello world

Status(3):1

通过 session_status() 这个函数可以得到 SESSION 的状态,返回值含义如下:

0 – 会话是被禁用的。

1 – 会话是启用的,但不存在当前会话。

2 – 会话是启用的,而且存在当前会话。

当上边的代码中第一次通过 session_status() 函数获取 SESSION 状态时,返回值为1,代表当前 SESSION 功能是可用的,但还没有处于激活状态的会话。

用我们非常熟悉的 session_start() 函数开启会话后,再次用 session_status() 函数获取状态,发现返回值已经变为2,这说明当前已经有了激活状态的会话。

重点在 session_commit() 这个函数被执行后,再次获取状态,返回值又变为1。

PHP 的 session_start() 函数执行时相当于完成了会话的 open 和 read 两个步骤,而 session_commit() 执行时相当于进行了会话的 write 和 close 两个步骤,与 session_write_close() 函数作用是一致的。

回到最初遇到的问题上,当 PHP 的 SESSION 开启后,进程会对会话的临时文件加锁,以保证同一时刻此文件只被一个进程修改。此时,如果会话没有 close 而其他进程又开启了会话,后来的进程就会被 PHP 暂时阻塞,等待临时文件解锁。

接下来看两段代码

a.php

<?php
 
session_start();
 
$_SESSION['t1'] = time();
 
sleep(10);
 
echo $_SESSION['t1'];
 
?>

b.php

<?php
 
session_start();
 
$_SESSION['t2'] = time();
 
echo $_SESSION['t1'];
 
?>

我们将上边两段代码分别保存为文件 a.php 和 b.php,首先运行 a.php,紧接着运行 b.php,我们发现在 a.php 没有结束还处于 sleep 状态时,b.php始终被阻塞在那里迟迟无法输出结果,原因就是上边我们分析的会话临时文件被加锁,后来的进程被暂时阻塞的问题。

为了解决这个问题,我们可以在进程进入 sleep 前,通过 session_commit() 函数将会话 close 掉,从而让当前进程解锁会话临时文件,以便让其他进程获得文件的锁。

修改后的 a.php 代码如下:

<?php
 
session_start();
 
$_SESSION['t1'] = time();
 
// write and close
session_commit();
 
sleep(10);
 
echo $_SESSION['t1'];
 
?>

按上边的代码修改 a.php 后,我们再次在浏览器中运行两个文件,a.php 在 sleep 状态下,b.php 已经可以很正常的运行了。

阳光部落原创,更多内容请访问 http://www.sunbloger.com/


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learning PHP, MySQL, and JavaScript

Learning PHP, MySQL, and JavaScript

Robin Nixon / O'Reilly Media / 2009-7-21 / USD 39.99

Learn how to create responsive, data-driven websites with PHP, MySQL, and JavaScript - whether or not you know how to program. This simple, streamlined guide explains how the powerful combination of P......一起来看看 《Learning PHP, MySQL, and JavaScript》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具