Игорь Олемской — практические заметки по системному администрированию Linux CentOS

Архив тега ‘memcached’

Getting apache, PHP, and memcached working with SELinux (перепечатка)

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

SELinux PenguinI'm using SELinux more often now on my Fedora 15 installations and I came up against a peculiar issue today on a new server. My PHP installation is configured to store its sessions in memcached and I brought over some working configurations from another server. However, each time I accessed a page which tried to initiate a session, the page load would hang for about a minute and I'd find this in my apache error logs:

[Thu Sep 08 03:23:40 2011] [error] [client 11.22.33.44] PHP Warning:
Unknown: Failed to write session data (memcached). Please verify that
the current setting of session.save_path is correct (127.0.0.1:11211)
in Unknown on line 0

I ran through my usual list of checks:

  • netstat showed memcached bound to the correct ports/interfaces
  • memcached was running and I could reach it via telnet
  • memcached-tool could connect and pull stats from memcached
  • double-checked my php.ini
  • tested memcached connectivity via a PHP and ruby script — they worked

Even after all that, I still couldn't figure out what was wrong. I ran strace on memcached while I ran a curl against the page which creates a session and I found something significant — memcached wasn't seeing any connections whatsoever at that time. A quick check of the lo interface with tcpdump showed the same result. Just before I threw a chair, I remembered one thing:

SELinux.

A quick check for AVC denials showed the problem:

# aureport --avc | tail -n 1
4021. 09/08/2011 03:23:38 httpd system_u:system_r:httpd_t:s0 42 tcp_socket name_connect system_u:object_r:memcache_port_t:s0 denied 31536

I'm far from being a guru on SELinux, so I leaned on audit2allow for help:

# grep memcache /var/log/audit/audit.log | audit2allow
 
#============= httpd_t ==============
#!!!! This avc can be allowed using one of the these booleans:
#     httpd_can_network_relay, httpd_can_network_memcache, httpd_can_network_connect
 
allow httpd_t memcache_port_t:tcp_socket name_connect;

The boolean we're looking for is httpd_can_network_memcache. Flipping the boolean can be done in a snap:

# setsebool -P httpd_can_network_memcache 1
# getsebool httpd_can_network_memcache
httpd_can_network_memcache --> on

After adjusting the boolean, apache was able to make connections to memcached without a hitch. My page which created sessions loaded quickly and I could see data being stored in memcached. If you want to check the status of all of the apache-related SELinux booleans, just use getsebool:

# getsebool -a | grep httpd | grep off$
allow_httpd_anon_write --> off
allow_httpd_mod_auth_ntlm_winbind --> off
allow_httpd_mod_auth_pam --> off
allow_httpd_sys_script_anon_write --> off
httpd_can_check_spam --> off
httpd_can_network_connect_cobbler --> off
httpd_can_network_connect_db --> off
httpd_can_network_relay --> off
httpd_can_sendmail --> off
httpd_dbus_avahi --> off
httpd_enable_ftp_server --> off
httpd_enable_homedirs --> off
httpd_execmem --> off
httpd_read_user_content --> off
httpd_setrlimit --> off
httpd_ssi_exec --> off
httpd_tmp_exec --> off
httpd_unified --> off
httpd_use_cifs --> off
httpd_use_gpg --> off
httpd_use_nfs --> off

If you're interested in SELinux, a good way to get your feet wet is to head over to the CentOS Wiki and review their SELinux Howtos

Getting apache, PHP, and memcached working with SELinux is a post from: Major Hayden's Racker Hacker blog.

Thanks for following the blog via the RSS feed. Please don't copy my posts or quote portions of them without attribution.

6 ways to kill your server – learning how to scale the hard way (перепечатка)

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

Learning how to scale isn't easy without any prior experience. Nowadays you have plenty of websites like highscalability.com to get some inspiration, but unfortunately there is no solution that fits all websites and needs. You still have to think on your own and find a concept that works for your requirements. So did I.

memcache vs memcached — сравниваем клиенты для PHP (перепечатка)

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

performance

Какой клиент лучше использовать при разработке на PHP — php-memcached или php-memcache? Все зависит от того, какие особенности Вам нужны (неужели?). Давайте сравним в двух аспектах — функциональность и производительность.

Функциональность

