Conversation
|
|
||
| public function get($key) { | ||
| $result = $this->getCache()->get($this->getPrefix() . $key); | ||
| if ($result === false && !$this->getCache()->exists($this->getPrefix() . $key)) { |
There was a problem hiding this comment.
This check is useless. Redis does not support boolean types, so getting a false means it did not exist.
| // TODO: this is slow and would fail with Redis cluster | ||
| $prefix = $this->getPrefix() . $prefix . '*'; | ||
| $keys = $this->getCache()->keys($prefix); | ||
| $deleted = $this->getCache()->del($keys); |
There was a problem hiding this comment.
This will fail for redis cluster and a large number of keys. The solution is to replace this with a lua script and run it on all masters.
| ->exec(); | ||
| return $result !== false; | ||
| } | ||
| $this->getCache()->unwatch(); |
There was a problem hiding this comment.
5 statements here vs 1 now. Ditto for cad.
lib/private/Memcache/Redis.php
Outdated
|
|
||
| return $this->getCache()->eval( | ||
| 'if redis.call("get", KEYS[1]) == ARGV[1] then | ||
| return redis.call("del", KEYS[1]) |
There was a problem hiding this comment.
Using unlink here is a premature optimization that's probably harmful. In fact, unless the values are huge, unlink internally calls del after checking the size, so we just did those checks for no reason...
This removes a lot of acrobatics in the code and does each operation atomically using a lua script. This also reduces several round trips to the server, and the scripts are compiled and cached server-side. Notably, since all operations work only on a single key (except clear, which is broken anyway and shouldn't be used), they will continue to function and be atomic for Redis cluster. Signed-off-by: Varun Patil <[email protected]>
3671f8d to
39e805f
Compare
Signed-off-by: Robin Appelman <[email protected]>
|
Added a unit test to validate the script hashes to make sure we don't forget to update them if we ever change the scripts |
Good point, thanks! |
|
Bump? |
CarlSchwan
left a comment
There was a problem hiding this comment.
This is pretty neat. I didn't knew that redis allowed to run lua script
juliusknorr
left a comment
There was a problem hiding this comment.
Minor comments, otherwise this seems like a nice improvement.
Is there any minimum version requirement for this on the redis side?
Thanks, will fix these tomorrow.
Redis 2.6, released ~10 years ago. |
Signed-off-by: Varun Patil <[email protected]>
|
CI failure unrelated |
juliusknorr
left a comment
There was a problem hiding this comment.
Let's get this in for 28 👍
|
Massive kudos for this patch @pulsejet. We ran into a production instance with incomprehensive file locking issues with a Redis cluster memcache backend. Sporadically unlocked files were still locked inside a single request. Only with this patch we could eliminate the issue. @AndyScherzinger this is not only a performance improvement but fixes Redis cluster inconsistencies. Would this change be ok to backport? |
|
Great! A possible reason I see is that |
|
@ChristophWurst yes, backporting would be fine from my pov 👍 |
|
/backport to stable27 |
|
/backport to stable26 |
|
@ChristophWurst any specific reason why not backporting to 25 also? |
|
Wrongly got the impression 25 is EOL but it's only 24 |
|
I think I'll backport the 26 backport because there are conflicts to resolve |
This removes a lot of acrobatics in the code and does each operation
atomically using a lua script. This also reduces several round trips
to the server, and the scripts are compiled and cached server-side.
Notably, since all operations work only on a single key (except clear,
which is broken anyway and shouldn't be used), they will continue to
function and be atomic for Redis cluster.
EDIT: I did some simple benchmark with a single client process. Looks like locking is approximately 2x faster (probably even better with multiple clients). This is with Redis on the same host, so gains will be better when latency is higher between the servers.
On a side note, using DB for locking is a joke: