【问题标题】:session_start hangssession_start 挂起
【发布时间】:2011-05-19 00:09:34
【问题描述】:

在几个小时内,每次您执行 session_start 时,我们的服务器都会挂起。

出于测试目的,我创建了一个如下所示的脚本:

<?php
session_start();
?>

从控制台调用它会挂起,甚至不能用 ctrl-c 停止,只有 kill -9 有效。通过 Apache 调用它也是如此。 /var/lib/php/session/ 保持为空,但权限绝对没问题,www 可以写入并且对所有父文件夹都有读取权限。

根据管理员的说法,服务器上没有进行任何更改,也没有为会话注册特殊代码。服务器是 CentOS 4 或 5,昨天一切正常。我们重启了服务器并更新了 PHP,但没有任何改变。

我的想法已经用完了,有什么建议吗?

更新

我们通过将项目移动到另一台服务器解决了这个问题,因此虽然问题仍然存在于一台服务器上,但不再需要立即解决。 不过,如果有人对将来遇到类似问题的其他人有想法,我会保持开放状态。

【问题讨论】:

  • 检查系统错误日志 - 是否有足够的空间?你的日志文件没有溢出吗?你没有用完inode吗? /tmp/session 中的文件数量或存储文件的位置是否有限制?
  • 日志文件显示没有错误,并且存储在 NFS 上。访问同一 NFS 的另一台服务器适用于该项目。会话文件的数量没有限制。
  • 服务器 A 与 NSF 之间的连接存在问题。再次检查连接。

标签: php session


【解决方案1】:

有很多原因,这里有几个:

A. 会话文件可以以独占方式打开。 当文件锁定由于某种原因没有正确释放时,它会导致session_start() 在任何未来的脚本执行中无限挂起。 解决方法:使用session_set_save_handler(),并确保写入函数使用fopen($file, 'w') instead of fopen($file, 'x')

B.切勿在您的 php.ini 文件中使用以下内容(熵文件为“/dev/random”),这将导致您的session_start() 挂起:

<?php
ini_set("session.entropy_file", "/dev/random");
ini_set("session.entropy_length", "512");
?>

C. session_start() 需要一个目录来写入。

您可以在普通用户帐户中运行 Apache 和 PHP。 Apache 当然必须监听 80 以外的其他端口(例如 8080)。

请务必执行以下操作: - 创建一个临时目录PREFIX/tmp - 将php.ini 放入PREFIX/lib - 编辑 php.ini 并将 session.save_path 设置为您刚刚创建的目录

否则,您的脚本将在session_start() 上“挂起”。

【讨论】:

  • 重启后应该没有任何锁了,lsof 没有显示其他正在运行的 PHP 脚本。我们没有改变熵文件或长度。会话的路径存在并且是可写的,所以 C 似乎也不是。我们将项目移动到另一个具有相同配置的节点,它再次在那里工作。感谢您的回复,但似乎不是问题。
  • 尝试使用自定义的非基于文件的会话处理程序。
  • 你能提供更多关于选项 A 的细节吗?
【解决方案2】:

如果这有帮助:

在我的场景中,session_start() 在我在 Windows 上的 IDE PHPStorm 中使用 XDebug 调试器的同时挂起。我发现有一个明确的原因:每当我从 PHPStorm 中终止调试会话时,下次我尝试运行调试会话时,session_start() 就会挂起。

如果这是您的方案,解决方案是确保每次在 IDE 中终止 XDebug 会话时都重新启动 Apache。

【讨论】:

  • 这个建议对我有帮助。谢谢。
  • 我刚刚遇到了这个问题。您的解决方案会有所帮助。
【解决方案3】:

我自己对此有一个奇怪的问题。

我使用的是 CentOS 5.5x64,PHP 5.2.10-1。根目录中有一个干净的 ANSI 文件,除了 session_start() 之外什么都没有。会话正在写入磁盘并且没有抛出任何错误。刚刚挂了。

我尝试了 Thariama 的所有建议,并检查了 PHP 编译设置等。

我的修复:

yum reinstall php;  /etc/init.d/httpd restart

希望这对某人有所帮助。

对于抱怨 30 秒的停机时间是不可接受的每个人来说,这是在全新的、干净的操作系统安装上出现的莫名其妙的问题,而不是在运行的生产机器上。此解决方案不应在生产环境中使用。

【讨论】:

  • @Wimpie 重新安装 php 并重新启动 httpd 大约需要 30 秒,即使在低级 VPS 上也是如此。
  • @csvan 这正好是 30 秒的不可接受的停机时间
  • @KapiteinZeiksnor 30 秒不可接受的停机时间,您可以通过向访问者显示您正在进行紧急维护并将在 30 秒内恢复的消息轻松缓解这种情况。
  • @KapiteinWitbaard 如果你看到这个特殊的问题,你已经死在水里了。
  • @csvan 30 秒可以在您的网站不赚钱时接受。当您以平均 65 美元的价格每小时接受 10,000 个订单时,那么 30 秒或 5417 美元绝对是不可接受的。如果您是客户服务部门,是唯一受此特定错误影响的人,并且您的客户仍在订购,那么不,您还没有死在水中。此修复程序可能适用于您的博客,但不适用于我的电子商务网站。