Клиентская библиотека php-memcache была разработана еще в 2004 году и сегодня существует уже довольно стабильная версия, которая используется в 99.9% проектах (использующих сервер Memcache). Большим недостатком этой библиотеки является ее ограниченные способности — она реализует только часть протокола мемкеша, и не позволяет использовать его дополнительные возможности (какие именно — чуть ниже).

Библиотека php-memcached была разработана сравнительно недавно, но уже успешно используется на некоторых крупных проектах (например, digg.com — из которого и вышла эта разработка). Самое главное ее преимущество — это полная реализация протокола, в том числе:

  • CAS токены для версионирования ключей
  • Обратные вызовы (callbacks)
  • Метод getDelayed () позволяющий уменьшить время ожидания откладывая фактическое чтение ключей
  • Поддержка бинарного протокола
  • Возможность избежать сериализации используя igbinary

Производительность

Теперь давайте сравним производительность на практике.
Для этого напишем небольшой скрипт, который делает одинаковые операции с обоими клиентами:

<?

$ops = 10000;

$m = new Memcache();
$m->addServer('localhost');

$md = new Memcached();
$md->addServer('localhost', 11211);

echo "Test operations: {$ops}";
echo "<h3>get test</h3>";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ ) $m->get( md5(rand(1000, 99999)) );
echo "Memcache: " . ($res['memcache']['set'] = microtime(true) - $s ) . "<br />";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ ) $md->get( md5(rand(1000, 99999)) );
echo "Memcached: " . ($res['memcached']['set'] = microtime(true) - $s );

echo "<h3>set test</h3>";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ ) $m->set(md5(rand(1000, 99999)), 2);
echo "Memcache: " . ($res['memcache']['get'] = microtime(true) - $s ) . "<br />";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ ) $md->set(md5(rand(1000, 99999)), 2);
echo "Memcached: " . ($res['memcached']['get'] = microtime(true) - $s );

echo "<h3>delete test</h3>";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ ) $m->delete(md5(rand(1000, 99999)));
echo "Memcache: " . ($res['memcache']['delete'] = microtime(true) - $s ) . "<br />";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ ) $md->delete(md5(rand(1000, 99999)));
echo "Memcached: " . ($res['memcached']['delete'] = microtime(true) - $s );

echo "<h3>combined test</h3>";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ )
{
	$key = md5(rand(1000, 99999));
	$m->set($key, 2);
	$m->get($key);
	$m->delete($key);
}
echo "Memcache: " . ($res['memcache']['combined'] = microtime(true) - $s ) . "<br />";
$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ )
{
	$key = md5(rand(1000, 99999));
	$md->set($key, 2);
	$md->get($key);
	$md->delete($key);
}
echo "Memcached: " . ($res['memcached']['combined'] = microtime(true) - $s );

Как видно, скрипт просто выполняет основные операции сохранения, чтения и удаления ключей 10 тыс. раз и замерает их время для каждого клиента.

Результаты работы теста

Как видно из графика, производительность клиента php-memcache почти втрое выше, чем php-memcached. Следует учесть, что показатели при работе с бинарным протоколом почти не отличалась по времени от ASCII протокола.

Обновление

Благодаря внимательному читателю этого блога удалось выяснить, что сильные отличия в показателях тестов связаны с конкретными версиями и настройками библиотек. Проверка на других платформах дает отличие в производительности не более 10%.

В качестве вывода следует сказать, что клиент php-memcache лучше использовать, если функционала приложению полностью хватает (лучше, т.к. он быстрее). Если нужны расширенные возможности, то нужно использовать php-memcached. Но в этом случае нужно учесть понижение производительности.

Хотя важно заметить: даже не смотря на трехкратное различие в скорости работы, операции общения с сервером Memcache обычно занимают доли процента от времени исполнения приложения. Различие в скорости работ библиотек может быть заметно только при массовой работе с кешом, или же на огромных объемах данных.

Google Bookmarks Digg I.ua Ru-marks Ruspace Zakladok.net Reddit delicious Technorati Yahoo My Web News2.ru БобрДобр.ru Memori.ru rucity.com
Related posts:
  1. Memcached Multi-Get, зачем?
  2. Memcached — настройка под малые объекты
  3. Nginx + Memcached + SSI — кеширование страниц и блоков (partials)

Nginx + Memcached + SSI — кеширование страниц и блоков (partials) (перепечатка)

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

