Автосжатие в php-memcached после 20 000 символов при выключенном сжатии

// Январь 14th, 2011 // Memcached, PHP

После переезда на новый сервер, мы запустили сайт. Грузился он конечно очень быстро, но хотелось ещё быстрее. Посмотрели, а у нас выключено страничное кэширование. После включения начал вылезать мистический баг…

История

Для мониторинга обращений к Memcached я использовал следующую команду:

tail -f /var/log/memcached.log | grep -E «FOUND|STORED»

Она выводила мне запросы к ключам, и попадания/промахи кэша. Оказалось, что с кэшем всё в порядке ключи пишутся Zend Framework’омб читаются Nginx’ом, но из кэша поступает всякая абракадабра. Попробовали писать ключи через консоль, всё нормально, сделали тестовый скрипт на Python (уж очень его наш админ любит :-) потом на PHP — всё нормально. Долго ломали голову, в чем может быть дело. Смотрели на данные, которые отправляются в memcached, там всё нормально было. Установили, что проблема скорее всего в php расширении Memcahed. Смотрели настройки, всё ок, сжатия не устанавливали. Потом мне пришла мысля обрезать контент, коорый кладется в кэш по длине. Работает O_0

Начали искать лимит, после которого появляются кракозябры. 20 000. Когда отправляет 19 999 символов, всё ок. Когда 20 000 — полная лажа. После гугления (см. раздел Ссылки)  наткнулся на замечательную особенности php расширения для memcached.

Проблема

Вне зависимости от того, включили ли вы сжатие или нет, оно будет АВТОМАТИЧЕСКИ включено если размер передаваемых данных больше 20 000 символов.

Нет слов! Вот из-за этой-то фигни мы убили пол дня.

Решение

Сам лимит определяется функцией bool Memcache::setCompressThreshold ( int $threshold [, float $min_savings ] ), и есть два варианта решения проблемы.

  1. Повысить лимит до максимально-нереального, чтобы длина контента всегда была меньше лимита. Но есть опастность, что коогла мы забудем об этой баге, а коонтент будет больше лимита она опять проявится.
  2. Сделать нулевое сжатие, чтобы для данных любого размера php-memcached вел себя одинакво. Так мы и сделали

Собственно вот код, программеры на Zend Framework быстро разберутся. Будут вопросы — пишите в комментах.

class ZendExtra_Cache_Backend_RawMemcached extends Zend_Cache_Backend_Memcached
{

 /**
 * Из-за того, что php-memcached автоматически включает сжатие
 * для контента > 20000 байт, необходимо сделать степень сжатия 0 (значение 1)
 * для того, чтобы он его не сжимал и nginx мог спокойно прочитать данные при
 * повторном запросе
 */
 public function __construct(array $options = array())
 {
 parent::__construct($options);
 // Отключаем сжатие
 $this->_memcache->setCompressThreshold(20000, 1); // 1 - 100% - без сжатия
 }

P.S. Желаю вам не попадать на такие вот неприятные грабли :-)

Похожие баги

Вот тут человек также пытается связать nginx и php-memmcached. Получает тот же fail. Слишком большая картинка.

http://pecl.php.net/bugs/bug.php?id=16748

Ссылки

http://nginx.org/pipermail/nginx-ru/2009-April/024375.html

http://php.net/manual/en/memcache.setcompressthreshold.php

http://marrch-caat.livejournal.com/678321.html

http://habrahabr.ru/blogs/server_side_optimization/99256/

Share

Спасибо!


Если вам помогла статья, или вы хотите поддержать мои исследования и блог - вот лучший способ сделать это:


3 Responses to “Автосжатие в php-memcached после 20 000 символов при выключенном сжатии”

  1. AVR:

    День убил на эту проблему.
    По логам memcached установил, что SET приходит с флагом 2(= MEMCACHE_COMPRESSED), хотя под дебаггером было видно, что передается другое значение = 0. В сторону неадекватности расширения даже не думал, зря выходит…

    Спасибо! Если бы не Ваша статья — убил бы еще один день.

    • google.com Андрей Токарчук:

      Пожалуйста! Сам кучу времени провозился, поэтому и решил написать. Чтобы другие обошли эти милые грабельки :-)

  2. Иван:

    Можно задать
    $this->_memcache->setCompressThreshold(0), в этом случае сжатие также не будет производиться.
    Возможно также будет выигрыш от отсутствия проверки степени сжатия, хотя, возможно, при задании степени сжатия = 1 проверка не производится

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