Pull to refresh

Memcached и PHP ликбез

Reading time 6 min
Views 223K
В интернете достаточно много информации на данную тему, но, несмотря на это, многие обходят её стороной. Цель данного поста, разъяснить на пальцах основы взаимодействия с Memcached.

Что такое Memcache и какое отношение он имеет к PHP?


Memcache разработан для кэширования данных, генерация которых требует большого количества ресурсов. Такого рода данные могут содержать что угодно, начиная с результатов запроса к базе данных и заканчивая тяжеловесным куском шаблона. Memcached не входит в базовый набор модулей, поставляемых с PHP, однако он доступен в репозитории pecl.

Установка и настройка


В качестве рассматриваемого дистрибутива я решил использовать Debian, потому как он наиболее часто используется при создании web-серверов. Модуль Memcached для PHP доступен в репозитории уже скомпилированным (php5-memcached), но я опишу процесс установки из исходного кода, так как не все репозитории настолько богаты, как дебиановский.

Устанавливаем сервер Memcached


#apt-get install memcached
Для начала, Вам хватит следующего конфига:
#/etc/memcached.conf
#Memcached будет работать, как демон
-d
#Лог будет складывать туда
logfile /var/log/memcached.log
#Отведём 256 мегабайт ОЗУ под хранилище
-m 256
#Слушать будет этот порт
-p 11211
#В последствии желательно поменять
-u nobody
#Слушаем localhost
-l 127.0.0.1

#/etc/init.d/memcached restart

Проверяем

# netstat -tap | grep memcached
tcp    0   0 localhost:11211     *:*           LISTEN   13036/memcached

Компилируем и устанавливаем модуль для PHP


apt-get install php5-dev libmemcache-dev
 
pecl download memcache
tar xzvf memcache-2.2.6.tgz
cd memcache-2.2.6/
phpize && ./configure --enable-memcache && make
cp modules/memcache.so /usr/lib/php5/20060613/
 
echo 'extension=memcache.so' >> /etc/php5/apache2/php.ini
/etc/init.d/apache2 restart

Вот и всё! Совсем не сложно.

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


1. Базовые операции


  1.     <?php
  2.     //Создаём новый объект. Также можно писать и в процедурном стиле
  3.     $memcache_obj = new Memcache;
  4.  
  5.     //Соединяемся с нашим сервером
  6.     $memcache_obj->connect('127.0.0.1', 11211) or die(«Could not connect»);
  7.  
  8.     //Попытаемся получить объект с ключом our_var
  9.     $var_key = @$memcache_obj->get('our_var');
  10.  
  11.     if(!empty($var_key))
  12.     {
  13.         //Если объект закэширован, выводим его значение
  14.         echo $var_key;
  15.     }
  16.  
  17.     else
  18.     {
  19.         //Если в кэше нет объекта с ключом our_var, создадим его
  20.         //Объект our_var будет храниться 5 секунд и не будет сжат
  21.         $memcache_obj->set('our_var', date('G:i:s'), false, 5);
  22.  
  23.         //Выведем закэшированные данные
  24.         echo $memcache_obj->get('our_var');
  25.     }
  26.  
  27.     //Закрываем соединение с сервером Memcached
  28.     $memcache_obj->close();
  29.     ?>

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

2. Повышаем производительность