nginx-logo

В одной из предыдущих статей мы рассмотрели, каким образом можно реализовать кеширование страниц с помощью Varnish и ESI. В этой статье рассмотрим альтернативное решение — на основе двух суперзнаменитых продуктов — nginx и memcached.
Оба не нуждаются в представлении, а о том, как на основе их можно значительно увеличить эффективность работы Вашего сайта, поговорим ниже.

Зачем нужно кешировать страницы?

Довольно детально принципы кеширования страниц и блоков были рассмотрены в предыдущей статье (Varnish + ESI).

В качестве краткого повторения, несколько основных идей и преимуществ кеширования на уровне странц:

  • Кешируя страницы на отдающем сервере, Вы освобождаете ощутимое количество ресурсов на бекендах
  • В случае медленных страниц, значительно уменьшается время ожидания страниц Вашего сайта (ускоряется его работа)
  • Как показывает практика, во многих случаях внедрять систему кеширования странц в готовый проект легче, чем систему кеширования запросов

Nginx и memcached

Nginx позволяет читать данные из Мemcached — для этого Вам необходим модуль HttpMemcachedModule.

Самый простой пример — проверяем есть ли страница в кеше и, если есть, достаем из кеша, иначе — делаем запрос к бекенду.

server {
  location / {
    set $memcached_key $uri; # Ключ для проверки в memcached
    memcached_pass     127.0.0.1:11211; # Параметры подключения
    default_type       text/html; # Заголовок по умолчанию
    error_page         404 = @fallback; # 404 - данные в кеше не найдены
  }
  location @fallback {
    proxy_pass backend; # Бекенд
  }
}

В данный момент Nginx не умеет сохранять значения в memcached — только читать данные. Значит задача по сохранению страниц в кеш ложится на бекенд. Выглядит это приблизительно так (PHP):

<?
$memcache = new Memcache();
# какой-то код

ob_start();
# визуализация страницы - html
$html = ob_get_clean();
$memcache->set($_SERVER['REQUEST_URI'], $html);
echo $html;
?>

Кеширование блоков и SSI

Если у Вас не самый примитивный сайт (а он у Вас не такой), логика кеширования страниц будет несколько усложнена различными динамическими элементами страницы (блок авторизации, динамическое меню и т.п.). Подобные задачи решаются c помощью SSI — server side includes. Кроме всего прочего использование SSI экономит память, т.к. для каждой страницы Вы не будете хранить ее исходник целиком, а только внутреннюю (изменяемую) часть.

Синтаксис SSI очень простой и выглядит так:

<!--# include virtual="/authentication.php" -->

Следует отметить, что SSI — это уровень Web сервера. Для прилжения этот механизм полностью прозрачен. В приведенном примере, на месте вызова SSI, Web сервер (nginx) просто сделает еще один запрос к бекенду. Например, если у Вас два SSI вызова на страницу, то клиентский запрос к каждой странице будет генерировать три запроса к бекенду. Конечно, само по себе это бессмысленно, но в связке с кешированием представляет из себя мощный инструмент оптимизации систем.

Практический пример

Теперь соберем все выше изложенное в последовательный рецепт решения рассматриваемой задачи.

Для начала Вам необходимо выделить блоки в Вашем базовом (глобальном) шаблоне и заменить их вызовами SSI. Пример на PHP:

<html>
<body>

<h1>Тестируем nginx + memcached + ssi</h1>

<div class="auth">

<!--# include virtual="/authentication.php" -->
</div>


<!--# include virtual="/somepage.php" -->
</body>
</html>

Как видно, на странице есть два блока — блок авторизации и контентный блок (содержимое странички). В нашем примере блок авторизации будет персональным (допустим, после входа, там будет имя пользователя). Блок содержимого не будет персональным (т.е. он будет общим для всех пользователей).

Теперь необходимо настроить nginx для обработки SSI вызовов и использованию memcached:

# Upstream бекенда
upstream backend {
    server 127.0.0.1:8081;
}

