浅析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 相关文章推荐
开启CURL扩展,让服务器支持PHP curl函数(远程采集)
Mar 19 PHP
PHP递归返回值时出现的问题解决办法
Feb 19 PHP
jQuery+php实现ajax文件即时上传的详解
Jun 17 PHP
PHP中使用memcache存储session的三种配置方法
Apr 05 PHP
PHP采用XML-RPC构造Web Service实例教程
Jul 16 PHP
php设计模式之简单工厂模式详解
Sep 04 PHP
PHP输入输出流学习笔记
May 12 PHP
PHP中strcmp()和strcasecmp()函数字符串比较用法分析
Jan 07 PHP
一个简单的php MVC留言本实例代码(必看篇)
Sep 22 PHP
PHP实现登录搜狐广告获取广告联盟数据的方法【附demo源码】
Oct 14 PHP
IOS 开发之NSDictionary转换成JSON字符串
Aug 14 PHP
PHP基于array_unique实现二维数组去重
Jul 14 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
星际争霸 Starcraft 游戏介绍
2020/03/14 星际争霸
PHP 计算代码执行耗时的代码修正网上普遍错误
2011/05/14 PHP
使用纯php代码实现页面伪静态的方法
2015/07/25 PHP
php 5.4 全新的代码复用Trait详解
2017/01/05 PHP
ThinkPHP 3.2.2实现事务操作的方法
2017/05/05 PHP
PHP 实现浏览记录并按日期分组
2017/05/11 PHP
PHP操作Redis常用技巧总结
2018/04/24 PHP
PHP实现的操作数组类库定义与用法示例
2019/05/24 PHP
浅析PHP中的 inet_pton 网络函数
2019/12/16 PHP
阻止子元素继承父元素事件具体思路及实现
2013/05/02 Javascript
在JavaScript中判断整型的N种方法示例介绍
2014/06/18 Javascript
JavaScript更改字符串的大小写
2015/05/07 Javascript
jQuery实现转动随机数抽奖效果的方法
2015/05/21 Javascript
JAVASCRIPT代码编写俄罗斯方块网页版
2015/11/26 Javascript
JavaScript制作弹出层效果
2016/12/02 Javascript
一个简易的js图片轮播效果
2017/07/22 Javascript
详解.vue文件中style标签的几个标识符
2018/07/17 Javascript
Vue computed 计算属性代码实例
2020/04/22 Javascript
python使用循环实现批量创建文件夹示例
2014/03/25 Python
python中使用xlrd、xlwt操作excel表格详解
2015/01/29 Python
Python爬取网易云音乐上评论火爆的歌曲
2017/01/19 Python
Python实现将SQLite中的数据直接输出为CVS的方法示例
2017/07/13 Python
详解Python 模拟实现生产者消费者模式的实例
2017/08/10 Python
浅谈python函数之作用域(python3.5)
2017/10/27 Python
对python的unittest架构公共参数token提取方法详解
2018/12/17 Python
jupyter lab文件导出/下载方式
2020/04/22 Python
Python应用实现双指数函数及拟合代码实例
2020/06/19 Python
Python实现GIF图倒放
2020/07/16 Python
python实现mask矩阵示例(根据列表所给元素)
2020/07/30 Python
Python提取视频中图片的示例(按帧、按秒)
2020/10/22 Python
3个CCIE对一个工程师的面试题
2012/05/06 面试题
五好家庭事迹材料
2014/12/20 职场文书
研究生给导师的自荐信
2015/03/06 职场文书
学生退学证明
2015/06/23 职场文书
Java Socket实现多人聊天系统
2021/07/15 Java/Android
vue配置型表格基于el-table拓展之table-plus组件
2022/04/12 Vue.js