This article mainly introduces how to solve the problem of simulating namespace and cache invalidation when using Memcache in PHP. the cache invalidation mentioned here is mainly for cases where cache invalidation cannot be obtained in high concurrency scenarios, for more information, see
Cache namespace
Memcache itself does not support namespaces, but we can use the mechanism of memcache itself to simulate namespaces. For example, if you want to clear a group of data, you need to use the namespace. let's take a look at this example and the description is written in the comment:
Class Action {public function index () {global $ mc_wr; // Obtain the namespace $ ns_key = $ mc_wr-> get ("foo_namespace_key"); // if the namespace does not exist, set an if ($ ns_key = false) $ mc_wr-> set ("foo_namespace_key", time (); $ otherParms = 'select * from user LIMIT 1 '; // generate a unique key $ my_key = "foo _" based on the namespace _". $ ns_key. '_'. md5 ($ otherParms); // get the cache under the current key $ val = $ mc_wr-> get ($ my_key); if (! $ Val) {$ value = 'hangzhou _'. time (); // if the cache does not exist, set 600 seconds for the cache. 0 indicates the random expiration time, and add a random number of seconds for the expiration time, prevents all caches from being invalidated at the same time $ mc_wr-> set ($ my_key, $ value, 600, 0);} echo $ val;} public function clear_ns () {global $ mc_wr; // update the namespace value to invalidate all the values of the current namespace. memcache's own cache invalidation mechanism. when the cache is not accessed, the LRU failure mechanism $ mc_wr-> set ('foo _ namespace_key ', time ());}}
Memcache cache failure
In the case of high concurrency, when the cache becomes invalid, a large number of concurrency cannot get the cache at the same time, and the database is accessed and the cache is reset instantly, which may bring potential overload risks to the system.
Solution:
Method 1
Add a mutex key before load the database, and load the database after the mutex key is added successfully. if the add operation fails, sleep the database and read the original cache data again. To prevent deadlocks, you also need to set the expiration time for the mutex key. The pseudocode is as follows:
if (memcache.get(key) == null) { // 3 min timeout to avoid mutex holder crash if (memcache.add(key_mutex, 3 * 60 * 1000) == true) { value = db.get(key); memcache.set(key, value); memcache.delete(key_mutex); } else { sleep(50); retry(); }}
Method 2
Set one timeout value (timeout1) inside the value, and the timeout1 is better than the actual memcache.
Timeout (timeout2) is small. When timeout1 is read from the cache and it is found that it has expired, extend timeout1 and reset it to the cache. However
Then load the data from the database and set it to the cache. The pseudocode is as follows:
v = memcache.get(key);if (v == null) { if (memcache.add(key_mutex, 3 * 60 * 1000) == true) { value = db.get(key); memcache.set(key, value); memcache.delete(key_mutex); } else { sleep(50); retry(); }} else { if (v.timeout <= now()) { if (memcache.add(key_mutex, 3 * 60 * 1000) == true) { // extend the timeout for other threads v.timeout += 3 * 60 * 1000; memcache.set(key, v, KEY_TIMEOUT * 2); // load the latest value from db v = db.get(key); v.timeout = KEY_TIMEOUT; memcache.set(key, value, KEY_TIMEOUT * 2); memcache.delete(key_mutex); } else { sleep(50); retry(); } }}