УрокУскоряем работу с memcached. Сокеты, PECL Memcached, настройки.

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

1. Доступ к демону осуществляется быстрее через сокеты (что, в принципе, и не удивительно).
2. Библиотика PECL Memcached работает быстрее, чем PECL Memcache (а вот это для меня оказалось сюрпризом).
3. Настройки для библиотек по-умолчанию использовать нельзя, надо конфигурировать самостоятельно.
4. Настройки для демона memcached также необходимо подстраивать под сервер и используемую среду, дефолтные никуда не годятся.

Давайте теперь рассмотрим эти пункты более подробно.

Важно: вся конфигурация представлена для работы под CentOS. Для других систем настройки и расположения файлов могут незначительно отличаться.

Часть первая. Использование сокетов

Не секрет, что сокеты работают быстрее, чем сетевой протокол. К тому же поменять сетевой протокол на сокет достаточно просто, и не требует никаких существенных телодвижений, кроме небольших правок в конфигурационном файле демона.

По-умолчанию настройки демона мемкэша лежат в файле /etc/sysconfig/memcached и выглядят следующим образом:

PORT="11211"
USER="memcached"
MAXCONN="64"
CACHESIZE="64"
OPTIONS=""

Будем полагать, что наш сайт более-менее нагружен, и под мемкэш мы можем выделить хотя бы 2 гб памяти. Таким образом, подключение сокета вместо tcp соединения будет выглядеть следующим образом:

PORT=0
USER="memcached"
MAXCONN="1024"
CACHESIZE="2048"
OPTIONS="-a 0766 -s /var/run/memcached/memcached.socket"

После сохранения настроек перезапустите memcached:

service memcached restart

Теперь надо настроить модуль Memcache Storage на работу с нашим сокетом. Для этого достаточно в settings.php дописать такую настройку:

$conf['memcache_servers'] = array(
  'unix:///var/run/memcached/memcached.socket' => 'default',
);

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

Настройка нескольких сокетов несколько сложнее. Я накидал свой конфиг для этих целей (всё тот же файл /etc/sysconfig/memcached):

#! /bin/sh
#
# chkconfig: - 55 45
# description:    The memcached daemon is a network memory cache service.
# processname: memcached
# config: /etc/sysconfig/memcached
# pidfile: /var/run/memcached/memcached.pid
 
# Standard LSB functions
#. /lib/lsb/init-functions
 
# Source function library.
. /etc/init.d/functions
 
USER=memcached
OPTIONS="-a 0766 -c 2048"
RETVAL=0
PROG="memcached"
 
start_instance() {
    echo -n $"Starting $PROG ($1): "       
    daemon --pidfile /var/run/memcached/memcached.$1.pid memcached -d -s $3 -u $USER -m $2 -P /var/run/memcached/memcached.$1.pid $OPTIONS
 
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/memcached.$1
}
 
stop_instance() {
    echo -n $"Stopping $PROG ($1): "
    killproc -p /var/run/memcached/memcached.$1.pid /usr/bin/memcached
    RETVAL=$?
    echo
    if [ $RETVAL -eq 0 ] ; then
        rm -f /var/lock/subsys/memcached.$1
        rm -f /var/run/memcached.$1.pid
    fi
}
 
start () {
    # insure that /var/run/memcached has proper permissions
    if [ "`stat -c %U /var/run/memcached`" != "$USER" ]; then
        chown $USER /var/run/memcached
    fi
 
    # start 2 socket streams for memcached.
    start_instance default 2048 /var/run/memcached/memcached.socket0;
    start_instance page 512 /var/run/memcached/memcached.socket1;
}
 
stop () {
    stop_instance default;
    stop_instance page;
}
 
restart () {
    stop
    start
}
 
 
# See how we were called.
case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  status)
    status memcached
    ;;
  restart|reload|force-reload)
    restart
    ;;
  condrestart)
    [ -f /var/lock/subsys/memcached ] && restart || :
    ;;
  *)
    echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
    exit 1
esac
 
exit $?

