PHP 中的随机会话数据丢失

2022-08-30 23:48:24

这是我们过去几周一直面临的问题。

1/ 我们的设置

  • PHP 5.4 + MySQL
  • 2 台专用服务器,负载平衡
  • 使用 memcached 在 2 台服务器之间复制会话
  • 在这些服务器上运行的 3 个应用程序:
    • 一个自定义开发的应用程序,使用默认的 php 会话设置
    • 另一个自定义开发的应用程序,使用不同的会话设置(Cookie 名称、路径)
    • 一个Wordpress CMS

2/ 问题

问题发生在我们的第一个应用程序上。

我们的一些用户报告说,他们有时会在几分钟后断开连接(当会话设置为持续3小时时)。它可能在同一天发生在他们身上几次,然后几天没有断开连接,但问题总是回来。到目前为止,受影响的用户比例很小,但我想在它“传播”给其他用户之前解决这个问题。

问题似乎发生在应用程序的不同位置,尽管我们已经确定了大多数错误发生的3个scenarii :

  • 有些涉及提交表单($_SESSION变量被修改)
  • 其他只是简单地打开一个弹出页面,而不修改会话数据

我们试图重现用户描述的不同scenarii :有时我们已经能够做到,但大多数时候我们没有任何问题,这使得调试变得困难。

其他注意事项 :

  • 问题是最近才出现的,此应用程序已经运行多年而没有任何问题。
  • 这似乎与我们的服务器负载无关,因为问题仍然发生在暑假期间,当时我们的trafic很低。
  • 它一次只影响一个会话/用户:同时登录的所有其他用户都不会遇到此问题
  • 问题发生在所有不同的浏览器(IE,火狐,Chrome)上

3/ 技术分析

发生断开连接时,用户将被重定向到“您的会话已过期或您无权查看”的页面。加载此页面后,我们会收到一封技术电子邮件,其中包含 $_SESSION 变量的转储。

当会话以正常方式过期时,我们收到的电子邮件显示 $_SESSION 变量为空(正常行为)。当发生意外断开连接时,有趣的是$_SESSION并非完全为空:在数组包含的约20个元素中,只剩下一个(始终相同)。

因此,这意味着会话未过期,但没有足够的数据来“识别”用户,因此显示“无权限”页面。作为发生这种情况时的确认,我们可以检查memcached此会话是否仍包含一些数据。

这些是到目前为止我们已经确定的潜在问题原因,以及我们为排除它们所做的工作:

  • Memcached表示在70%到80%的自由空间之间,所以我们不认为这是问题所在。
  • 我们删除了 Memcached,并返回到对会话文件使用 NFS 共享目录:问题实际上变得更糟了。这将指向一个应用错误,因为NFS写入数据的速度较慢,会话丢失将更频繁地发生。
  • 我们已经浏览了所有不同的论坛(包括SO)讨论PHP会话数据丢失,并相应地审查了我们的代码。代码库很大,但我们使用了自动化工具和脚本来避免丢失文件。
    • session_start() 在每个页面的开头调用。
    • exit() 在每个标头之后调用(“位置...”)
    • register_globals已关闭
  • 我们已经测试了其他2个应用程序和有问题的应用程序之间可能存在的交互,尽管它们不共享任何代码,数据库或会话处理。那里什么也没发现。
  • 我们已经分析了断开连接时间的访问日志,以检查行为模式 :这里也没有运气。

因此,我们不知道是什么原因导致此问题,因为它似乎是随机发生的,所以我的问题是:

  • 问题可能来自我们的代码:我们是否遗漏了任何要检查的内容?这种解决方案似乎不太可能,因为代码大部分时间都适用于我们所有的用户,但我仍在考虑它。
  • 问题可能来自另一个应用程序/进程,该应用程序/进程将会话变量数组的“空”部分。我们还查看了其他应用程序中的代码,但没有找到任何可能导致这种情况的原因。如果另一个进程正在这样做,为什么它只会清空一些会话而不是所有会话?

感谢您的帮助。


答案 1

我不认为你会得到一个明确的答案。有太多可能的原因,你还没有显示任何代码。

不过,我的猜测是,你已经关闭了memcached.sess_locking,或者如果你有一个自定义会话实现 - 它根本没有实现锁定。
最终,这会导致两个同时进行的 HTTP 请求之间的争用情况。

我的猜测是基于经常看到的坏建议,即尽快关闭锁或释放它们,以实现更高的性能。


答案 2

如果“突然”出现此问题,请检查已更改的内容。您是否对应用程序执行过任何工作?如果是这样,请检查提交的代码(您谈到了自动化工具,所以我希望有一个存储库,可以准确查找代码更改)。您是否在服务器上更改了任何内容?像升级软件,升级/更换硬件,对其他两个应用程序进行更改?有一件事突然浮现在脑海中,您是否检查了用于缓存的驱动器?它可能是文件系统的损坏部分。这可以解释随机用户部分。

我一直想做的几件事是:

  • 尝试尽可能准确地确定首次发生的时刻。在我的工作中,这偶尔会触发某人说“哦,是的,这可能与我更改/更新/创建这个或那个有关”,所以这可能会有所帮助。另一方面,有时可能需要数天,数周或更长时间才能注意到某些事情,因此,如果没有出现任何问题,请开始扩展该时间框架。
  • 你已经有几个场景,找到这些中的共同因素。如果他们不共享任何代码,请停止查看那里。如果他们确实在那里共享代码搜索。当然,在这里分享(部分)它可能会让我们帮助您搜索。
  • 执行有组织的搜索。我通常在处理应用程序最多的人时(或者在创建应用程序时更好)进行主应用程序检查。同事将检查可能对它产生影响的周围应用程序。在您的情况下,其他2个应用程序。最后,我们的系统管理员将检查服务器上新安装或更新的软件,他还将与我们的网络人员一起检查是否有任何硬件更改或与网络相关(对于其他人来说,这可能是托管服务提供商)。

推荐