2010-06-22 5 views
18

Как проверить PHP, если значение хранится в Memcache без его получения? Мне не нравится получать его, потому что значения, которые я установил, имеют размер 1 МБ, и после того, как я его извлечу, я не использую его, поэтому я трачу ресурсы. Я использую это в скрипте, который проверяет, кэшируются ли определенные ключи в memcache, а если нет, он читает их из медленного источника данных и устанавливает их в memcache.Проверьте, существует ли ключ в Memcache

Редактировать: Что делать, если я использую Memcached::append для добавления NULL к ключу, который я проверяю? Возвращает TRUE по успеху или FALSE при сбое. Memcached::getResultCode вернет Memcached::RES_NOTSTORED, если ключ не существует. Таким образом, я проверяю, существует ли ключ, и он должен правильно поставить ключ поверх списка LRU?

спасибо.

ответ

3

В основном, что вы хотите сделать, это заполнить memcached вашими данными, не так ли?

Дело в том, что вопрос о том, есть ли ключ с удаленным извлечением значения, не очень полезен. См. Этот случайный сценарий:

Вы спрашиваете, существует ли ключ и что он делает. Как только вы спросите, данные ключа выведены из кеша. В то время как ваш ответ возвращается, говоря, что существует дата, реальность такова, что данных нет. Таким образом, вы потеряли время, спрашивая, потому что ответ отличается от реальности.

Я предполагаю, что вы хотите узнать, существует ли ключ, а затем, если это не так, заполните его вашими данными. Почему вы не заполняете непосредственно все данные? Кстати, считали ли вы, что, когда вы заполняете memcached данными, вы можете вытеснять ключи, которые вы только что вставили ранее?

+0

Да, но сначала я должен быть уверен, что он еще не установлен. Потому что, если он уже установлен, я буду тратить время на чтение данных из медленного источника. Если я использую get() для проверки, тогда я буду тратить сеть IO, потому что значение 1MB - это размер. – Matic

+0

@Matic «проблема» в том, что memcached не был разработан с учетом сетевого ввода-вывода, поэтому я думаю, именно поэтому такая функциональность была опущена. Если сетевой IO является проблемой, вам лучше использовать базу данных kv. Я понимаю, что иногда вам просто не требуется дополнительное выделение, даже если сетевое IO не является проблемой, но это невозможно с memcached. У Redis есть такая возможность. – themihai

6

Я не уверен, если это какой-либо помощи, но вы можете использовать

Memcache::add ( string $key , mixed $var) 

Она возвращает ложь, если ключ уже существует.

В случае истинной возвращается вы можете использовать

Memcache::delete ( string $key) 

удалить ключ вы просто установить. Таким образом вам не нужно будет получать данные.

+0

И если она возвращает истину, не забудьте сделать Memcached :: удалить после –

+0

@Serty Оан: оба написали то же самое время :) – Thariama

+0

великие умы мыслят одинаково;) –

0

Это не имеет смысла с точки зрения Memcached. Если вы хотите избежать медленного источника данных (по плану, я полагаю?), Сохраните данные в более быстрый, но все же стабильный источник данных (например, файл) в запланированном задании. Когда вам нужны данные, попробуйте сначала прочитать Memcached, и если это не удается прочитать файл и сохранить его в Memcached.

Memcached не может дать вам хороший ответ, так как pakore уже ответил. Архитектура не должна быть стабильным источником данных.

3

Я решил это, используя Memcached :: append. Я пытаюсь добавить значение NULL, и если он возвращает TRUE, это означает, что ключ существует. Если он возвращает FALSE, значит, ключ не существует. Если ключ существует, он также будет помещен поверх списка LRU.

+1

Вам необходимо убедиться, что для параметра «Memcached :: OPT_COMPRESSION» установлено значение false, иначе операция будет всегда терпеть неудачу. Кроме того, может быть лучше добавить пустую строку * '' * вместо * NULL * .. –

+0

Для тех, кто использует 'Memcache', а не' Memcached': 'append' метод доступен только в последнем. – TheFrost

2

Мне не нравится предложение добавить/удалить, потому что оно вставляет неверные данные, которые могут зависеть от того, насколько ваше приложение может быть действительным. Если ваше приложение делает это предположение, это может вызвать тонкую ошибку, которая возникает каждый так часто из-за состояния гонки, которое оно вводит.

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

Если набор ключей достаточно мал, вы можете сохранить это в memcached и использовать, чтобы определить, следует ли снова извлекать данные из источника. Однако, если его значение больше или больше, значение этого метода хуже, чем просто получение всего значения из memcached.

Вы могли бы решить новую проблему, используя индекс для разделения ключей на меньшие наборы (конечно хороший способ шарда этих данных, так что каждый ковш определенного размера легче сказать, чем сделать.)

Реализация будет состоять из использования memcached append или prepend для поддержки вашего списка ключей, привязанных к некоторому главному ключу или мастер-ключу, который указывает на набор суб-клавиш, которые указывают на сами клавиши :)

В любом случае, вы делаете приложение все более и более сложное, поэтому я бы рекомендовал сделать это, если действительно есть узкое место (например, было бы, если существование ключей необходимо проверять часто по сети), или если usabil (задержка).

