PHP 中的随机会话数据丢失
这是我们过去几周一直面临的问题。
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个应用程序和有问题的应用程序之间可能存在的交互,尽管它们不共享任何代码,数据库或会话处理。那里什么也没发现。
- 我们已经分析了断开连接时间的访问日志,以检查行为模式 :这里也没有运气。
因此,我们不知道是什么原因导致此问题,因为它似乎是随机发生的,所以我的问题是:
- 问题可能来自我们的代码:我们是否遗漏了任何要检查的内容?这种解决方案似乎不太可能,因为代码大部分时间都适用于我们所有的用户,但我仍在考虑它。
- 问题可能来自另一个应用程序/进程,该应用程序/进程将会话变量数组的“空”部分。我们还查看了其他应用程序中的代码,但没有找到任何可能导致这种情况的原因。如果另一个进程正在这样做,为什么它只会清空一些会话而不是所有会话?
感谢您的帮助。