⬆️ ⬇️

Memcached and tags. Implementation for the Kohana framework

Greetings to all.



For quite some time now we have been developing a project on Kohana and the need for effective data caching has arisen. Not that the issue of performance is very acute at the moment, but I would like to prepare in advance, and not to write a caching system at night after a wave of visitors. Yes, and attendance is constantly growing, and at some moments there are bursts up to 3 times compared with the usual day.



Actually, there were no special questions in the choice of a caching system - memcached, which everyone knows, immediately comes to mind.

')

If you watched memcached at least a little, you should have noted that, by and large, it only supports 2 operations: getting the value, writing the value. There is no way to pull out all the keys for a particular feature or pattern. This was done consciously, in order to make it as simple as possible, and therefore as fast as possible.



So, imagine a situation that we cache the blog post data under the post_ keys. At some point we need to reset all entries with posts, while not clearing the cache completely (there may be stored other data, the values ​​of which are still relevant). The situation is hopeless. We do not know the list of keys of posts, there is no way to get them, it is also impossible to reset the keys by the pattern. What to do?





I will not go into a theoretical description of the ways how memcached can be used to implement a tagging system, and there are many articles about this. For example, in the blog of Andrey Smirnov: www.smira.ru/2008/10/29/web-caching-memcached-5 . This is the method I used to create a caching system on my site.



So that you understand what this is about, we are going to store our cache data in an array of the form:



array (

'tags' => array (

'tag1' => <......>,

'tag2' => <......>

),

'data' => <.... ...>,

);



* This source code was highlighted with Source Code Highlighter .


Also, every label we have is stored in memcached with the key tag_ <tag name>. In meaning, we store a certain number. In our case, for reliability, we store in it the time to create / update the label with an accuracy of milliseconds.

When adding a new item to the cache, we read this number and store it in the array described above. When reading the key value, we check whether the value of the label has changed relative to the values ​​stored in the key value. In case they differ, we consider that the key is reset. Thus, resetting the keys by tag is made by changing the value of the tag key.



For example:

// post_1:

array (

'tags' => array (

'posts' => 1

),

'data' => 'post content'

)

// tag_posts:

array (

'data' => 1

)




* This source code was highlighted with Source Code Highlighter .




When reading the key post_1, the algorithm also reads the value of tag_posts and compares it with the value stored in the ['tags'] ['posts'] key of post_1. If they are equal, everything is in order, post_1 is valid. If the values ​​are different, we assume that post_1 is not valid and return NULL. Thus, we can mark keys that are not valid simply by changing the values ​​that are stored in the "tags".



If I explained it is not very clear - it does not matter. From above, I gave a link to an article where the method I used is described in more detail.



Kohana's memcached driver does not support memcached tags by default. More precisely, a couple of versions ago it was implemented, but it worked so that in the end the authors decided to abandon the tags in general. In short - there was created one key in memcached, which stored an array of the form <key name> => <list of tags>. You can imagine what size this array had on a rather large site.



You can download my driver version here: github.com/Kolger/kohana-memcacheimp

This is the usual Kohana module. Download the code, create the memcachedimp directory in the application / modules folder of your project. Do not forget to connect the module in config.php:



$config[ 'modules' ] = array

(

//.....

MODPATH. 'memcacheimp' , // Memcacheimp driver

//.....

);

// , cache.php:



$config[ 'default' ] = array

(

'driver' => 'memcacheimp' ,

'lifetime' => 3600,

'requests' => 1000,

);




* This source code was highlighted with Source Code Highlighter .




Now, the Cache class will work with the new driver.

The use is no different from the method described in the documentation: docs.kohanaphp.com/libraries/cache

$cache = new Cache();

// :

$cache-> set ( 'post_1' , 'post content' , array( 'posts' ));

$cache-> set ( 'post_2' , 'post content' , array( 'posts' ));

//

$ value = $cache-> get ( 'post_1' );

// $value == post content

// "" . , , tag_posts, post_1 post_2 -

$cache->delete_tag( 'posts' );

// post_1

$ value = $cache-> get ( 'post_1' );

// $value === NULL, . post_1 , , .. .



* This source code was highlighted with Source Code Highlighter .




I think that by changing my class a little, you can use it not only in Kokhane, but also in any other PHP project. If you have any ideas how to improve or optimize the class - welcome to the github github.com/Kolger/kohana-memcacheimp :)



What should be improved:

- Getting tags in the get method with getMulti, so as not to multiply requests to memcached.

- Delete keys in case the label has changed.

Source: https://habr.com/ru/post/73423/



All Articles