浅析PHP中Session可能会引起并发问题


Posted in PHP onJuly 23, 2015

在进行Web应用程序开发的时候,人们经常会用Session存储数据。但可能有人不知道,在PHP中,Session使用不当可能会引起并发问题。印度医疗行业软件解决方案提供商Plus91 Technologies高级工程师Kishan Gor在个人博客上对这个问题进行了阐释。

如果同一个客户端并发发送多个请求,而每个请求都使用了Session,那么PHP Session锁的存在会导致服务器串行响应这些请求,而不是并行。这是因为在默认情况下,PHP使用文件存储Session数据。对于每一个新的Session,PHP会创建一个文件,并持续向其中写入数据。所以,每次调用session_start()方法,就会打开Session文件,并取得文件的独占锁。这样,如果服务器脚本正在处理一个请求,而客户端又发送了一个同样需要使用Session的请求,那么后一个请求会阻塞,直至前一个请求处理完成释放了文件上的独占锁。不过,这只限于来自同一个客户端的多个请求,也就是说,来自一个客户端的请求并不会阻塞另一个客户端的请求。

如果脚本很短,这通常没有问题。但如果脚本运行时间比较长,那就可能会产生问题。在现代Web应用程序开发中,有一个非常常见的情况,就是使用AJAX技术在同一个页面内发送多个请求获取数据。如果这些请求都需要使用Session,那么第一个请求到达服务器后会取得Session锁,其它请求就必须等待,所有请求将串行处理,即使它们彼此之间并没有依赖关系。这将大大增加页面的响应时间。

有一个方法可以避免这个问题,就是在使用完Session以后立即调用session_write_close()方法关闭Session。这样Session锁就会释放,即使当前脚本还在等在处理。需要注意的是,调用该方法后,当前脚本就不能进一步操作Session了。

需要特别指出的是,本文所陈述的问题和观点只适用于使用session_start()方法的PHP默认Session管理模式。比如,有用户就指出,如果将应用程序托管在AWS EC2上,并正确配置DynamoDB,Session锁定问题就不会出现。

附上一份实例代码:

Session.php

<?php

final class SessionController extends YafController_Abstract
{
  public function setUserFileAction()
  {
    session_start();
    $_SESSION['user_name'] = 'xudianyang';
    $_SESSION['user_id']  = '123';

    sleep(3);
    echo json_encode($_SESSION);
    return false;
  }

  public function setLoginFileAction()
  {
    session_start();
    $_SESSION['last_time'] = time();

    echo json_encode($_SESSION);
    return false;
  }

  public function indexFileAction()
  {
    // Auto Rend View
  }

  public function getSessionFileAction()
  {
    session_start();
    var_dump($_SESSION);

    return false;
  }

  public function setUserRedisAction()
  {
    $session = CoreFactory::session();
    $session->set('user_name', 'xudianyang');
    $session->set('user_id', '123');

    sleep(3);
    echo json_encode($_SESSION);
    return false;
  }

  public function setLoginRedisAction()
  {
    $session = CoreFactory::session();
    $session->set('last_time', time());

    echo json_encode($_SESSION);
    return false;
  }

  public function indexRedisAction()
  {
    // Auto Rend View
  }

  public function getSessionRedisAction()
  {
    $session = CoreFactory::session();
    var_dump($_SESSION);

    return false;
  }
}

indexfile.phtml

<!DOCTYPE html>
<html>
<head>
 <title>测试session并发锁问题</title>
 <meta charset="utf-8">
 <script type="text/javascript" src="/assets/js/jquery-1.10.2.min.js"></script>
 <script type="text/javascript">
   $.ajax({
     url: "/session/setUserFile",
     type: "get",
     dataType: "json",
     success: function(response){
       console.info(response.last_time);
     }
   });
   setTimeout(function(){
     $.ajax({
       url: "/session/setLoginFile",
       type: "get",
       dataType: "json",
       success: function(response){
         console.info(response.last_time);
       }
     });
   }, 300);
 </script>
</head>
<body>
同时发起2两个ajax请求
</body>
</html>

indexredis.phtml

<!DOCTYPE html>
<html>
<head>
 <title>测试session并发锁问题</title>
 <meta charset="utf-8">
 <script type="text/javascript" src="/assets/js/jquery-1.10.2.min.js"></script>
 <script type="text/javascript">
   $.ajax({
     url: "/session/setUserRedis",
     type: "get",
     dataType: "json",
     success: function(response){
       console.info(response.last_time);
     }
   });
   setTimeout(function(){
     $.ajax({
       url: "/session/setLoginRedis",
       type: "get",
       dataType: "json",
       success: function(response){
         console.info(response.last_time);
       }
     });
   }, 300);
 </script>
