Symfony 2 blocked concurrency

后端 未结 2 1944
失恋的感觉
失恋的感觉 2021-01-20 05:34

I have a Symfony 2.5 application and I have some weird problems with request concurrency.

To demonstrate the issue I\'ve created two routes called /time

2条回答
  •  失恋的感觉
    2021-01-20 05:39

    Update

    Looks like PdoSessionHandler is now uses some locking mechanism of it's own that will prevent concurrent requests. The old solution will no longer work out of the box.

    The official solution to the concurrency problem is to close the session as soon as possible in the request handling cycle. You can do this by calling $session->close() or session_write_close().

    However, if you are sure that session data conflicts will not arise in your application you can safely disable locking in the configuration of the PDO session handler:

    # 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
    

    You can read more in this issue: https://github.com/symfony/symfony/pull/10908

    Old solution

    Thanks to Crozin who pointed me in the right direction that helped to solve my problem. I will put additional information here that I hope will help someone in the future to save some time.

    The issue is also described in the following topics:

    • How do I configure Apache2 to allow multiple simultaneous connections from same IP address?
    • Simultaneous Requests to PHP Script

    The problem is that PHP by default is using file-based session handling. In other words, session data is stored in the specific file in the server's filesystem. And in order to protect this file from accidental simultaneous writing, file locking mechanism is used. This is a classic locking problem in computer science. The first request to the PHP will gain a lock on the session file and all other requests will have to wait for this lock to be released. And if you have a long-lasting requests in multi-request environment (like with simultaneous AJAX requests or multiple frames on a page) it will become apparent.

    The problem can be solved by either calling session_write_close() prematurelly, before script is finished, but after all session manipulations are done or by switching to another session storage mechanism, like database session storage.

    I think, that in Symfony 2 the best course of action is to store session with the PDO handler (in a database of your choice). Here's the official tutorial of how it can be set up:

    How to Use PdoSessionHandler to Store Sessions in the Database.

    HINT: If you are using Doctrine migrations, then you can create a new migration class and add SQL required to create table for session storage to it.

    With this approach you will have a better non-blocking session storage mechanism and your application will be able to scale horizontally.

提交回复
热议问题