В моем случае я не буду этого делать, потому что я собираюсь получить доступ к memcached через localhost и использовать его как расширение расширения для моего приложения для кэширования ресурсов, которые требуют более нескольких секунд для нормальной работы.

0

Самый простой способ - получить заданный ключ и привести его к логическому значению.

(bool) Memcache::get(string $key) 
+1

Как сказал OP, он не хочет «получать» из-за большого объема данных. –

1

Просто невозможно, невозможно проверить только ключ существует или нет. Лучше создать отдельный ключ с истинными/ложными значениями, чтобы проверить наличие ключей

0

(немного поздно к обсуждению, но) на самом деле вы можете получить доступ ко всем ключи/значения, хранящиеся в кэше, за:

$allSlabs = $memcache->getExtendedStats('slabs'); 
$items = $memcache->getExtendedStats('items'); 

foreach ($allSlabs as $server => $slabs) 
    foreach ($slabs as $slabId => $slabMeta) 
     foreach ($memcache->getExtendedStats('cachedump', (int) $slabId) as $entries) 
      if (!empty($entries)) 
       foreach ($entries as $key => $entry) 
+0

Это сработало бы, но сродни тому, чтобы использовать кувалду, чтобы взломать грецкий орех, накладные расходы при этом каждый раз, чтобы проверить, существует ли ключ, было бы менее обременительно просто получить данные и проверить код результата. –

+0

@SteveChilds - это становится полезным, если вы не знаете точное значение ключа. Например, если вы сохраняете определенные экземпляры объектов в вашем memcache под похожими ключами (object_type-object_id # object_options), и вы хотите перезагрузить все экземпляры объекта object_type-object_id. На самом деле все зависит от настройки и кодовой базы. – eithed

+0

А, ок - да в вашем случае использования это имеет смысл, но в контексте ОП его избыток. –

4

Интересно, почему у Memcached нет специального метода для этого. Вот что я придумал после некоторых соображений:

function has($key) 
{ 
    $m->get($key) 

    return \Memcached::RES_NOTFOUND !== $m->getResultCode(); 
} 
1

memcached теперь имеет команду cas. Вы можете использовать его с КАСОМ уникальным в 0, чтобы получить EXISTS или NOT_FOUND ответов:

$ telnet localhost 11211 
Trying 127.0.0.1... 
Connected to localhost. 
Escape character is '^]'. 
set hello 0 0 5 
12345 
STORED 
gets hello 
VALUE hello 0 5 6743 
12345 
END 
cas hello 0 0 0 0 

EXISTS 
cas foo 0 0 0 0 

NOT_FOUND 

В приведенной выше стенограмме, я первым использовать команду набора для установки ключа привета со значением 12345. Затем получает его обратно, который также возвратил cas уникальный 6743. Затем я пытаюсь использовать команду cas, чтобы заменить значение ничем, но так как единственный случай, который я использовал, - 0, я получил ошибку EXISTS.

Наконец, я пытаюсь использовать cas для установки ключа foo, который не существует, и возвращает ошибку NOT_FOUND.

Поскольку memcached использует глобальное значение incrementing для уникального cas, использование 0 безопасно, что оно недействительно для элемента, который вы пытаетесь установить, и вы вернете ошибку EXISTS, если она существует.

Извините, не знакомы с клиентом memcache php, чтобы поместить его в php-код.

0

Мне нужен был надежный тест, чтобы знать, как использовать memcache. Установите или замените memcache.

Это то, с чем я закончил.

Другим вариантом является создание сетевого сокета для запроса memcache, но в конце концов он будет делать то же самое, и это соединение уже существует, что избавит меня от накладных расходов на создание и поддержание другого соединения, как в Joel Chen's ответ.

$key = 'test'; 
$value = 'foobarbaz'; 
/** 
* Intricate dance to test if key exists. 
* If it doesn't exist flags will remain a boolean and we need to use the method set. 
* If it does exist it'll be set to integer indicating the compression and what not, then we need to use replace. 
*/ 
$storageFlag = (is_null($value) || is_bool($value) || is_int($value) || is_float($value) ? false : MEMCACHE_COMPRESSED); 
$flags = false; 
$memcache->get($key, $flags); 
if(false === $flags) { 
    $memcache->set($key, $value, storageFlag , $minutes); 
} 
else { 
    $memcache->replace($key, $value, storageFlag, $minutes); 
} 

Теперь, если у вас есть «большие данные», решение довольно простое. Используйте второй ключ в cojoin, который содержит что-то простое, например, целое число для проверки. Всегда используйте их вместе, и у вас нет проблем.

$key = 'test'; 
$value = 'foobarbaz'; 

$storageFlag = (is_null($value) || is_bool($value) || is_int($value) || is_float($value) ? false : MEMCACHE_COMPRESSED); 
$flags = false; 
$exist_key = $key.'_exists'; 

$memcache->get($exist_key, $flags); 
if(false === $flags) { 
    $memcache->set($key, $value, storageFlag , $minutes); 
    $memcache->set($exist_key, 42, false , $minutes); 
} 
else { 
    $memcache->replace($key, $value, storageFlag, $minutes); 
    $memcache->replace($exist_key, 42, false , $minutes); 
} 
Смежные вопросы