Чем забита ваша память или анализируем содержимое кеша XCache

Источник: habrahabr


Вас смущает это число? Меня тоже.

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

Возможно, вы выделили слишком много оперативной памяти под кеш. Размер его можно значительно уменьшить путем отключения тяжеловесных, но редко посещаемых сайтов. Я вам помогу вычислить такие сайты.

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

Админка - штука очень полезная, позволяет подобрать оптимальный размер оперативной памяти, выделяемый для хранения байткода исполняемых скриптов. Также она позволяет просматривать хранимые данные и удалять их.

Список эакешированных скриптов выглядит длинной колбасой. Админка имеет встроенное средство для сортировки данных, но работать со столь длинным списком невозможно.


Добавляем статистику в штатную админку

Поскольку админка написана на PHP с открытым кодом, то мы её модифицируем, добавив нужный функционал.


Добавим на страницу List PHP:
1. Статистику скриптов по хостам
2. Фильтр скриптов по хостам (если быть точным, по префиксам).

xcache.tpl.php строка 150
После
    foreach (array('Cached' => $cachelist['cache_list'], 'Deleted' => $cachelist['deleted_list']) as $listname => $entries) {
        $a->reset();

добавляем
        if ($listname == 'Cached')
        {		
            $hosts = array();
            $filtertrash = array('', 'usr', 'home');
            foreach ($entries as $i => $entry)
            {
                if (strpos($entry['name'], $_SERVER['DOCUMENT_ROOT']) === 0)
                {
                    $host = $_SERVER['DOCUMENT_ROOT'];
                    $prefix = $_SERVER['DOCUMENT_ROOT'];
                }
                else
                {
                    $pos = 0;
                    foreach (explode('/', $entry['name']) as $host)
                    {
                        if (!in_array($host, $filtertrash)) break;
                        $pos += strlen($host) + 1;
                    }
                    $prefix = substr($entry['name'], 0, strpos($entry['name'], $host, $pos) + strlen($host));
                }
                if (isset($hosts[$host]))
                {
                    $hosts[$host]['files']++;
                    $hosts[$host]['hits'] += $entry['hits'];
                    $hosts[$host]['size'] += $entry['size'];
                }
                else
                {
                    $hosts[$host] = array(
                    'prefix' => $prefix,
                    'files' => 1,
                    'hits' => $entry['hits'],
                    'size' => $entry['size'],
                    );
                }
            }
            ?>
            <table cellspacing="0" cellpadding="4" class="cycles entries">
                <tr><th>Host</th><th>Files</th><th>Hits</th><th>Size</th><th>Ratio(size/hits)</th></tr>
            <?php
            uasort($hosts, create_function('$a,$b' , 'return $b["size"] - $a["size"];'));
            foreach ($hosts as $host => $hoststats)
            {
                ?><tr><td><a href="?type=0&prefix=<?=$hoststats['prefix']?>"><?=$host?></a></td><td><?=$hoststats['files']?></td><td><?=$hoststats['hits']?></td>
                    <td><?= ($hoststats['size'] > 1048576 ? round($hoststats['size'] / 1048576).' M' :
                        ($hoststats['size'] > 1024 ? round($hoststats['size'] / 1024).' k' : $hoststats['size'])  
                        ) ?></td>
                    <td><?=round($hoststats['size']/$hoststats['hits'])?>
                </tr>
                <?php
            }
            ?>
            </table>
            <?php
        }

Здесь мы вырезаем имя хоста из имени скрипта либо используем DOCUMENT_ROOT для chroot'ованных хостов.
Все скрипты моих сайтов лежат в /usr/home/HOST/
Для каждого хоста считаем статистику.

Экраном ниже изменяем начало цикла таким образом. Обратите внимание на измененный порядок строк.
        foreach ($entries as $i => $entry) {
            $name     = htmlspecialchars($entry['name']);
            if (!empty($_GET['prefix']) && strpos($name, $_GET['prefix']) !== 0)
            {
                continue;
            }
            echo "
            <tr ", $a->next(), ">";

Это фильтр таблицы по префиксу, переданному в $_GET['prefix']

Результат

Обновляем, и наслаждаемся статистикой по хостам


Самое интересное в последней колонке В ней примитивно посчитана эффективность занятой памяти, исходя из размера и количества запросов.
Скорее всего, вы увидите гораздо больший разброс значений. Моя таблица - уже после проведенной работы, в результате которой я выбросил некоторые толстые сайты без значимой посещаемости.

Как отключить кеширование ненужного?

Если вы отключите кеширование, то для скриптов будет генерироваться байткод при каждом запуске. И всё равно он будет исполняться быстрее, чем если бы он работал без акселератора.

Для отключения кеширования необходимо установить стандартную INI переменную
xcache.cacher = Off

Для отдельных хостов и файлов необходимо использовать следующие варианты
1. в php.ini вписать секцию для каждого хоста
[HOST=<host>]
xcache.cacher = Off

2. если у вас FCGI/FPM/5.3+, то в папку со скриптами положить файл .user.ini
xcache.cacher = Off

Кеширование будет отключено для всех скриптов, расположенных в этой папке и во всех уровнях ниже

3. если у вас Apache
<IfModule mod_php5.c>
  php_value xcache.cacher  Off
</IfModule>


Заключение

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

Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=33715