2.1 С кэшированием

  1. <?php
  2. function LoadCPU()
  3. {
  4. //Функция, которая должна зугрузить процессор
  5.  
  6. //Создадим изображение 800x600
  7. $image = imagecreate(800600);
  8.  
  9. //Белый фоновый цвет
  10. $color = imagecolorallocate($image, 255255255);
  11.  
  12. //Чёрный
  13. $color2 = imagecolorallocate($image, 000);
  14.  
  15. for ($i = 0; $i < 10000; $i++) {
  16. //Расставим 10 000 точек в случайном порядке
  17. imagesetpixel($image, rand(0800)rand(0,600), $color2);
  18. }
  19.  
  20. //Выбрасываем указатель
  21. return $image;
  22. }
  23.  
  24.  
  25. //Создаём новый объект Memcache
  26. $memcache_obj = new Memcache;
  27.  
  28. //Соединяемся с нашим сервером
  29. $memcache_obj->connect('127.0.0.1'11211) or die("Could not connect");
  30.  
  31. //Попытаемся получить объект с ключом image
  32. $image_bin = @$memcache_obj->get('image');
  33.  
  34. if(empty($image_bin)) {
  35.  
  36. //Если в кэше нет картинки, сгенерируем её и закэшируем
  37. imagepng(LoadCPU(),getcwd().'/tmp.png',9);
  38. $image_bin = file_get_contents(getcwd().'/tmp.png');
  39. unlink(getcwd().'/tmp.png');
  40. $memcache_obj->set('image', $image_bin, false30);
  41. }
  42.  
  43. //Выведем картинку из кэша
  44. header('Content-type: image/png');
  45. echo $image_bin;
  46.  
  47. //Закрываем соединение с сервером Memcached
  48. $memcache_obj->close();
  49. ?>

В данном примере приведена функция, которая создаёт изображение размером 800x600 и расставляет на нём 10 000 точек. Один раз, сгенерировав такое изображение, в дальнейшем мы лишь выводим его на экран, не генерируя заново.

2.2 Без кэширования

  1. <?php
  2. function LoadCPU()
  3. {
  4. //Функция, которая должна загрузить процессор
  5.  
  6. //Создадим изображение 800x600
  7. $image = imagecreate(800, 600);
  8.  
  9. //Белый фоновый цвет
  10. $color = imagecolorallocate($image, 255, 255, 255);
  11.  
  12. //Чёрный
  13. $color2 = imagecolorallocate($image, 0, 0, 0);
  14.  
  15. for ($i = 0; $i < 10000; $i++) {
  16. //Расставим 10 000 точек в случайном порядке
  17. imagesetpixel($image, rand(0, 800), rand(0,600), $color2);
  18. }
  19.  
  20. //Выбрасываем указатель
  21. return $image;
  22. }
  23.  
  24. //Выводим изображение, не кэшируя
  25. header('Content-type: image/png');
  26. imagepng(LoadCPU(),'',9);
  27. ?>

Тут всё гораздо проще и привычней: генерируем изображение каждый раз заново.

Результаты

Я протестировал оба скрипта на производительность. Одна и та же машина в первом случае выдала 460 ответов в секунду, а во втором лишь 10. Чего и следовало ожидать.
memcache


Ещё несколько полезных функций



addServer — в случае, если у вас в распоряжении несколько кэширующих серверов, вы можете создать некий кластер, добавляя сервера в пул. Следует обратить внимание на параметр weight. Он указывает на то, сколько памяти вам будет доступно на конкретном сервере.
delete — из названия понятно, что данный метод удаляет из кэша объект с заданным ключом.
replace — заменяет значение объекта с заданным ключом. Используйте в случае, если Вам понадобится изменить содержимое объекта, раньше чем истечёт время его жизни.

Итог


С моей точки зрения, применять кэширование стоит только на высоконагруженных ресурсах. Ведь каждый раз, подключаясь к серверу Memcached, вы тратите драгоценное время, что скорее всего не будет оправданным. Что касается больших проектов, лучше сразу написать больше строк кода, чем потом делать это в попыхах, с мыслью о том, что ваш сервис лежит. Также не стоит забывать о расходовании памяти! Учтите, что положив 300 мегабайт в кэш, вы отняли у себя 300 мегабайт ОЗУ...
В завершение хочу сказать, что данная статья не раскрывает все прелести технологии, однако я надеюсь, что она стимулирует Вас к самосовершенствованию. Спасибо за прочтение, многоуважаемый %username%!

UPD: Ещё один интересный момент. Memcached, есть PHP API к libmemcached. А Memcache, библиотека для php, не использующая libmemcached.
Tags:
Hubs:
+53
Comments 87
Comments Comments 87

Articles