Memcached. Как найти ключи по паттерну?

    Доброе утро|день|вечер|ночь, %username%!

    При использовании Memcached, иногда могут возникнуть вопросы: «А как посмотреть все ключи Memcached?» или «Как найти все ключи по маске „*“ или „sql_*“ ?»
    Вот тогда открываются мануалы и начинается поиск такой функции, но, к сожалению, такой не оказывается :-(
    Потом начинается Гугление… И там особо ничего нет :-(
    А потом начинается поиск незадокументированных возможностей :-) и тут «Ура! Нашел!»

    Данный код, как раз, добавляет такую простую функцию, как просмотр ключей, и возвращает их в виде массива, с которым потом можно делать всё, что вздумается :-)

    1. /**
    2.  * getKeys()
    3.  *
    4.  *  get all keys from Memcache
    5.  *
    6.  * @author         Roman Kutsy
    7.  * @version        2.0.20090708
    8.  *
    9.  * @return    array     $keys
    10.  */    
    11. function getKeys()
    12.     ///////////////////////////////////////////////////////////////////////
    13.  
    14.     $s = @fsockopen('127.0.0.1',11211);
    15.          
    16.     // SLABS //////////////////////////////////////////////////////////////
    17.     
    18.     fwrite($s, 'stats slabs'."\r\n");
    19.          
    20.     $slabs = array();
    21.     
    22.     while( !feof($s) )
    23.     {
    24.         $temp = fgets($s, 256);
    25.         
    26.         preg_match('/^STAT\s([0-9]*)(.*)/', $temp, $slab_temp);
    27.         
    28.         if(isset($slab_temp['1']) && strlen($slab_temp['1'])>0)
    29.         {
    30.             $slabs[] = $slab_temp['1'];
    31.         }            
    32.         
    33.         unset($slab_temp);
    34.  
    35.         if(trim($temp)=='END')
    36.         {
    37.             break;
    38.         }
    39.     }
    40.  
    41.     unset($temp);
    42.  
    43.     // ITEMS //////////////////////////////////////////////////////////////
    44.     
    45.     fwrite($s, 'stats items'."\r\n");
    46.          
    47.     $items = array();
    48.     
    49.     while( !feof($s) )
    50.     {
    51.         $temp = fgets($s, 256);
    52.         
    53.         preg_match('/^STAT\sitems\:([0-9]*)(.*)/', $temp, $item_temp);
    54.         
    55.         if(isset($item_temp['1']) && strlen($item_temp['1'])>0)
    56.         {
    57.             $items[] = $item_temp['1'];
    58.         }            
    59.         
    60.         unset($item_temp);
    61.  
    62.         if(trim($temp)=='END')
    63.         {
    64.             break;
    65.         }
    66.     }
    67.  
    68.     unset($temp);
    69.     
    70.     $slabs = array_unique($slabs);
    71.     $items = array_unique($items);        
    72.  
    73.     // CACHEDUMP //////////////////////////////////////////////////////////
    74.  
    75.     $keys = array();            
    76.         
    77.     foreach($slabs as &$slab)
    78.     {
    79.         foreach($items as &$item)
    80.         {
    81.             fwrite($s, 'stats cachedump '.$slab.' '.$item."\r\n"); 
    82.             
    83.             while( !feof($s) )
    84.             {
    85.                 $temp = fgets($s, 256);
    86.  
    87.                 // ITEM cd3aec8b1dd7ef828267408e68b6d961:user_1_status [1 b; 1247043297 s]
    88.                 // or
    89.                 // ITEM sql_custom_photos_showphoto_11 [1379 b; 1247064083 s]
    90.  
    91.                 preg_match('/^ITEM\s([a-f0-9]{32}\:)?([A-Za-z0-9\_\-\.]*)\s\[[0-9]*\sb\;\s([0-9]*)\s.*/', $temp, $key_temp);
    92.  
    93.                 if(isset($key_temp['2']) && strlen($key_temp['2'])>0)
    94.                 {         
    95.                   $keys[] = $key_temp['2'];
    96.                 }            
    97.                 
    98.                 unset($key_temp);
    99.             
    100.                 if(trim($temp)=='END')
    101.                 {
    102.                     break;
    103.                 }                
    104.             }            
    105.         }
    106.     }
    107.     
    108.     unset($temp,$slabs,$items);
    109.     
    110.     fclose($s);
    111.     
    112.     ///////////////////////////////////////////////////////////////////////        
    113.          
    114.     $keys_temp = array_unique($keys);
    115.     unset($keys);        
    116.     asort($keys_temp);
    117.     
    118.     $keys = array();
    119.     foreach($keys_temp as &$k)
    120.     {
    121.         $keys[] = $k;
    122.     }
    123.     
    124.     return $keys;        
    125.     
    126.     ///////////////////////////////////////////////////////////////////////        
    127. }

    Удачи, %username%!

    UPD. Перенёс в "Web-разработка"
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 44

      +3
      и почему они, интересно, не сделали это в стандартном API?
        +1
        Наверное потому, что это приведет к падению производительности, а задача memcache — быть максимально быстрым
        Советую смотреть в сторону memcachedb, возможно там есть нужный функционал
          +7
          В MemcacheDB тоже нет такого функционала.
          Я бы советовал смотреть в сторону Redis'a [ code.google.com/p/redis/ ]
            +1
            я бы не советовал смотреть ни в редис ни в мемкешбд
              0
              А на что тогда?
                +4
                key-value для таких задач не предназначены т.к. идеология в том что сложность операций при работе с ними не больше O(1). Кеш сканировать по идее не нужно. Если все-таки нужно то где-то ошибка в архитектуре приложения.

                мемкешбд и редис кроме всего прочего сами по себе на практике довольно кривые.

                Если нужно сканирование то надо использовать бд а не кеш и нормальные индексы — это либо в реляционных бд, либо в документоориентированных бд.
                  0
                  согласен.

                  юзайте теги и не будет вам нужды найти «по маске»
                  –1
                  может сиськи?
              +1
              Мы использовали его в качестве хранилища счетчиков и отказались из-за deadlockов, получаемых при сбросе данных из памяти в хранилище.
                0
                а что используете теперь?
                  0
                  просто memcache, с последующим переносом данных в субд
                    0
                    данные потерять не страшно? почему тогда редис не используете — он примерно так же работает?
                      0
                      Потеря данных с той долей вероятностью, с которой это может произойти допустима. С редисом из команды ни кто не знаком, а на эксперименты и тестирование новых продуктов время не всегда есть
                      Перенос в бд происходит раз в сутки, поэтому это «примерно» также работает
              0
              memcached — это сервер кешинга в памяти, он может использоваться несколькими приложениями. Мне кажется это из соображений безопасности.
                +1
                из соображений безопасности надо было на уровне архитектуры сервера принципиально такую возможность исключать.
              +2
              Мдас, перешурстите мои пару миллионов ключей с десятка серверов кешеда.
              Повторюсь конечно, но молимся на тэги smira
                0
                Тэги smira?
                Если можно — по-подробнее.
                  0
                    0
                    Спасибо.

                    Проблема в том, что если так делать, то увеличится количество запросов, а отсюда — и нагрузка.
                    А используя скрипт — нагрузка будет большой (тут не отрицаю), но не постоянной.
                +1
                Надо замерить скорость работы кода на реальных нагруженных приложениях. Это лишь мое предположение, но видимо поиск происходит так медленно, что использовать memcache в этом случае бессмыссленно.
                  0
                  Ну я и не говорю что это довольно быстро, особенно на паре миллионов записей на десятке мемкэш-серверов при полной нагрузке., но альтернатив получения всех (или по уканному паттерну) ключей с Мемкэша я пока не видел :-)
                    0
                    А вот если использовать теги? Ну я вот не специалист вообще в этом, знаю только принцип работы и пару раз баловался.
                    +1
                    В дальнейшем надо будет подумать о кэшировании этих кэш ключей :)))
                      0
                      Думали уже неоднократно. Всё упиралось в «гонки». Есть ли в мемкэше понятие эксклюзивной записи с блокировками? А осилит ли этот кэш ключей (псевдо «регистр ключей») значение в два-три миллиона записей?
                    0
                    Спасибо за решение.
                    Может быть теперь получится реализовать очистку кеша по маске.
                      0
                      Как раз таки для очистки есть уже масса более правильных и грамотных решений с тегами.
                      0
                      Вы не представляете, как я вам благодарен.
                        0
                        Всегда пожалуйста! ;-)
                        +1
                        А не проще ли хранить все нужные тебе ключи в массиве по отдельному ключу, ну т. е. пользоваться стандартными средствами мемкешеда?

                        Т. е. записал в мемкешед ключ1-значение1, ключ2-значение2, ..., ключN-значениеN, а по ключу keys-[ключ1, ключ2, ..., ключN] или даже keys-[ключ1-времяЖизни1, ключ2-времяЖизни2, ..., ключ3-времяЖизни3].

                        В процессе работы просто пушим в массив keys новые ключи, а когда нужно, считываем, агрегируем (чтобы исключить уже умершие ключи) и обновляем keys в самом мемкешеде.
                          0
                          >В процессе работы просто пушим в массив keys новые ключи, а когда нужно, считываем, агрегируем (чтобы исключить уже умершие ключи) и обновляем keys в самом мемкешеде.
                          1) если ключей данное поле станет большим и не поворотливым
                          2) и вообще это работать не будет, тк в случае одновременного запроса к элементу keys 2х или более процессов, и последующем обновлении, целостность данных нарушится
                            0
                            1. Уверен, что контент который в обычных условиях храниться в мемкеше намного привысит по объему массив самих ключей, даже если у Вас этот массив будет в несколько кБ.

                            2. Тут так же применимы все техники работы при конкурентном доступе.

                            Т. е. Вы считаете, что метод топикстартера лучше будет работать с большими объемами ключей и в условиях конкурентного доступа?
                              0
                              считаю (уверен), что оба варианта работать при больших объемах и конкуренции работать не будут.
                              нужен другой подход, по типу хеш-таблицы. В общем, в комментарии суть не вместить, как будет время, напишу пост
                                0
                                Где вы хеш-таблицу хранить думаете? И как реализацию делать? Если все делать стандартными средствами и хранить данные в самом мемкеше — так я о том и писал, просто реализацию самую простую предложил.

                                А если дорабатывать сам мемкеш, добавляя ему соответствующий функционал, так проще не изобретать велосипед, а применить другой инструмент, из тех что тут в комментах опоминали или поискать другой.
                          +1
                          Вот, то что Вам нужно. Linux
                            0
                            О! Спасибо.
                            Посмотрим, посмотрим.
                            0
                            PHP Client Comparison
                            Как я понял есть 2 разных библиотеки для работы с memcache из под php (pecl/memcache и pecl/memcached). А в чем их принципиальное отличие? (сорри с английским не всё так хорошо)
                              +8
                              Это конечно замечательно, но ахтунг: stats cachedump выдает лишь часть данных (что-то коло 200к ключей, насколько я помню). Если у вас весь кэш помещается в это количество, тогда ура, если нет — нарветесь на проблемы, если будете рассчитывать, что возращен весь кэш.

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

                              Именно по этим причинам этих функций и нет в различных API. Формально memcached ничего не знает о структуре хранимых им ключей.
                                +2
                                Таким образом топик и решение — бред. Будет только хуже, чем перезапуск сервиса.
                                0
                                Чтобы к такой проблеме прийти — нужно вначале нагадитьнакодить так чтобы эти ключи потерять.
                                  –1
                                  Последнее время memcached применяют где надо и где не надо. Почитайте FAQ на сайте memcached, там ясно написано почему не стоит выгребать все ключи из сервера.
                                    0
                                    Хм, ваша функция возвращает пустой массив, а getStats('cachedump') — FALSE.
                                    Всё на локалхосте.
                                    Интересно, почему?
                                      0
                                      IP и порт верны?
                                      А если телнетом зайти (telnet 127.0.0.1 11211) и написать к примеру "stats slabs"? Что пишет?
                                        0
                                        STAT 5:chunk_size 232
                                        STAT 5:chunks_per_page 4519
                                        STAT 5:total_pages 1
                                        STAT 5:total_chunks 4519
                                        STAT 5:used_chunks 4519
                                        STAT 5:free_chunks 0



                                        END
                                      0
                                      Ужс! Представляю как приложение, использующее этот метод сломается, как только кол-во ключей зашкалит за 10К.

                                      Не стоит изобретать велосипед. используйте теги

                                      Only users with full accounts can post comments. Log in, please.