Pull to refresh

Дамп memcached на диск

Reading time 3 min
Views 9.1K
API взаимодействия с memcached представлен во всех популярных языках, поэтому в задачах кэширования это наиболее используемый инструмент. В случае когда не требуется ничего кроме кэширования, видимо, — самый оправданный.
Одна из проблем с которой я столкнулся при работе с memcached — невозможность сбросить его состояние на диск. Существующие решения либо не являлись простым кэшом (представляя скорее БД), либо не были настолько же стабильны и поддерживаемы. Вдобавок имелось желание «покодить», поэтому какой-то из готовых вариантов я мог банально упустить.

Зачем это может понадобиться


Причина почему обычно не нужен персистентный кэш — данные легко заполучить снова. Однако, если есть вероятность того, что в «час пик» кэш-сервера с hitrate=60% перезагрузятся, а сервис физически не сможет справиться с возросшей нагрузкой, то эту вероятность стоит учесть.

Форк и выполнение дампа


Представленный форк, memcached-dd, решает именно обозначенную проблему — производит дамп записей на диск. Использование простое — достаточно запустить модифицированный memcached с указанием имени файла в параметре -F:

memcached -F /tmp/memcache.dump -m 64 -p 11211 -l 127.0.0.1

При старте файл /tmp/memcache.dump будет загружен (если он существует). Туда же будет произведена и запись нового дампа. Управление распорядком записи дампов и т.п. предполагается извне, инициирование — сигналом SIGUSR2. Стоит отметить, что дамп сперва запишется файл .tmp и лишь затем, при успешной записи, будет переименован.

Особенности выполнения дампа


  • Дамп производится в отдельном потоке и не блокирует работу memcached
  • Если используется TTL, то при загрузке дампа TTL будет равен оному на момент выгрузки
  • Просроченные данные не попадают в дамп (*)

* - Как memcached удаляет данные
memcached использует т.н. «ленивое» удаление. Данные проверяются на просроченность лишь при явных операциях. Аналогично работает и обнуление кэша (команда flush_all): memcached просто проверяет что запись была создана после предыдущей команды очистки. Такой подход позволяет сбрасывать данные мгновенно.


Пример использования


Посмотрим как использовать memcached с Perl-скриптом, загружающим в него «автогенеренные» строки

use Cache::Memcached;
 
$memd = new Cache::Memcached {
    'servers' => [ "127.0.0.1:11211" ]
};
 
$| = 1;
 
for (my $i = 0; $i <= 10000; $i++) {
    $memd->set( "key_$i", "x"x100 . " [$i]" );
    # my $val = $memd->get( "xkey_$i");
 
    if ($i % 1000 == 0) {
        print "\r$i...";
    }
}

Используем этот скрипт после запуска memcached

$ ./memcached -P /tmp/memcached.pid -F /tmp/memcached.dump -m 128 -p 11211 -l 127.0.0.1

# загрузим данные
$ perl ./load.pl

# произведем дамп
$ kill -USR2 `cat /tmp/memcached.pid`
1Mb dumped: 10001 items (0 expired during dump, 0 nuked by flush)
Moving temprorary /tmp/memcached.dump.tmp -> /tmp/memcached.dump

Итак, у нас есть файл /tmp/memcached.dump с 10001 записями. Перезапустим memcached с тем же флагом -F и проверим на существование ключа #1:

$ ./memcached -P /tmp/memcached.pid -F /tmp/memcached.dump -m 128 -p 11211 -l 127.0.0.1
$ echo get key_1 | nc 127.0.0.1 11211
VALUE key_1 0 104
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx [1]
END

Как видно, содержимое успешно восстановилось из дампа.

Это решение позволяет задействовать имеющееся API memcache, т.е. использовать дамп не модифицируя схему общения. Надеюсь, что такая возможность будет полезна при особых сценариях работы с memcached.
Tags:
Hubs:
+25
Comments 15
Comments Comments 15

Articles