Этот файл запускает 2 демона мемкэша, каждый из которых работает через свой сокет. Для того, чтобы поменять количество запущенных демонов и объём их оперативной памяти, достаточно поменять параметры здесь:

    # start 2 socket streams for memcached.
    start_instance default 2048 /var/run/memcached/memcached.socket0;
    start_instance page 512 /var/run/memcached/memcached.socket1;

Давайте коротко расскажу о смысле этих строк:

  • start_instance - название функции, которая запускает работу memcached.
  • default - название сущности. Может быть любым.
  • 2048 - количество памяти в мегабайтах, которое выделится для работы демона.
  • /var/run/memcached/memcached.socket0 - путь к сокету. Для добавления ещё одного сокета просто поменяйте последнюю цифру.

Ну и конечно, если добавляете ещё одну сущность мемкэша, не забудьте добавить в конфиг её остановку:

stop () {
    stop_instance default;
    stop_instance page;
}

Для двух сокетов настройки Memcache Storage в settings.php будут выглядеть так:

# Add multiple memcached instances.
$conf['memcache_servers'] = array(
  'unix:///var/run/memcached/memcached.socket0' => 'default',
  'unix:///var/run/memcached/memcached.socket1' => 'page',
);
 
# Set reference between cache bins and memcache server names.
$conf['memcache_bins'] = array(
  'cache_page' => 'page',
);

Для более подробного мануала внимательно читайте README.

Часть вторая. PECL Memcached vs PECL Memcache

Изначально я был уверен, что PECL Memcache быстрее, чем PECL Memcached. Подтверждения этому я находил в тестах, проведённых различными разработчиками на просторах интернета. Однако потом мудрые люди натолкнули меня на идею попробовать сделать тесты самостоятельно. В результате оказалось, что PECL Memcached несколько быстрее своего аналога. А если его ещё и правильно настроить - он оказывается существенно быстрее.

Обратите внимание, что минимальная версия PECL Memcached, которая работает с Memcache Storage - 2.0.1. При использовании более старых версий я гаратнировать стабильность и скорость работы не берусь.

Помимо установки расширения PECL Memcached на сервере (если на нём уже стоит PECL Memcache), в settings.php надо указать, какое из расширений использовать в качестве связующего звена между клиентом и демоном memcached:

# Set current extension.
$conf['memcache_extension'] = 'Memcached';

Часть третья. Настройка PECL Memcached.

Поигравшись со всеми настройками расширения pecl memcached, я получил наиболее оптимальный набор, который даёт прирост в скорости:

$conf['memcache_options'] = array(
  Memcached::OPT_TCP_NODELAY => TRUE,
  Memcached::OPT_BINARY_PROTOCOL => TRUE,
  Memcached::OPT_BUFFER_WRITES => TRUE,
  Memcached::OPT_NO_BLOCK => TRUE
);

Подсказка: на некоторых серверах Memcached::OPT_BINARY_PROTOCOL лучше поставить в FALSE.

Часть четвёртая. Настройка демона memcached.

У memcached есть масса собственных настроек, с которыми его можно запускать. Понаблюдав за нескольми серверами, на которых стоит мемкэш и их взаимодействием с Друпалом, я вывел свой конфиг, который приносит хороший результат как в производительности, так и в эффективном использовании памяти:

#! /bin/sh
#
# chkconfig: - 55 45
# description:    The memcached daemon is a network memory cache service.
# processname: memcached
# config: /etc/sysconfig/memcached
# pidfile: /var/run/memcached/memcached.pid
 
# Standard LSB functions
#. /lib/lsb/init-functions
 
# Source function library.
. /etc/init.d/functions
 
USER=memcached
OPTIONS="-a 0766 -c 2048 -f 1.07 -n 512 -L"
RETVAL=0
PROG="memcached"
 
start_instance() {
    echo -n $"Starting $PROG ($1): "       
    daemon --pidfile /var/run/memcached/memcached.$1.pid memcached -d -s $3 -u $USER -m $2 -P /var/run/memcached/memcached.$1.pid -v 2>> /var/log/memcached/memcached.$1.log $OPTIONS
 
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/memcached.$1
}
 