</head>
<body>
同时发起2两个ajax请求
</body>
</html>

以上所述就是本文的全部内容了,希望大家能够喜欢。

PHP 相关文章推荐
PHP如何抛出异常处理错误
Mar 02 PHP
php实现格式化多行文本为Js可用格式
Apr 15 PHP
php如何执行非缓冲查询API
Jul 22 PHP
PHP 表单提交及处理表单数据详解及实例
Dec 27 PHP
yii使用bootstrap分页样式的实例
Jan 17 PHP
基于yaf框架和uploadify插件,做的一个导入excel文件,查看并保存数据的功能
Jan 24 PHP
php微信公众号开发之音乐信息
Oct 20 PHP
Thinkphp整合阿里云OSS图片上传实例代码
Apr 28 PHP
redis+php实现微博(二)发布与关注功能详解
Sep 23 PHP
浅谈laravel orm 中的一对多关系 hasMany
Oct 21 PHP
laravel5.6框架操作数据curd写法(查询构建器)实例分析
Jan 26 PHP
Laravel框架下的Contracts契约详解
Mar 17 PHP
PHP技术开发微信公众平台
Jul 22 #PHP
PHP使用array_merge重新排列数组下标的方法
Jul 22 #PHP
PHP结合jQuery实现找回密码
Jul 22 #PHP
使用PHP生成二维码的方法汇总
Jul 22 #PHP
使用PHP编写发红包程序
Jul 22 #PHP
解决nginx不支持thinkphp中pathinfo的问题
Jul 21 #PHP
php 把数字转换成汉字的代码
Jul 21 #PHP
You might like
smarty静态实验表明,网络上是错的~呵呵
2006/11/25 PHP
轻松修复Discuz!数据库
2008/05/03 PHP
PHP插入排序实现代码
2013/04/04 PHP
PHP序列化/对象注入漏洞分析
2016/04/18 PHP
PHP实现驼峰样式字符串(首字母大写)转换成下划线样式字符串的方法示例
2017/08/10 PHP
laravel-admin 在列表页添加自定义按钮的例子
2019/09/30 PHP
JavaScript 学习点滴记录
2009/04/24 Javascript
鼠标滑上去后图片放大浮出效果的js代码
2011/05/28 Javascript
提交表单时执行func方法实现代码
2013/03/17 Javascript
jquery实现简单的自动播放幻灯片效果
2015/06/13 Javascript
谈谈对offsetleft兼容性的理解
2015/11/11 Javascript
原生js实现弹出层登录拖拽功能
2016/12/05 Javascript
浅谈Angular4中常用管道
2017/09/27 Javascript
通过js控制时间,一秒一秒自己动的实例
2017/10/25 Javascript
利用babel将es6语法转es5的简单示例
2017/12/01 Javascript
npm scripts 使用指南详解
2018/10/08 Javascript
微信小程序的mpvue框架快速上手指南
2019/05/15 Javascript
vue子路由跳转实现tab选项卡
2019/07/24 Javascript
node 解析图片二维码的内容代码实例
2019/09/11 Javascript
python开启多个子进程并行运行的方法
2015/04/18 Python
Python随手笔记第一篇(2)之初识列表和元组
2016/01/23 Python
Python脚本实时处理log文件的方法
2016/11/21 Python
django 发送邮件和缓存的实现代码
2018/07/18 Python
Python的缺点和劣势分析
2019/11/19 Python
python中pyplot基础图标函数整理
2020/11/10 Python
python中delattr删除对象方法的代码分析
2020/12/15 Python
CSS3等相关属性制作分页导航实现代码
2012/12/24 HTML / CSS
HTML利用九宫格原理进行网页布局
2020/03/13 HTML / CSS
雅诗兰黛(Estee Lauder)英国官方网站:世界顶级化妆品牌
2016/12/29 全球购物
法国包包和行李箱销售网站:Bagage24.fr
2020/03/24 全球购物
final, finally, finalize的区别
2012/03/01 面试题
群众路线教育实践活动学习心得体会
2014/10/30 职场文书
医生辞职信范文
2015/03/02 职场文书
法人代表资格证明书
2015/06/18 职场文书
受欢迎的自荐信,就这么写!
2019/04/19 职场文书
关于React Native使用axios进行网络请求的方法
2021/08/02 Javascript