PHP Redis Session Locking Internals
Asked Answered
D

2

5

How does phpredis session locking work internally? Does it store a value internally and keep checking it? If I have a high redis.session.lock_retries will that put load on the server if it takes 10 seconds to get a lock and had to try thousands of times?

Below are the configuration parameters.

; Should the locking be enabled? Defaults to: 0.
redis.session.locking_enabled = 1
; How long should the lock live (in seconds)? Defaults to: value of max_execution_time.
redis.session.lock_expire = 60
; How long to wait between attempts to acquire lock, in microseconds (µs)?. Defaults to: 2000
redis.session.lock_wait_time = 50000
; Maximum number of times to retry (-1 means infinite). Defaults to: 10
redis.session.lock_retries = 10
Dissonant answered 20/12, 2019 at 14:6 Comment(1)
Defaults are a factor 100 off (redis.session.lock_retries=100, redis.session.lock_wait_time=20000), causing the total lock wait time to be not 20 ms but 2000 ms (=2 sec)Lublin
F
5

The commit that added this is here.

It seems to imply that it uses the locking recipe described in the Redis docs.

Overall this recipe relies on atomically trying to set a key if it doesn't exist (this is the lock) and failing if it already exists. This means that every attempt is a command to the Redis server which on its own is very fast but if your Redis server is hosted remotely then there is the overhead of a network round-trip

Fleshpots answered 20/12, 2019 at 14:30 Comment(2)
Ok understood. In my case the locking won't happen often but if it does it could take 1-10 seconds. What would you recommend for the parameters I described in question? Also if it fails to get a lock after redis.session.lock_retries does the program continue execution and does it lose any data or access to session (set or get)Dissonant
I would think a 2 second wait time should be pretty good. If Redis is on the same server as the webserver (or if you're running on e.g. AWS and using ElasticCache on the same VPC) then you could probably decrease it. I wouldn't recommend increasing it unless the round-trip is very high (in which case using Redis for caching might end up being counter-productive anyway)Fleshpots
S
4

Looks like it's a hot loop:

static int lock_acquire(RedisSock *redis_sock, redis_session_lock_status *lock_status)
{
  ...
  for (i = 0; retries == -1 || i <= retries; i++) {
      set_lock_key_result = set_session_lock_key(redis_sock, cmd, cmd_len);
      ...
      /* Sleep unless we're done making attempts */
      if (retries == -1 || i < retries) {
        usleep(lock_wait_time);
      }

There is no exponential back-off or other mitigation for long-blocking requests. If you have a high spread (eg sometimes instant lock acquisition, sometimes 1s, sometimes 10s, etc.) then I'd suggest setting the lock attempt length quite low, then writing your own hot loop that does back-off more in line with your expected wait time. If you have a pretty stable expected wait time (eg always about 10s) then just set the wait time quite high.

Soppy answered 20/12, 2019 at 14:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.