stop_instance() {
    echo -n $"Stopping $PROG ($1): "
    killproc -p /var/run/memcached/memcached.$1.pid /usr/bin/memcached
    RETVAL=$?
    echo
    if [ $RETVAL -eq 0 ] ; then
        rm -f /var/lock/subsys/memcached.$1
        rm -f /var/run/memcached.$1.pid
    fi
}
 
start () {
    # insure that /var/run/memcached has proper permissions
    if [ "`stat -c %U /var/run/memcached`" != "$USER" ]; then
        chown $USER /var/run/memcached
    fi
 
    # start 3 socket streams for memcached.
    start_instance default 2048 /var/run/memcached/memcached.socket0;
    start_instance page 1024 /var/run/memcached/memcached.socket1;
}
 
stop () {
    stop_instance default;
    stop_instance page;
}
 
restart () {
    stop
    start
}
 
 
# See how we were called.
case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  status)
    status memcached
    ;;
  restart|reload|force-reload)
    restart
    ;;
  condrestart)
    [ -f /var/lock/subsys/memcached ] && restart || :
    ;;
  *)
    echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
    exit 1
esac
 
exit $?

В этом конфигурационном файле запускается 2 сокета - один для кэша страниц, второй для остального кэша. Это позволяет мне отдавать кэш анонимам и авторизованным пользователям через разные сокеты, что ведёт к увеличению пропускной способности.

Теперь о настройках, которые я добавлял:

  • -a 0766: маска доступа к файлу с сокетом. По идее это оптимальный вариант. На 0755 мемкэш ругается, что нехватает прав на работу с файлом, а 0777 уж слишком небезопасно.
  • -c 2048: количетво одновременных подключений к мемкэшу. Учитывая, что это число дублируется для каждого сокета, мне пока хватает. И не думаю, что скоро придётся это число менять.
  • -f 1.07: фактор роста размера chunk'ов. Не буду вдаваться в подробности фрагментации памяти мемкэша, но смысл такой: чем меньше этот показатель, тем эффективнее использование памяти (уменьшается показатель wasted). Однако в то же время, чем меньше этот показатель, тем чаще из памяти начинают выбрасываться записи кэша, у которых не истёк срок годности (eviction per second). Поэтому важно словить баланс между количеством памяти и этим показателем, при котором эффективность будет максимальная. Для себя я его нашёл: параметр -f колеблется от 1.07 до 1.1 на разных Drupal проектах.
  • -n 512: минимальный размер chunk'a, с которого начинается умножение на фактор роста (-f). Учитывая что Друпал в основном хранит массивы, оставлять значение по умолчанию (64 байта) крайне неэффективно. Опять же, как показывает мой опыт - на более-менее серьёзном проекте практически нет кэшированных данных, размером меньше 500 байт. А необходимости в бесполезной трате памяти я не вижу.
  • -L: попытка использование больших страниц памяти. При этой настройке мемкэш пытается объеденить всю предоставленную ему память в один большой chunk. Этот параметр позволяет улучшить производительность при работе с мемкэшем. Однако он может быть недоступен на некоторых операционных системах.
  • -v 2>> /var/log/memcached/memcached.$1.log: логирование ошибок и уведомлений при работе с мемкэшем. Может быть полезным, если его начинает штормить по непонятным причинам.

Если мой конфиг не запустится с первого раза, попробуйте сделать 2 вещи:
1. Уберите параметр -L из него (как я уже говорил - он не везде работает).
2. Создайте директорию memcached в /var/log.

А теперь о настройках Memcache Storage для эффективной работы:

Исходя из вышеуказанных настроек, а также учитывая опыт снижения нагрузки на сервер для анонимных пользователей, мой текущий конфиг settings.php выглядит таким образом:

# Move cache data info memcache storage.
$conf['cache_backends'][] = 'sites/all/modules/memcache_storage/memcache_storage.inc';
$conf['cache_default_class'] = 'MemcacheStorage';
$conf['cache_class_cache_form'] = 'DrupalDatabaseCache';
 
# Configure Memcache Storage module.
$conf['memcache_storage_debug'] = TRUE;
$conf['memcache_storage_wildcard_invalidate'] = 60 * 60 * 24 * 5; // 5 days.
 
