Лучший способ сделать недействительными несколько ключей memcache, используя стандартные библиотеки php? - PullRequest
6 голосов
/ 03 июня 2011

У меня есть база данных с файлами, которые можно искать, просматривать и иметь несколько копий на нескольких серверах.

Я кеширую результаты поиска, просматриваю страницы и расположения серверов (URL).Скажем, я удаляю файл, что является хорошим способом сделать все запросы недействительными, просмотреть данные и URL-адреса этого файла?Или, если файловый сервер выходит из строя, и мне нужно аннулировать все URL, указывающие на этот сервер?

По сути, я ищу что-то похожее на memcache-tags , но со стандартным memcache иphp компоненты.(Без необходимости что-либо менять на самом веб-сервере).Мне нужно какое-то отношение между многими (один сервер имеет много файлов, а один файл имеет несколько серверов) между ключами, но, похоже, не могу найти хороший способ сделать это.В некоторых ситуациях устаревший кеш является приемлемым (незначительные обновления и т. Д.), Но в некоторых случаях это не так (обычно удаление и отключение сервера), когда мне нужно сделать недействительными все элементы кеша, содержащие ссылки на него.Посмотрели:

Пространства имен :

$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-адреса этого сервера, должныбыть признан недействительным (например, потребуется большое количество небольших элементов кэша, что, в свою очередь, требует большого количества запросов к кэшу) - исключает любую вероятность кэширования полных объектов и наборов результатовРеализация тега :
    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);
                }
            }
        }
    }
    
    • Отсутствует контроль над тем, какие ключи признаны недействительными, когда из-за внутреннего сброса ключа memcache можно удалить ключ тега, что, в свою очередь, делает недействительным большое количествофактические действительные ключи(который все еще существует)
    • Проблемы с параллелизмом записи

    Двухэтапная система кэширования :

    // 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 и т. Д. Для медленного кэша
    • Проблемы с параллелизмом записи

Ответы [ 3 ]

0 голосов
/ 04 июня 2011

У меня нет опыта работы с memcached, но я понимаю, что IO там дешевы.

Я бы пошел с вашей реализацией тега, удостоверился, что список тегов используется часто, и надеюсь, что внутренняя логика mmcd 'будет думать, что это что-то слишком занятое, чтобы быть отброшенным:)

0 голосов
/ 04 июня 2011

Прочитав комментарий здесь , который объясняет логику удаления существующих ключей, я считаю, что теги могут быть надежно реализованы с помощью подхода с флагами версий, упомянутого в: Шаблоны разработки PHP memcache

Я уже однажды реализовал эту логику, но отбросил ее как ненадежную из-за удаления элементов memcache до истечения срока действия.Вы можете найти мою первоначальную реализацию здесь .Однако я считаю, что это надежный шаблон тегов, потому что:

  • При извлечении объекта из кэша объект перемещается поверх стека LRU
  • Все теги / флаги извлекаются правильнопосле объекта кеша
  • Если флаг был удален, любой элемент, содержащий этот флаг, был бы удален непосредственно перед
  • Увеличение флага возвращает новое значение в той же операции, избегая параллелизма записи.Если второй поток увеличивает этот же флаг до того, как будет записан объект кэша, он по определению уже недействителен

Пожалуйста, исправьте меня, если я ошибаюсь!: -)

0 голосов
/ 03 июня 2011

См. Организация ключей memcache

Если вы не можете "создавать" ключевые ключи ", разумного способа сделать это не существует.Под этим я подразумеваю что-то вроде «user4231-is_valid».Вы можете проверить это для всего, что использует данные этого пользователя.В противном случае, если вы не отслеживаете все, что ссылается на ваш файл, вы не можете сделать их недействительными.Если вы это сделаете, вам все равно придется повторить все возможности, чтобы успешно удалить.

Документируйте свои зависимости, ограничивайте свои зависимости, отслеживайте свои зависимости в своем коде для операций удаления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...