深入研究 PHP 的 SESSION 阻塞问题

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

内容简介:最近在一个基于 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/


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

查看所有标签

猜你喜欢:

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

系统分析与设计方法

系统分析与设计方法

惠滕 / 孙慧、肖刚 / 机械工业出版社 / 2004-9 / 69.00元

本书是介绍信息系统分析和设计原理、方法、技术、工具和应用的力作,自问世以来,广受欢迎,以至于一版再版,延续至今。 本书采用一个完整的案例研究,以整个信息系统构件(基于Zachman框架)和信息系统开发生命周期(FAST方法学)为主线,详细探讨了系统开发生命周期的前期、中期和后期以及跨生命周期的活动。另外,书中第一章都提供了大量的练习题、讨论题、研究题和小型案例,以加深读者对书中所述理论的实际应用和......一起来看看 《系统分析与设计方法》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具