cache namespace
Memcache itself does not support namespaces, but we can use memcache's own mechanism to simulate namespaces. For example: if you want to clear a set of data, you need to use a namespace. Let’s look at such an example. The instructions are written in comments:
class Action { public function index() { global $mc_wr; // 获取命名空间 $ns_key = $mc_wr->get("foo_namespace_key"); // 如果命名空间不存在,则设置一个 if($ns_key===false) $mc_wr->set("foo_namespace_key",time()); $otherParms = 'select * from user LIMIT 1'; // 根据命名空间生成唯一的key $my_key = "foo_".$ns_key.'_'.md5($otherParms); // 获取当前key下的缓存 $val = $mc_wr->get($my_key); if (!$val) { $value = 'wangdekang_'.time(); // 缓存不存在则设置缓存 600秒, 0为随机失效时间, 为失效时间添加随机秒数,防止瞬间所有缓存同时失效 $mc_wr->set($my_key,$value,600, 0); } echo $val; } public function clear_ns() { global $mc_wr; // 更新命名空间值,让当前命名空间的所有值失效, memcache自身的缓存失效机制,当缓存不在被访问,会通过LRU失效机制 $mc_wr->set('foo_namespace_key', time()); } }
memcache cache invalidation problem
In a large concurrency situation, when the cache fails, a large number of concurrent users cannot access the cache at the same time. They will access the db and reset the cache at the same time, which may bring potential overload risks to the system.
Solution:
Method 1
Add a mutex key before loading the db. After the mutex key add is successful, load the db. If the add fails, sleep and retry reading the original cache data. In order to prevent deadlock, the mutex key also needs to set an expiration time. The pseudo code 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 a timeout value (timeout1) inside value, timeout1 is longer than the actual memcache
timeout(timeout2) is small. When timeout1 is read from the cache and it is found that it has expired, timeout1 is immediately extended and reset to the cache. Ran
Then load the data from the database and set it in the cache. The pseudo code 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(); } } }