# Add multiple memcached instances.
$conf['memcache_servers'] = array(
  'unix:///var/run/memcached/memcached.socket0' => 'default',
  'unix:///var/run/memcached/memcached.socket1' => 'page',
);
 
# Set reference between cache bins and memcache server names.
$conf['memcache_bins'] = array(
  'cache_page'  => 'page',
);
 
# Set custom expiration for cached pages.
$conf['memcache_storage_page_cache_custom_expiration'] = TRUE;
$conf['memcache_storage_page_cache_expire'] = 0;  // Never.
 
# Set current extension.
$conf['memcache_extension'] = 'Memcached';
 
# Configure memcached extenstion.
$conf['memcache_options'] = array(
  Memcached::OPT_TCP_NODELAY => TRUE,
  Memcached::OPT_BINARY_PROTOCOL => TRUE,
  Memcached::OPT_BUFFER_WRITES => TRUE,
  Memcached::OPT_NO_BLOCK => TRUE
);
 
# Avoid database connection for cached pages.
$conf['page_cache_without_database'] = TRUE;
$conf['page_cache_invoke_hooks'] = FALSE;
 
# Move storage for locking mechanism into memcache.
$conf['lock_inc'] = 'sites/all/modules/memcache_storage/includes/lock.inc';

По поводу последней строки конфига - да, Memcache Storage уже позволяет вынести механизм блокировки потоков в memcached :)

Итог. Тесты.

По итогу работы я накидал небольшой тест, в котором сравниваю производительность модулей Memcache Storage, Memcache API при их работе с PECL Memcache и PECL Memcached, с использованием сокетов и без них.

Тест выглядит так:

$bins = array('cache', 'cache_path', 'cache_filter', 'cache_bootstrap', 'cache_page');
$data = array_fill(0, 100, rand());
 
timer_start('cache_set');
for ($i = 0; $i < 2000; $i++) {
  foreach ($bins as $bin) {
    cache_set($bin . '_' . $i, $data, $bin);
  }
}
print '10 000 sets: ' . timer_read('cache_set') . ' ms<br>';
 
timer_start('cache_get');
for ($i = 0; $i < 2000; $i++) {
  foreach ($bins as $bin) {
    cache_get($bin . '_' . $i, $bin);
  }
}
print '10 000 gets: ' . timer_read('cache_get') . ' ms<br>';
 
timer_start('cache_clear_all');
for ($i = 0; $i < 2000; $i++) {
  foreach ($bins as $bin) {
    cache_clear_all($bin . '_' . $i, $bin);
  }
}
print '10 000 deletes: ' . timer_read('cache_clear_all') . ' ms<br>';

А вот так выглядят результаты тестов:

Memcache Storage (PECL Memcache)
10 000 sets: 1232.38 ms
10 000 gets: 1317.51 ms
10 000 deletes: 819.4 ms
 
Memcache Storage (PECL Memcache) + UNIX SOCKET
10 000 sets: 1079.81 ms
10 000 gets: 1083.23 ms
10 000 deletes: 670.9 ms
 
Memcache Storage (PECL Memcached)
10 000 sets: 381.98 ms
10 000 gets: 1010.02 ms
10 000 deletes: 145.95 ms
 
Memcache Storage (PECL Memcached) + UNIX SOCKET
10 000 sets: 352.63 ms
10 000 gets: 908.82 ms
10 000 deletes: 142.94 ms
 
Memcache API (PECL Memcache)
10 000 sets: 1745.43 ms
10 000 gets: 1543.33 ms
10 000 deletes: 890.73 ms
 
Memcache API (PECL Memcache) + UNIX SOCKET
10 000 sets: 1547.99 ms
10 000 gets: 1348.77 ms
10 000 deletes: 712.43 ms
 
Memcache API (PECL Memcached)
10 000 sets: 446.28 ms
10 000 gets: 1067.4 ms
10 000 deletes: 170.53 ms
 
Memcache API (PECL Memcached) + UNIX SOCKET
**Not working**
 
MySQL (Percona) + fun :)
10 000 sets: 33322.87 ms
10 000 gets: 2457.66 ms
10 000 deletes: 22653.61 ms

