Кешировать данные в файлах

Этот пост только для PHP-программеров. Остальным он будет непонятен.

В ObjectNuke используется схема дискового кеширования некоторых SQL-запросов. Я решил проверить эффективность этой схемы на различных масштабах.

Дело в том, что все проекты нашей фирмы работают на ReiserFS, которая сама по сути является БД с индексированием доступа к файлам. Поэтому у меня и встал вопрос: что эффективнее: один запрос к MySQL или одно считывание файла под ReiserFS?

Итак, я создал таблицу:

CREATE TABLE `skorost` (
`guid` bigint(20) unsigned NOT NULL default ‘0’,
`datatext` char(255) NOT NULL default ”,
`minitext` char(255) NOT NULL default ”,
`date` datetime NOT NULL default ‘0000-00-00 00:00:00′,
`size` bigint(20) unsigned NOT NULL default ‘1’,
PRIMARY KEY (`guid`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251

Потом заполнил её и дисковый кэш вот этим скриптом:

chdir(dirname(realpath($_SERVER['PHP_SELF'])));

require ‘../conf/config.conf';
require_core(‘Sqlfunc.lib’);

$conn = &getADO();

for ($i=0; $i < 1000000; $i++)
{
$sSql = ‘INSERT INTO answer(guid, datatext, minitext, date) VALUES (‘.$i.’, “‘.$i.'”, “‘.$i.'”, NOW())';
$conn->Execute($sSql);
if ($i % 10000 ==0) echo $i.”n”;
dcache::set(‘values’, $i, $sSql);
}

А потом тестировал время исполнения скриптов последовательного считывания всех значений из кэша и из БД (MySQL 4.1).

time ./test_reiser.php
time ./test_sql.php

Число элементов Время ReiserFS 3.6 (опции BORDER, SMALL_TAILS), секунды MySql 4.1, секунды
1000 real 0.112 0,16
user 0.084 0,11
system 0.028 0,02
100000 real 5,75 8,11
user 2,48 2,54
system 3,11 0,96
1000000 real 104 75,87
user 25,67 24
system 62,88 8
1000000 (не дефрагментированный результат) real 96,92 74,78
user 25,89 23,94
system 63,11 8,86

Когда тестировался миллион элементов MySQL-база данных занимала 535 мегабайт, а индекс около 12 мегабайт. И то и другое помещалось в кэше. По данным df папка с файлами занимала 211 мб. А по данным du папка с файлами занимала 4,3 гб. Вот как эффективно умеет упаковывать маленькие файлы ReiserFS!

Выводы: Даже до тех пор пока число кешируемых элементов относительно велико (до сотни тысяч), имеет смысл использовать дисковое кэширование. Только в сервисах, где речь идёт о миллионах кешируемых элементов, начинает выигрывать MySql, да и то, если кэшируется результат всего одного запроса.

Нужно учесть следующие моменты:

  1. Лучше всего дисковое кеширование использовать, когда кешируется результат одного сложного или нескольких простых запросов. Причём кэшировать желательно уже сгенерированные куски HTML. А иначе загрузка CPU может повысится.
  2. Для большинства сайтов оно будет эффективно даже для одного запроса, так как у очень редких сайтов число кешируемых элементов более десяти тысяч.
  3. Если диск сильно дефрагментирован, то эффективность дискового кеширования снижается примерно на 10%, на скорость работы MySql это практически не влияет. Т.е. имеет смысл выделять отдельный диск или RAM-диск для папки дискового кеша.

Почему же при миллионе элементов MySql опередила ReiserFS? Если присмотреться к таблице то видно, что при 100 000 запросах время, которое ушло у ReiserFS на работу с файлами составило 3,11 секунды, а при 1 миллионе уже 62 секунды. Запросов увеличилось в 10 раз, а время в 20. Очевидно, что собака зарыта здесь. Видимо если в папке от 500 тысяч файлов, то эффективность работы ReiserFS падает.

Т.е. если разбивать кешируемые элементы по разным папкам (пространствам в терминах ObjectNuke), то, наверное, ReiserFS может выиграть по скорости и при миллионе элементов.

Запись опубликована в рубрике интернет, стартап. Добавьте в закладки постоянную ссылку.