Symfony 2 blocked by concurrency

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

To demonstrate the problem, I created two routes named /time

and /sleep

. The controls are pretty simple:

timeAction():
    time();

sleepAction()
    sleep(30);

      

When I request a route /time

in my browser - it responds instantly with the current timestamp. However, when I first ask for a route /sleep

and then a route /time

- it just hangs there until sleep()

it's complete. Only then does the controller /time

respond with a timestamp. In other words, one request blocks all others. I didn't even notice it at first, but when you have queries with a long execution plan, it becomes obvious.

What could be causing this?

I will still be doing some additional tests myself to dig deeper into the situation. I will try to update the question in more detail.

+3


source to share


2 answers


Update

It looks like it PdoSessionHandler

now uses its own locking mechanism which 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 loop. You can do this by calling $session->close()

or session_write_close()

.

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

# 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 for pointing me in the right direction which helped solve my problem. I will provide some additional information here that will hopefully help someone save time in the future.



The problem is also described in the following sections:

The problem is that PHP uses file based session processing by default. In other words, session data is stored in a specific file on the server's file system. And to protect this file from accidental concurrent writing, a file locking mechanism is used. This is a classic blocking problem in computer science. The first request to PHP will acquire the session file lock and all other requests will have to wait until that lock is released. And if you have long running requests in a multi-request environment (like concurrent AJAX requests or multiple frames per page), this will become obvious.

The problem can be resolved by calling it session_write_close()

prematurely, before the script finishes, but after all session manipulations have finished, or by switching to a different session storage engine, such as database session storage.

I think in Symfony 2 the best way is to store the session with a PDO handler (in a database of your choice). Here's the official guide to setting it up:

How to use PdoSessionHandler to store sessions in a database .

ADVICE. If you are using Doctrine migrations, you can create a new migration class and add the SQL needed to create the table to hold the session.

With this approach, you have a better non-blocking session locking mechanism, and your application can scale horizontally.

+5


source


While I think you found the answer in the comment above, it's worth noting that there is a reason why you might receive one request to the server blocking another. Both web servers and browsers actively limit the number of open connections to a single host. The HTTP standard actually says that any client should not have more than two (!!!) active connections at the same time: http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4 . Modern browsers usually allow more, see Maximum concurrent HTTP connections per browser? but they still limit you.



To work around this issue, people often configure multiple hostnames for the same server (for example, using CNAMES), so the limitation does not apply.

+1


source







All Articles