Как видите, наиболее быстрой на данный момент является связка Memcache Storage + PECL Memcached + unix sockets.

Комментарии

Аватар пользователя Коллега по правую руку
Коллега по прав... написал:

Статьи становятся все интереснее и полезнее для нагруженных сайтов. Автор - молодец :)

22.04.2013 15:17
Аватар пользователя Гость
Гость написал:

На open-server не пробовали такое повторить ?

03.05.2013 08:48
Аватар пользователя Spleshka
Spleshka написал:

На винду нельзя поставить pecl memcached. Да и само название "unix socket" подразумевает использование другой платформы. Поэтому - нет, по вполне понятным причинам.

03.05.2013 21:51
Аватар пользователя chilic
chilic написал:

Немного поправил скрипт запуска memcached для Debian.

Debian memcached socket start script

18.06.2013 12:27
Аватар пользователя Frantsuzzz2
Frantsuzzz2 написал:

Подскажите, как правильно пользоваться отладкой.
Выставляю параметр $conf['memcache_storage_debug'] = TRUE;
Внизу страниц появляется большая таблица со статистикой. Но у меня почему-то 100% промахи постоянно. Включал просмотр отладки для анонимных пользователей. Там тоже 100% промахи. При этом никаких ошибок на сайте нет. Memcached 2.1.0 установлен.

14.12.2013 06:44
Аватар пользователя Frantsuzzz2
Frantsuzzz2 написал:

Короче, ситуация оказалось смешной до слез. Когда Вы написали эту статью, я сразу обратился к своему хостинг провайдеру с вопросом, где и как подключается memcached. Мне объяснили. Я подключил. Настроил Друпал по вашим рекомендациям. И вроде сайт начал быстрее работать. А вот вчера решил все-таки разобраться, работает ли memcached. Почему всегда 100% промахи. Причина оказалась неожиданной:
- К сожалению, на виртуальном хостинге мы не предоставляем memcached из-за соображения безопасности. - получил сегодня от хостера.

14.12.2013 21:58
Аватар пользователя Гость
Гость написал:

Memcache Storage (PECL Memcache) на пока не сильно нагруженном сайте
10 000 sets: 1466.87 ms
10 000 gets: 623.17 ms
10 000 deletes: 783.24 ms

08.02.2014 00:58
Аватар пользователя АндрейЛ
АндрейЛ написал:

Тот же сайт, что и комментом выше:
10 000 sets: 761.84 ms
10 000 gets: 209.21 ms
10 000 deletes: 222.77 ms

Вроде, все работает, memcache выводит

memcache
memcache support => enabled
memcache.allow_failover => 1 => 1
memcache.chunk_size => 8192 => 8192
memcache.default_port => 11211 => 11211
memcache.default_timeout_ms => 1000 => 1000
memcache.hash_function => crc32 => crc32
memcache.hash_strategy => standard => standard
memcache.max_failover_attempts => 20 => 20
Registered save handlers => files user memcache

В admin/reports/status/php memcache есть
но попытки теста memcache (на разных сайтах примеры php-кода есть) проваливаются - белый экран выводится.

Я в этих делах, мягко говоря, не опытен; вроде, по цифрам, выходит, что работает все как надо, да?

09.02.2014 00:47
Аватар пользователя Виктор
Виктор написал:

Привет. Спасибо за статью.
Пробовал вариант с одним сокетом.
Вроде, кеширует (включил дебаг), но на скорость загрузки страниц это никак не влияет. Все те же 150ms.
Вот кусок из переделанного /etc/memcached.conf (у меня дебиан):
--------------------------
...
# Start with a cap of 64 megs of memory. It's reasonable, and the daemon default
# Note that the daemon will grow to this size, but does not start out holding this much
# memory
-m 256

# Default connection port is 11211
#-p 11211

# UNIX socket path to listen on (disables network support)
-s /var/run/memcached.socket

# access mask for UNIX socket, in octal (default: 0700)
-a 0766

# chunk size growth factor (default: 1.25)
-f 1.07

# Run the daemon as root. The start-memcached will default to running as root if no
# -u command is present in this config file
-u root