【解决方案4】:

好的,我在 2 台 PC 上遇到同样的问题,1 台是 MAC mini XAMPP,1 台是 Windows 10 Xampp。 两者都是 php 花费了无穷大来运行 session_start()。两个 PHP 版本都是 7.x.x

我发现会话文件被锁定读写。所以我添加了代码让 PHP 读取会话文件并在完成后立即解锁

<?php
session_start([
    'read_and_close' => true,
]);
?>

<?php
//For PHP 5.x
session_start();

session_write_close();
?>

在这个 PHP 解锁会话文件之后 => 问题解决

【讨论】:

    【解决方案5】:

    问题:-

    我遇到(并修复了)基于文件的会话挂起请求的问题,并且基于数据库的会话通过存储过期的会话数据(例如以错误的顺序存储每个会话保存)而失去同步。

    这是由加载会话(同时请求)的任何后续请求引起的,例如 ajax、通过 php 脚本传递视频文件的视频嵌入、通过 php 脚本传递的动态资源文件(如脚本或 css)等。

    在基于文件的会话中,文件锁定会阻止会话写入,从而导致同时请求线程之间的死锁。

    在基于数据库的会话中,最后一个完成的请求线程成为最近的保存,因此,例如,视频交付脚本将在页面请求后很长时间完成,并用旧会话数据覆盖自更新后的会话。

    修复:-

    如果您的 ajax 或资源交付脚本不需要使用会话,那么最简单的方法是从中删除会话使用。

    否则你最好给自己泡杯咖啡,然后做以下事情:-

    1. 根据http://www.php.net//manual/en/class.sessionhandler.php 编写或使用会话处理程序(如果尚未这样做)(可通过谷歌搜索获得许多其他示例)。
    2. 在您的会话处理函数 write() 中添加代码...

          // processes may declare their session as read only ...
          if(!empty($_SESSION['no_session_write'])) {
                  unset($_SESSION['no_session_write']);
                  return true;
          }
      
    3. 在您的 ajax 或资源交付 php 脚本中添加代码(在会话启动后)...

          $_SESSION['no_session_write'] = true;
      

    我意识到这似乎是一个很小的修复,但不幸的是,如果您需要同时请求每个加载会话,那么它是必需的。

    注意,如果您的 ajax 或资源交付脚本确实需要写入/保存数据,那么您需要在会话之外的其他地方进行,例如数据库。

    【讨论】:

      【解决方案6】:

      我不知道为什么,但是在 /etc/php/7.4/apache2/php.ini 中更改此值对我有用:

      ;session.save_path = "/var/lib/php/sessions"
      session.save_path = "/tmp"
      

      【讨论】:

        【解决方案7】:

        为了给那些疯狂的人提供另一个答案,我有一个 session_start() 仅在特定情况和脚本中死亡。我的会话结束的原因最终是因为我在一个特别密集的脚本之后在其中存储了大量数据,最终对 session_start() 的调用耗尽了 php.ini 中的“memory_limit”设置.

        增加“memory_limit”后,那些session_start() 调用不再杀死我的脚本。

        【讨论】:

          【解决方案8】:

          只要把 session_write_close();在 Session_start() 之前;

          如下:

          <?php
              session_write_close();
              session_start();
              .....
          ?>
          

          【讨论】:

            【解决方案9】:

            对我来说,问题似乎源于 SeLinux。所需的命令是 chcon -R -t httpd_sys_content_t [www 目录] 以授予对正确目录的访问权限。 见https://askubuntu.com/questions/451922/apache-access-denied-because-search-permissions-are-missing

            【讨论】:

              【解决方案10】:

              如果您使用 pgAdmin 4,这也可能发生。

              如果您禁用了 文件 > 首选项 > SQL 编辑器 > 选项 > “自动提交”,并且您只是使用查询工具运行了查询但没有手动提交,那么 session_start() 将冻结。

              启用自动提交,或者手动提交,或者直接关闭pgAdmin,它就不会再冻结了。

              【讨论】:

                【解决方案11】:

                在我的情况下,似乎是 NFS 共享 锁定了会话,在重新启动 NFS 服务器并且只启用了 1 个网络客户端节点后,会话正常工作。

                【讨论】:

                  【解决方案12】:

                  另外几美分可能对某人有所帮助。在我的情况下,我将复杂数据存储在 $_SESSION 中,其中包含几个不同的类对象,并且 session_start() 无法处理整个反序列化,因为并非每个类都加载到 session_start 上。解决方案是我的情况是在将数据保存到 $_SESSION 之前序列化/jsonify 数据,并在我将数据从会话中取出后反转该过程。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-01-19
                    • 1970-01-01
                    • 2017-02-25
                    • 2014-11-18
                    • 1970-01-01
                    相关资源
                    最近更新 更多