zoukankan      html  css  js  c++  java
  • Web提速:避免php session拖慢执行速度

    Web提速:避免php session拖慢运行速度

     

    一、WHAT--并发訪问,堵塞运行
    1.1 不使用session

    文件index.php:

    <script type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
    <script type="text/javascript">
    $(document).ready(function(){
    $.ajax({url:"/ajax.php"});
    $.ajax({url:"/ajax2.php"});
    $.ajax({url:"/ajax3.php"});
    });
    </script>


    文件ajax.php、ajax2.php、ajax3.php的内容都是

    <?

    php sleep(1); echo "php script run";



      每一个请求都sleep 1s,jq的ajax请求是异步的,也就是说这三个请求基本上是同一时候发出的,理论上最好的情况是浏览器等待1s,3个接口所有返回。

    訪问http://localhost,在chrome下查看測试结果:


    图 1.1 不使用session測试结果

      測试结果基本上跟理论一致

    1.2 使用session

    如今我们把文件ajax.php、ajax2.php、ajax3.php都改为

    <?

    php session_start(); sleep(1); echo "php script run";




    这样做会什么有什么差别吗?我们直接看測试结果:


    图 1.2 使用session測试结果

    不是每一个请求仅仅运行1s钟吗?为什么ajax2.php消耗了2s。ajax3.php消耗3s?

    二、WHO -- Session锁

    session锁的官方定义:

            Session data is usually stored after your script terminated without the need to call session_write_close(), but as session data is locked to prevent concurrent writes only one script may operate on a session at any time.

      大致的意思是: 从调用session_start()開始,直到显示调用session_write_close()或脚本结束,session的数据都会被锁起来,届时同一个SESSIONID用户的请求会被堵塞。

    从图1.2的測试结果看到,ajax2.php与ajax3.php分别多运行了1s和2s。很明显session_start()操作造成了堵塞。

      当index.php同一时候訪问ajax.php、ajax2.php、ajax3.php,ajax.php首先运行。此时ajax2.php与ajax3.php都在等在ajax.php释放session锁。都消耗1s。

      当ajax.php运行完毕。释放了session锁,ajax2.php与ajax3.php再次竞争session锁,同理ajax3.php又等待了1s钟。

    所以我们得到的结果:

      ajax.php 消耗1s

      ajax2.php 消耗2s

      ajax3.php 消耗3s

    三、WHEN -- 什么时候会触发Session锁

      在章节二中,session锁定义为session_start()開始即会触发session锁,所以对于现有大部分php框架(使用原生php session的情况下)存在session锁造成的用户请求堵塞的问题。试想,有2个请求,当中请求A须要3s钟才干返回结果,另外请求B仅须要10ms即能返回,前端同一时候请求这两个接口,假如后台先处理了A请求,那么B请求就要等待3s后再运行10ms才干返回结果。可是最优的情况是,同一时候发起请求,10ms后收到B请求返回,3s后收到A请求返回。

    四、WHY -- Session内部运行机制

      默认情况下php session採用文件为服务端存储介质。在php session模块的源代码中。有一个比較重要的结构体:


    图4.1 php session模块结构体 ps_module_struct


      该结构体里面的几个函数指针分别相应了session操作的open、close、read、write、destory、gc回收等功能。看到这6个函数,是否想起了php的SessionHandlerInterface接口(版本号>=php5.4)?


    图4.2 php SessionHandlerInterface接口

      用这个接口配合session_set_save_handler能够重写session的这几个关键操作。于是我们能够使用下面代码来探探php session在一个请求的生命周期中的运行顺序:

    图4.3 session运行顺序測试代码

    測试结果:

      由測试结果可知一般的session运行顺序。在session_start()调用时,php回去调用open和read操作,脚本运行结束后(输出了php script run),再会调用write和close操作。

    如今我们最好还是做一个大胆的猜想。php 在 session的open或者read操作时,开启了session锁。并write或close后释放session锁。这样的猜想也符合我们在章节1的測试结果。

      为了验证我们的猜想。就须要去php的源代码探个到底了。在php源代码文件/ ext / session / mod_files.c中能够看到默认session的6个重要操作的部分实现。在156行(点击打开链接)。看到open操作有一个打开文件操作:flock(data->fd, LOCK_EX);该操作以相互排斥锁定的方式打开文件。在110行关掉文件close(data->fd);。

      看到这里,我们应该得到的结论是:

    在默认情况下,所谓的php session锁事实上就是文件锁

      所以,当我们使用session_set_save_handler来自定session操作,改用memcache或其它介质时,仅仅要我们在SessionHandlerInterface的接口中没有锁的逻辑。那么session锁自然也不会存在。

    作者私下也做了这样的实验。实践证明也的确如此。

    五、HOW -- 怎样避免Session锁带来的堵塞现象

      首先,session锁不一定是坏事情,在一种情况下就很好用。比如某接口对与同一个用户的请求默认同一时刻仅仅能运行一次。

    这样的时候。就能够用seesion_start()和session_write_close()把要堵塞的代码括起来。很easy暴力有用。

      可是大部分时候我们还是要避免这样的锁的存在,解决方式:

    1、在用完session的时候就立即session_write_close()掉,释放session锁

    2、採用没有锁的session操作,如章节4中所说的用session_set_save_handler来自己定义一个没有锁的session操作。

    3、再使用默认php session时,个人比較中意的一个方案:大部分情况下,我们对session的操作基本上都是读操作。写操作一般都比較少。

    这样的时候。我们能够自己写一个session类。

    构造函数:将session读入cache,关闭session锁

    写操作:打开session锁,写入值,关闭session锁

    读操作:直接读cache

    部分代码例如以下:

    //将session读入全局变量$_SEESION
    static private function init(){
    if(self::$not_init){
     session_start();
     session_write_close();
     self::$not_init = false;
    }
    }


    //读session
    static public function get($name){
    self::init();
    return $_SESSION[$name];
    }


    //写session
    static public function set($name, $val){
    session_start();
    $_SESSION[$name] = $val;
    session_write_close();
    }


    注意:假设是写操作频繁的操作,就不适合使用该方法。

     

     


  • 相关阅读:
    php 有趣的头像拼图
    php基础篇-二维数组排序姐妹篇
    php基础篇-二维数组排序 array_multisort
    php应用篇-百度图片的防盗链
    《留给自己,也留给每一位在青春里迷茫找不到自己的年轻人》 爱你现在的时光——白岩松
    没有什么能一下打垮你,就像没有什么能一下拯救你
    php基础篇-双引号、单引号的区别
    TortoiseSVN Start
    cover-view文案被切割:加全角空格
    canvas不显示,必须设置canvas-id
  • 原文地址:https://www.cnblogs.com/mqxnongmin/p/10868742.html
Copyright © 2011-2022 走看看