# Specify which IP address to listen on. The default is to listen on all IP addresses
# This parameter is one of the only security measures that memcached has, so make sure
# it's listening on a firewalled interface.
# -l 127.0.0.1
...
------------------------
и вот, что добавил в settings.php
// MEMCACHED
# Move all cached data (except form cache) to memcache storage.
$conf['cache_backends'][] = 'sites/all/modules/memcache_storage/memcache_storage.inc';
$conf['cache_default_class'] = 'MemcacheStorage';
$conf['cache_class_cache_form'] = 'DrupalDatabaseCache';
$conf['cache_class_cache_update'] = 'DrupalDatabaseCache';

# Advanced usage of Drupal page cache.
$conf['cache_backends'][] = 'sites/all/modules/memcache_storage/memcache_storage.page_cache.inc';
$conf['cache_class_cache_page'] = 'MemcacheStoragePageCache';

# Enable storing of plain HTML text instead of Drupal usual cache object.
$conf['memcache_storage_external_page_cache'] = TRUE;

$conf['memcache_extension'] = 'Memcached';
$conf['memcache_storage_debug'] = TRUE;
$conf['memcache_servers'] = array(
'unix:///var/run/memcached.socket' => 'default',
);
-------------
... и ничего. Накешировал целых два метра, но воз и ныне там. 150ms.
Такое подозрение, что страницы не кешируются. Какие Cache bin или Cache ID должны быть у главной страницы?

Изменения в конфигурации nginx (http://drupalace.ru/lesson/otdayom-kesh-anonimov-bez-podnyatiya-bekenda-drupal-7-nginx-memcached) тоже ничего не дало (с тем же одним сокетом):
---------------------
location / {
...
## MEMCACHED
default_type text/html;
add_header X-Nginx-Page-Cache HIT;
set $memcached_key "cache_page-$scheme://$server_name$uri$is_args$args";
memcached_pass unix:/var/run/memcached.socket;
#proxy_intercept_errors on;
#error_page 404 502 = @drupal;

## First we try the URI and relay to the /index.php?q=$uri&$args if not found.
try_files $uri @drupal;
}

########### Security measures ##########

## Restrict access to the strictly necessary PHP files. Reducing the
## scope for exploits. Handling of PHP code and the Drupal event loop.
location @drupal {
add_header X-Nginx-Page-Cache MISS;
...
---------------------

Короче говоря, что-то я туплю робяты. Голова идет кругом. Помогите кто чем может. :)
p.s.: Жду ответа, как соловей лета.

18.02.2014 02:35
Аватар пользователя Spleshka
Spleshka написал:

Виктор, кэш Nginx + memcached - это кэш для анонимных пользователей. То есть если в админке включена галочка "Кэшировать страницы для анонимных пользователей", то анонимам страница должна отдаваться из кэша.

То, что у вас страница отдаётся за 150мс - это отлично. Значит, что сайт достаточно свежий и лёгкий, и нет большой нагрузки на выборку из базы данных. Есть вещи в производительности, которые заметны только на больших нагрузках. На простых сайтах не всегда есть смысл ставить мемкэш, тем более, если без него работает так же.

P.S. Конфиги правильные.

21.02.2014 16:22
Аватар пользователя Читатель
Читатель написал:

>Однако сокеты всё же имеют какой-то предел на количество одновременных подключений к нему.

Можно подробнее раскрыть тему максимального количества подключений к UNIX-сокету? Сколько их может быть?

25.03.2014 18:49
Аватар пользователя Михаил
Михаил написал:

Информация по настройке Hugepages (параметр -L у memcached): https://wiki.debian.org/Hugepages, http://www.peuss.de/node/67

22.04.2014 10:20
Аватар пользователя Виталий
Виталий написал:

Вопрос проверки работы связки Drupal + Memcache Storage, если включить в модуле $conf['memcache_storage_debug'] = TRUE; то судя по данным модуль работает. Вопрос - почему при попытке сделать curl -sIXGET site.com получаем
X-Drupal-Cache: MISS ?

14.07.2015 00:11
Аватар пользователя Rush
Rush написал:

кто-кто, а друпалисты знают о кэше все)

25.11.2015 15:50

Комментировать