Jump to content

CacheRedis - fast memory caching


BitPoet
 Share

Recommended Posts

Here's a small new module that started as a spinoff of a memcache proof-of-concept. Cache your strings and partials in-memory using Redis as a backend.

CacheRedis

All you need is a running Redis database. The module supports connection through regular TCP, over TLS and via unix domain sockets. Host and port are configurable, and authentication is supported too. Here's a screenshot of the module configuration options:

CacheRedisSettings.thumb.png.b7055071e956b4ed16fff2146be1c6da.png

I'll not go into too many details about the usage, you can see everything explained in the README on GitHub, and just highlight the most important points.

When the module is active, you'll have a wired $redis variable, which means you can reach the module as $redis, wire("redis") or within Wire classes / modules as $this->redis.

CacheRedis is strongly influenced by WireCache, and its usage is (hopefully) straight forward.

// Store an entry in the cache under the given key name with the given value:
$redis->store("cached_value_number_one", $expire, $value);

// Retrieve a value from the cache
$value = $redis->fetch($key);

// Delete a cache entry
$redis->delete("my_other_cached_value");

// Clear the whole cache
$redis->flush();

// Retrieve a value from the cache, and if not found, create it through the given function
// and store it with a lifetime of 5 minutes (300 seconds)
$value = $redis->fetch($key, 300, function() use($page) {
	return "Page last changed on " . strftime('%m/%d/%Y %H:%M', $page->modified | $page->created);
});

// Render a file using wireRenderFile and store it in the cache.
// We'll pass a selector as the expiry value so this cache gets
// emptied every time a page matching the selector is saved.
$news = $redis->renderFile("partials/news.php", 'template=blog-post', ["page" => $page]);

The module is still very crude work in progress, but I hope some of you feel daring, try it out and let me know in case anything breaks.

Have fun!

  • Like 16
  • Thanks 4
Link to comment
Share on other sites

  • 9 months later...
On 12/15/2020 at 4:06 PM, netcarver said:

This looks great. Are we able to get/save/flush using any kind of namespacing?  Wirecache has getFor() / saveFor() / deleteFor() etc, which are very useful for classifying cache entries and doing targeted flushing.

Built into the dev branch at https://github.com/BitPoet/CacheRedis/tree/dev  are storeFor() / fetchFor() / deleteFor().

I'm not a thousand percent sure how reliable this is in large environments, since this uses SCAN and UNLINK to iterate with a wildcard over all keys in the namespace and deletes them asynchronously. You can pass TRUE as the third parameter to deleteFor to force synchronous deletion, but SCAN may at (rare) times return incomplete results anyway.

Needs at least redis 2.8.0.

  • Like 1
Link to comment
Share on other sites

@BitPoet Fantastic, thank you.

I guess you mean the flushing of a namespace regarding the SCAN with DEL/UNLINK operations? Hmm, I wonder if we could keep either a hash or set for all the keys within a namespace, then flushing the namespace could become something like a lua EVAL that iterates the hash/set doing the deletes and then empties the hash/set as one atomic operation without a load of network traffic. Will have a think about it, it's been years since I did any Lua scripting in Redis.

  • Like 1
Link to comment
Share on other sites

Even then, for large cardinalities, the Lua script idea (with or without a hash/set holding the key references) would be blocking on other processes using Redis. So this might not be ideal either. At least with your current implementation it's non-blocking as there are separate calls to redis. However, that needs to be weighed against the network overhead.

Link to comment
Share on other sites

@BitPoet I've cloned the module and pushed an experimental script for deleteFor() here.  It uses a Lua script that's evaluated in the Redis server.

My rough testing using 100k namespaced keys shows this to be much faster than iterating over the scan results in PHP and the PHP cpu + network load is also much lower.  However, that is at the cost of blocking the Redis server whilst the delete is taking place.

I've not massaged this into a pull request yet, as I'd like to get your feedback on it.

  • Like 1
Link to comment
Share on other sites

6 hours ago, netcarver said:

I've cloned the module and pushed an experimental script for deleteFor() here.  It uses a Lua script that's evaluated in the Redis server.

My rough testing using 100k namespaced keys shows this to be much faster than iterating over the scan results in PHP and the PHP cpu + network load is also much lower.  However, that is at the cost of blocking the Redis server whilst the delete is taking place.

I've not massaged this into a pull request yet, as I'd like to get your feedback on it.

Thanks, this looks good at first glance. I'm going to give it a spin as soon as I find the time. I'll probably want to let the user choose between client and server side tradeoffs depending on the use case, which also means deciding which is the reasonable default.

  • Like 1
Link to comment
Share on other sites

  • 1 year later...
  • 1 month later...
On 5/19/2022 at 9:22 AM, Ivan Gretsky said:

Good day, @BitPoet!

Are you planning to merge dev branch to have a new stable?

Hi @Ivan Gretsky, I will at one point for sure, but that will be late in the year. I‘m currently hiking across the U.S. and won‘t get my hands on a computer until October.

  • Like 3
Link to comment
Share on other sites

As I've never used redis I had to do some research what it is and what it does... Here's a good video that gives you a quick overview: 

Would be interesting to hear why/where/when one could use this module and what benefit one would get vs. using WireCache ? 

  • Like 1
Link to comment
Share on other sites

@bernhard I use redis alongside PW on some client sites (using php-resque for background jobs like email composition and send) - though I do not use this particular module in production yet.  I think bitpoet is aiming for an API-compatible drop-in for wirecache that leverages the lower latency of redis' in-memory accesses.

  • Like 3
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...