server {
	listen 80;
	server_name test.com;

	root /var/www/test;
	index index.php;

	location / {
		# Все POST запросы отправляем на бекенд (не кешируя)
		if ($request_method = POST) {
			proxy_pass http://backend;
			break;
	        }

		# Включаем обработку SSI
		ssi on;
		default_type text/html;

		# Проверяем в мемкеше
		set $memcached_key "$uri";
		memcached_pass localhost:11211;
		proxy_intercept_errors  on;
		error_page 404 502 = @process;
	}

	# Сюда запрос приходит, если его небыло в кеше
	location @process
	{
		proxy_pass http://backend;
		ssi on;
	}
}

# Обычный бекенд
server {
	listen 8081;
	location ~* \.(php)$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME /var/www/test$fastcgi_script_name;
    }
}

Следующим шагом в приложении необходимо будет реализовать сохранение исходников страниц в memcached.

Кеширование персонализированных блоков

Ясно, что для кеширования персонализированных блоков необходимо добавить идентификатор пользователя (не вздумайте использовать внутренний ID пользователя) в ключ memcached. SSI вызов необходимо пометить, чтобы отличать персональные блоки от общих. Т.е. персональный вызов SSI будет иметь такой вид:


<!--# include virtual="/uid/authentication.php" -->
</div>

Для генерации memcached ключей с идентификатором пользователя можно использовать куки (устанавливать его будет приложение при авторизации пользователя):

set $memcached_key "$uri:$cookie_uid";

Соответственно, необходимо в nginx добавить обработчик для “/uid” запросов:

        location /uid {
                ssi on;
                default_type text/html;
                set $memcached_key "$uri:$cookie_uid";
                memcached_pass localhost:11211;
                proxy_intercept_errors  on;
                error_page 404 502 = @process;
        }

Естественно, в самом приложении все “/uid” запросы должны кешироваться с идентификатором пользователя:

$m->set($_SERVER['REQUEST_URI'] . ':' . $_COOKIE['uid'], $html);

Следует обратить внимание

Недавно появился продукт, который должен стать типичным решением при кешировании страниц — Twicecache. Пока он на очень ранней стадии и доступны только его исходники. Будем внимательно следить.

Google Bookmarks Digg I.ua Ru-marks Ruspace Zakladok.net Reddit delicious Technorati Yahoo My Web News2.ru БобрДобр.ru Memori.ru rucity.com
Related posts:
  1. Кеширование страниц — ускоряем сайт в 100 раз (Varnish + ESI)
  2. Настройка nginx
  3. Ресайзинг картинок в nginx

CentOS 5: особенности установки memcached и pgbouncer на одной машине

Один комментарий

В этой заметке описано, как установить memcached на ту же машину, где уже запущен pgbouncer (из репозитория pgdg). Сложность в том, что pgbouncer использует более новую версию libevent, чем memcached, в результате чего memcached при установке выдает «transaction failed».

Один из наиболее красивых выходов из ситуации — пересборка SRPM с новой библиотекой libevent, а заодно и новой версией memcached.

В случае, если репозиторий pgdg еще не установлен, его можно инсталировать следующей командой (версию можно выбрать на странице http://yum.pgsqlrpms.org/reporpms/repoview/pgdg-centos.html)

rpm -ihv http://yum.pgsqlrpms.org/reporpms/8.3/pgdg-centos-8.3-6.noarch.rpm

Из репозитория pgdg необходимо установить новый libevent-devel (вместо 83 может быть ваша версия pgdg)

yum --disablerepo=\* --enablerepo=pgdg83 install libevent-devel

Теперь необходимо загрузить srpm memcached (выбрать версию из репозитория можно по адресу: http://download.fedora.redhat.com/pub/epel/5/SRPMS/repoview/memcached.html) и последнюю версию самого memcached

rpm -Uhv http://download.fedora.redhat.com/pub/epel/5/SRPMS/memcached-1.2.5-2.el5.src.rpm
wget http://memcached.googlecode.com/files/memcached-1.2.8.tar.gz -O /usr/src/redhat/SOURCES/memcached-1.2.8.tar.gz

В файле /usr/src/redhat/SPECS/memcached.spec необходимо актуализировать версии memcached и rpm

Version:        1.2.8
Release:        1%{?dist}

Осталось собрать rpm

rpmbuild -bb /usr/src/redhat/SPECS/memcached.spec

В случае, если не хватает каких-то дополнительных библиотек, их можно установить командой «yum install».

Готовые пакеты можно найти в папке /usr/src/redhat/RPMS/

28.05.2009

Написал Игорь Олемской