Что быстрее Memcache или file_get_contents()

fixxxer

К.О.
Партнер клуба
Да, согласен: для кэширования рантайм данных apc_fetch + serialize - это хорошо (пока влазит ;)). Про прирост я сравнительно с unserialize file_get_contents имел ввиду.

Include хорошо, если надо положить и забыть (как я говорил, при деплое - например, какие-нибудь автогенеренные маппинги).

Кстати, unserialize(file_get_contents) оказался чуточку быстрее чем unserialize(apc_fetch) на больших файлах.
Это явно vfs cache операционки помог :)
 

MiksIr

miksir@home:~$
> Вообще, я не то чтобы одобряю такой подход для кэширования данных
В случае, когда у нас нормальная база - это может быть более удобный вариант, чем надстраивать денормализованную базу. Но в общем это на совести конкретного архитектора все.
 

MiksIr

miksir@home:~$
>Include хорошо, если надо положить и забыть (как я говорил, при деплое - например, какие-нибудь автогенеренные маппинги).

А, ну это конечно самое оптимальное.
 

fixxxer

К.О.
Партнер клуба
> Вообще, я не то чтобы одобряю такой подход для кэширования данных
В случае, когда у нас нормальная база - это может быть более удобный вариант, чем надстраивать денормализованную базу. Но в общем это на совести конкретного архитектора все.
Не, я про файловый кэш в любом его виде (за исключением статики, отдаваемой напрямую веб-сервером, или частных случаев, типа компилируемых шаблонов а-ля Twig). То есть - если данные динамические, и нет заранее известного ограничения по числу файлов в ФС - нааафиг. Иначе , этот кэш подчищать - та еще задачка.

Можно, конечно, изобразить заранее преаллоцированные файлы фиксированного размера а-ля memcached slabs, hash индексы и LRU... Но это уже из разряда "идея хорошая, но требуется немедленный выдох" (с)fisher
 

MiksIr

miksir@home:~$
Это явно vfs cache операционки помог
Это понятно... но явно еще какая-то проблема... Вот....
unserialize(file_get_contents()): 7.5344958305359s
apc_fetch: 12.583029031754s
$memcache->get: 10.116214990616s (локальная машина, tcp/ip)
Это 1000 итераций среднего массива (2мб в памяти).
А вот с очень мелким массивом и 1м итераций все иначе - там, видимо, накладные у мемкеша высокие и он вообще загибается - 74 сек против 9 секунд apc
 

fixxxer

К.О.
Партнер клуба
unserialize(file_get_contents()): 7.5344958305359s
apc_fetch: 12.583029031754s
$memcache->get: 10.116214990616s (локальная машина, tcp/ip)
apc_fetch - оойй... А это последовательно или параллельно? Если параллельно - может там apc с блокировками жестит?
А покажи
Код:
php -i | grep ^apc\.
А вот с очень мелким массивом и 1м итераций все иначе - там, видимо, накладные у мемкеша высокие и он вообще загибается
А если бинарный протокол использовать? :)
 

MiksIr

miksir@home:~$
apc_fetch - оойй... А это последовательно или параллельно? Если параллельно - может там apc с блокировками жестит?
А покажи
Код:
php -i | grep ^apc\.
Последовательно.
Additional .ini files parsed => /etc/php.d/apc.ini,
apc
apc.cache_by_default => On => On
apc.canonicalize => On => On
apc.coredump_unmap => Off => Off
apc.enable_cli => On => On
apc.enabled => On => On
apc.file_md5 => Off => Off
apc.file_update_protection => 2 => 2
apc.filters => no value => no value
apc.gc_ttl => 3600 => 3600
apc.include_once_override => Off => Off
apc.lazy_classes => Off => Off
apc.lazy_functions => Off => Off
apc.max_file_size => 200M => 200M
apc.mmap_file_mask => no value => no value
apc.num_files_hint => 1000 => 1000
apc.preload_path => no value => no value
apc.report_autofilter => Off => Off
apc.rfc1867 => Off => Off
apc.rfc1867_freq => 0 => 0
apc.rfc1867_name => APC_UPLOAD_PROGRESS => APC_UPLOAD_PROGRESS
apc.rfc1867_prefix => upload_ => upload_
apc.rfc1867_ttl => 3600 => 3600
apc.serializer => default => default
apc.shm_segments => 1 => 1
apc.shm_size => 512M => 512M
apc.shm_strings_buffer => 4M => 4M
apc.slam_defense => On => On
apc.stat => Off => Off
apc.stat_ctime => Off => Off
apc.ttl => 0 => 0
apc.use_request_time => On => On
apc.user_entries_hint => 4096 => 4096
apc.user_ttl => 0 => 0
apc.write_lock => On => On

А если бинарный протокол использовать? :)
Что-то не заработал, лень щас разбираться
 

fixxxer

К.О.
Партнер клуба
Ммм. У меня примерно с той же хренью так получается

на средних
Код:
apc 10.95
file_get_c 13.46
mc 23.34
на в 10 раз больше но мелких
Код:
apc 0.62
file_get_c 3.04
mc 6.23
у тебя неправильный apc! :)

Что-то не заработал, лень щас разбираться
У меня тоже )
 

Фанат

oncle terrible
Команда форума
Опять сферическими конями в вакууме меряемся...
 
  • Like
Реакции: craz

fixxxer

К.О.
Партнер клуба
Чисто спортивный интерес. :)

Где-то в середине топика надо поместить

