使用标准php库使许多Memcache键无效的最佳方法? [英] Best way to invalidate a number of memcache keys using standard php libraries?
问题描述
我有一个包含文件的数据库,该文件可以搜索,浏览并在多个服务器上具有多个副本.
I have a database with files which can be searched, browsed and have multiple copies on multiple servers.
我缓存搜索,浏览页面和服务器位置(URL).假设我删除了一个文件,那么使该文件的所有搜索,浏览数据和网址的一种好方法是什么?还是文件服务器出现故障,并且我需要使指向该服务器的所有URL无效?
I cache searches, browse pages and server locations (urls). Say I delete a file, what's a good way to invalidate all searches, browse data and urls for this file? Or if a file server goes down, and I need to invalidate all urls pointing to this server?
基本上,我正在寻找与 memcache-tags 类似的东西,但是带有标准的memcache和php组件. (无需更改Web服务器本身的任何内容).在密钥之间,我需要某种多对多的关系(一个服务器有许多文件,一个文件有多个服务器),但是似乎无法找出实现此目的的好方法.在某些情况下,过时的缓存是可以接受的(较小的更新等),但是在某些情况下(通常是删除并关闭服务器),我需要使所有包含对它的引用的缓存项无效.
Essentially I'm looking for something similar to memcache-tags, but with standard memcache and php components. (Without having to change anything on the web server itself). I need some sort of many to many relation (one server has many files, and one file has multiple servers) in between keys, but can't seem to figure out a good way to accomplish this. In some situations stale cache is acceptable (minor updates etc.), but in some cases it's not (typically delete, and server down) where I need to invalidate all cache items containing references to it.
我研究过的一些方法:
命名空间 :>
$ns_key = $memcache->get("foo_namespace_key");
// if not set, initialize it
if($ns_key===false) $memcache->set("foo_namespace_key", rand(1, 10000));
// cleverly use the ns_key
$my_key = "foo_".$ns_key."_12345";
$my_val = $memcache->get($my_key);
//To clear the namespace do:
$memcache->increment("foo_namespace_key");
$files = array('file1','file2');
// Cache all files as single entries
foreach ($files as $file) {
$memcache->set($file.'_key');
}
$search = array('file1_key','file2_key');
// Retrieve all items found by search (typically cached as file ids)
foreach ($search as $item) {
$memcache->get($item);
}
- 如果文件服务器已关闭,则所有问题都将失效,并且所有包含该服务器URL的密钥都应无效(例如,将需要大量的小型缓存项,这反过来又需要针对缓存的大量请求)-中断任何缓存完整对象和结果集的机会
标记实现 :
Tag implemenation:
class KeyEnabled_Memcached extends Zend_Cache_Backend_Memcached
{
private function getTagListId()
{
return "MyTagArrayCacheKey";
}
private function getTags()
{
if(!$tags = $this->_memcache->get($this->getTagListId()))
{
$tags = array();
}
return $tags;
}
private function saveTags($id, $tags)
{
// First get the tags
$siteTags = $this->getTags();
foreach($tags as $tag)
{
$siteTags[$tag][] = $id;
}
$this->_memcache->set($this->getTagListId(), $siteTags);
}
private function getItemsByTag($tag)
{
$siteTags = $this->_memcache->get($this->getTagListId());
return isset($siteTags[$tag]) ? $siteTags[$tag] : false;
}
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean True if no problem
*/
public function save($data, $id, $tags = array(), $specificLifetime = false)
{
$lifetime = $this->getLifetime($specificLifetime);
if ($this->_options['compression']) {
$flag = MEMCACHE_COMPRESSED;
} else {
$flag = 0;
}
$result = $this->_memcache->set($id, array($data, time()), $flag, $lifetime);
if (count($tags) > 0) {
$this->saveTags($id, $tags);
}
return $result;
}
/**
* Clean some cache records
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => remove too old cache entries ($tags is not used)
* 'matchingTag' => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* 'notMatchingTag' => remove cache entries not matching one of the given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @return boolean True if no problem
*/
public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
{
if ($mode==Zend_Cache::CLEANING_MODE_ALL) {
return $this->_memcache->flush();
}
if ($mode==Zend_Cache::CLEANING_MODE_OLD) {
$this->_log("Zend_Cache_Backend_Memcached::clean() : CLEANING_MODE_OLD is unsupported by the Memcached backend");
}
if ($mode==Zend_Cache::CLEANING_MODE_MATCHING_TAG) {
$siteTags = $newTags = $this->getTags();
if(count($siteTags))
{
foreach($tags as $tag)
{
if(isset($siteTags[$tag]))
{
foreach($siteTags[$tag] as $item)
{
// We call delete directly here because the ID in the cache is already specific for this site
$this->_memcache->delete($item);
}
unset($newTags[$tag]);
}
}
$this->_memcache->set($this->getTagListId(),$newTags);
}
}
if ($mode==Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG) {
$siteTags = $newTags = $this->getTags();
if(count($siteTags))
{
foreach($siteTags as $siteTag => $items)
{
if(array_search($siteTag,$tags) === false)
{
foreach($items as $item)
{
$this->_memcache->delete($item);
}
unset($newTags[$siteTag]);
}
}
$this->_memcache->set($this->getTagListId(),$newTags);
}
}
}
}
- 由于内部内存缓存密钥丢失,无法控制哪些密钥无效,何时可以丢弃标签密钥,从而使大量实际有效密钥(仍将存在)失效
- 存在写并发问题
Two-step cache system:
// Having one slow, and one fast cache mechanism where the slow cache is reliable storage containing a copy of tag versions
$cache_using_file['tag1'] = 'version1';
$cache_using_memcache['key'] = array('data' = 'abc', 'tags' => array('tag1' => 'version1');
- 使用磁盘/mysql等进行缓慢缓存的潜在瓶颈
- 存在写并发问题
- 在缓存对象检索中,对象被移动到LRU堆栈的顶部
- 在缓存对象之后立即检索所有标签/标志
- 如果驱逐了一个标志,则包含该标志的任何项目都将在此之前被驱逐
- 递增标志将在同一操作中返回新值,从而避免写入并发.如果在写入缓存对象之前,另一个线程正在递增相同的标志,则根据定义,该线程已经无效
推荐答案
注释中出现了此处,其中说明了收回现有密钥的逻辑,我相信可以通过
Having come accross the comment here, which explains the logic of evicting existing keys, I believe tags can be implemented reliable by the version flags approach mentioned in: PHP memcache design patterns
我实际上已经实现了此逻辑一次,但是由于元素在过期之前被内存缓存逐出而将其丢弃为不可靠.您可以在此处找到我的初始实现.但是,我确实相信这是一种可靠的标记模式,因为:
I actually implemented this logic once already, but discarded it as unreliable due to memcache eviction of elements before they expire. You can find my initial implementation here. I do however, believe this is a reliable tags pattern because:
如果我错了,请纠正我! :-)
Please correct me if I'm wrong! :-)
这篇关于使用标准php库使许多Memcache键无效的最佳方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!