长时间运行的管理页面请求阻止其他请求


17

如果我登录到Magento的后端并执行一些需要很长时间的任务(在大型目录上进行全局搜索,长时间运行的数据流等),则我的Web浏览器将拒绝仅在该浏览器中加载其他管理页面。为什么会发生这种情况,并且有任何已知的解决方法科学?

也就是说,如果我

  1. 登录到Magento的仪表板页面

  2. 使用任何Magento管理页面打开第二个标签页

  3. 在第一个标签中执行长时间运行的全局搜索(以sleep(30)开头的调用模拟globalSearchAction

  4. 尝试重新加载第二个标签

预期的行为:第二个选项卡立即加载页面内容

实际行为:只有长时间运行的全局搜索完成后,才会加载第二个选项卡

有谁知道具体为什么会这样?(我的猜测是Magento管理控制台请求锁定了Magento需要引导的某些资源,但我不知道那是什么)

有人知道修复/解决方法吗?


1
先生,您刚刚向我发送了挑战!:)
davidalger

Answers:


21

该问题是由PHP会话处理程序放置的锁引起的。因此,这不是Magento明确锁定某些内容并试图阻止管理员请求,而是基于文件的会话存储本身的几乎副作用。

当通过初始(长时间运行)请求打开会话数据文件时,会将写锁放置在会话数据文件上,从而导致第二个请求阻塞,直到调用它时释放该锁为止session_startMage_Core_Model_Session_Abstract_Varien::start

这是100%可复制的。我使用了与您相同的方法,sleep(30)Mage_Adminhtml_IndexController::globalSearchAction

值得注意的是,如果您正在使用数据库会话存储,则无法复制。找到根本原因后,我将一个沙箱设置为数据库会话存储,不再能够重现该问题。因此,Magento的数据库会话处理程序似乎不使用行级锁定来锁定会话写入。我发现这很有趣,因为它有可能丢失会话数据,因为该应用程序显然没有考虑写入同一会话的多个线程。读者注意事项:我绝不会在生产中使用db会话存储来尝试解决此问题,这仅适用于重载MySql数据库。

我没有尝试使用基于内存的会话存储系统(例如Redis)来重现该行为,但我的猜测是在这些存储中也可能忽略了锁定会话存储中的记录。

有一些技术可以避免这种情况,例如session_write_close在开始长期运行的作业之前先使用释放锁。但是,这也将阻止您写入该会话,因为您刚刚将其关闭。因此,它不太可能在Magento中全面实现,而有可能在特定的路径/控制器上实现。

我将其固定为根本原因的技术是启用Xdebug分析器并检查“ cachegrind”文件。第二个请求完成后,我将输出文件(约25 MB日志)加载到MacCallGrind中,并沿着包含最终时间为28秒或更长的调用路径深入到跟踪中。最终,我session_start花了大约28秒才能完成通话,这给了我很好的研究依据。

编辑:对于感兴趣的人,我已经在Twitter的MacCallGrind中发布了 “ cachegrind”文件的屏幕截图


Unirgy的uRapidFlow模块为了避免此问题而关闭了会话,这在某种程度上是不错的,但是令人沮丧的是,它使得以后难以向用户提供反馈。
彼得·奥卡拉汉

@davidalger —通常为客户端站点部署什么会话存储?
艾伦·风暴

3
回复:锁定PHP会话文件,这对数据完整性的要求要小于对磁盘文件本身的完整性的要求。具有多个进程打开并写入磁盘上的位(文件即文件)将迅速导致数据损坏。MySQL,redis和大多数数据库都是专​​门为保持一致而设计的,即使几乎同时进行多次写入也是如此。也就是说,并不是不是忽略了锁定,而是因为它不是非常需要的。
艾伦·风暴

@AlanStorm —用于单个应用程序节点群集的负载均衡安装文件系统的专用Memcached实例。由于没有IP延迟,因此在没有多个节点的情况下,文件系统的性能最佳。
davidalger

正确,锁定文件只是为了防止数据损坏。但是,将锁保持到会话关闭之前是为了防止数据丢失。如果有两个进程加载会话数据,先对其进行修改然后将其写出,则其中之一将覆盖其修改。通常不会造成严重问题,但可能导致数据丢失和/或难以调试的麻烦。
davidalger
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.