DISCLAIMER: ниже мы тут меряемся сферическими конями, серьезно не относиться!
upd: done
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
спасибо, поржал, а потом стало даже интересно
MiksIr, тесты покажи, я вылизываю PHPFileCache для yii, тоже немало гонял эти тесты
 

fixxxer

К.О.
Партнер клуба
grigori
кстати - насколько я понимаю, что ты делаешь (вроде ты говорил про cms для установки куда попало) - может, тебе эта идея и не совсем наркоманской покажется. ;) Про преаллоцированные файлики для кэшей, выровненные по 2^N и LRU. ;) Особенно если заранее знать, сколько места на хостинге можно под это скушать.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
да-да, читал только что, задумался :)
а зачем преаллоцировать файлы?
вообще, мне надо хранить в кеше мелочь: структуру базы для маппинга, соответствие ip региону,
а над реализацией LRU можно подумать
 

fixxxer

К.О.
Партнер клуба
а зачем преаллоцировать файлы?
С преаллоцированными легко (вроде =)) сделать LRU в виде кольцевого буфера. С динамическими я чото хз как это сделать O(1) или близко к тому
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
блин, я вообще не знаю эту тему, надо хоть почитать какие там алгоритмы и что такое кольцевой буфер :)
 

fixxxer

К.О.
Партнер клуба
большой оверхед по disk space будет в любом случае =)

тут уж выбирать - производительность или disk space waste
 

MiksIr

miksir@home:~$
Генерирую файлы
PHP:
<?php

$arr = array();
run($arr);
$in = "2";
file_put_contents($in.'test.php', '<?php $var='.preg_replace('/[\n\r\s\t]+/', '', var_export($arr, true)).';');
file_put_contents($in.'test2.php', serialize($arr));
file_put_contents($in.'test3.bin', igbinary_serialize($arr));

function run(&$arr, $level=0) {
  for($i=0;$i<rand(10,20);$i++) {
     if ($level == 3) {
        $arr[$i] = rand(1000,10000);
     } else {
       $arr[$i] = array();
       run($arr[$i],$level+1);
    }
  }
}
и запускаю тест
PHP:
<?php

$in = "2";
$it = 1000;

$a = memory_get_usage();
require("{$in}test.php");
echo "memory: ".((memory_get_usage()-$a)/1048576)."Mb\n\n";
unset($var);
$x = microtime(true);
for($i=0;$i<$it;$i++) {
  require("{$in}test.php");
//  unset($var);
}
echo "var_export: ".(microtime(true)-$x)."s\n";

$var = unserialize(file_get_contents("{$in}test2.php"));
unset($var);
$x = microtime(true);
for($i=0;$i<$it;$i++) {
  $var = unserialize(file_get_contents("{$in}test2.php"));
//  unset($var);
}
echo "unserialize: ".(microtime(true)-$x)."s\n";


$var = igbinary_unserialize(file_get_contents("{$in}test3.bin"));
unset($var);
$x = microtime(true);
for($i=0;$i<$it;$i++) {
  $var = igbinary_unserialize(file_get_contents("{$in}test3.bin"));
//  unset($var);
}
echo "igbinary_unserialize: ".(microtime(true)-$x)."s\n";


$var = file_get_contents("{$in}test2.php");
apc_store("test", $var=unserialize($var));
$x = microtime(true);
for($i=0;$i<$it;$i++) {
  $var = apc_fetch("test");
//  unset($var);
}
echo "mem apc: ".(microtime(true)-$x)."s\n";


$memcache = new Memcache();
$memcache->connect('localhost', 11211);
$var = file_get_contents("{$in}test2.php");
$memcache->set("test", $var=unserialize($var));
$x = microtime(true);
for($i=0;$i<$it;$i++) {
  $var = $memcache->get("test");
//  unset($var);
}
echo "memcache: ".(microtime(true)-$x)."s\n";
 

fixxxer

К.О.
Партнер клуба
лучше все таки несколько ключиков делать, и читать в цикле рандомный, будет чуть менее синтетический тест:)
 

~WR~

Новичок
Однажды попробовав, постоянно пользуюсь подобным файловым конфигом.

1). Генерируется из массивов через var_export.
2). Разбивается на небольшие кусочки по смыслу. Кусочки раскладываются по папкам.
3). Обязательно используется eAccelerator или аналоги.
4). Обязательно версионирование. Новый конфиг всегда кладется в новую папку со следующим порядковым номером. После полной успешной раскладки переключается симлинк.
5). Обязательно один раз в коде делаем realpath() и получаем реальный путь до текущей версии. Далее ходим только по нему.

Таким образом храним всё, что редко меняется, но очень часто запрашивается на чтение. Например, цены на услуги, всякие названия, списки.
Загружаем отдельные кусочки конфига только по запросу. Никаких file_exist() не делаем. Голый include() is good enough.

В результате имеем:
1). Ноль запросов к базе, ноль запросов к мемкешу, ноль коннектов к внешним сервисам.
2). Всегда можно откатиться на 1-2 версии назад, если что-то сломали.
3). Можно делать какую угодно схему базы и исходных данных. Всё равно с ними работает только backend и кеширующий скрипт.
4). Готовые конфиги легко прочитать невооруженным глазом.

В принципе, в некоторых случаях получается сделать странички с кучей переменного контента, которые ходят только в мемкеш за сессией пользователя и больше никуда. Performance, highload, все дела. :)
 
  • Like
Реакции: AmdY
Сверху