Symfony 2阻止了并发

Sla*_* II 3 php concurrency blocking symfony

我有一个Symfony 2.5应用程序,我有一些奇怪的请求并发问题.

为了演示这个问题,我创建了两个名为/timeand的路由/sleep.控制器的主体非常简单:

timeAction():
    time();

sleepAction()
    sleep(30);
Run Code Online (Sandbox Code Playgroud)

当我/time在浏览器中请求路由时 - 它会立即响应当前时间戳.但是,当我第一次请求/sleep路线然后/time路线时 - 它只是挂在那里直到sleep()完成.只有在此之后,/time控制器才会响应时间戳.换句话说 - 一个请求阻止所有其他请求.我一开始并没有注意到这一点,但是当你有长期执行计划的请求时 - 它变得明显.

这可能是什么原因?

我还是要自己做一些额外的测试来深入挖掘这种情况.我将尝试更详细地更新问题.

Sla*_* II 6

更新

看起来PdoSessionHandler现在使用它自己的一些锁定机制来阻止并发请求.旧的解决方案将不再开箱即用.

并发问题的官方解决方案是在请求处理周期中尽快关闭会话.您可以通过调用$session->close()或执行此操作session_write_close().

但是,如果您确定应用程序中不会出现会话数据冲突,则可以安全地禁用PDO会话处理程序配置中的锁定:

# services.yml

session.handler.pdo:
        class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
        public: false
        arguments:
            - "pgsql:host=%database_host%;port=%database_port%;dbname=%database_name%"
            - db_username: %database_user%
              db_password: %database_password%
              db_table: session
              db_id_col: session_id
              db_data_col: session_value
              db_time_col: session_time
              db_lifetime_col: session_lifetime
              lock_mode: 0 # LOCK_NONE
Run Code Online (Sandbox Code Playgroud)

您可以在本期杂志中阅读更多内容:https: //github.com/symfony/symfony/pull/10908

老解决方案

感谢Crozin指出了我正确的方向,这有助于解决我的问题.我将在此处提供其他信息,希望将来可以帮助某人节省一些时间.

以下主题还介绍了此问题:

问题是PHP默认使用基于文件的会话处理.换句话说,会话数据存储在服务器文件系统的特定文件中.并且为了保护该文件免于意外同时写入,使用文件锁定机制.这是计算机科学中的经典锁定问题.对PHP的第一个请求将获得会话文件的锁定,所有其他请求将必须等待释放此锁定.如果您在多请求环境中有一个持久的请求(例如同时使用AJAX请求或页面上有多个帧),它将变得明显.

这个问题可以通过session_write_close()在脚本完成之前预先调用,但在完成所有会话操作之后调用,或者通过切换到另一个会话存储机制(如数据库会话存储)来解决.

我认为,在Symfony 2中,最好的做法是与PDO处理程序(在您选择的数据库中)存储会话.以下是如何设置它的官方教程:

如何使用PdoSessionHandler在数据库中存储会话.

提示:如果您正在使用Doctrine迁移,那么您可以创建一个新的迁移类,并添加为创建会话存储表所需的SQL.

使用这种方法,您将拥有更好的非阻塞会话存储机制,您的应用程序将能够水平扩展.