суббота, 30 октября 2010 г.

php Cacher

Опубликовал набор классов для кеширования:
http://github.com/valmat/Cacher
Опубликовано под лицензией
GPL v.3 http://www.gnu.org/licenses/gpl.txt
Т.е. свободно для использования и изменения. Разумеется, приветствуются любые исправления и дополнения.

Назначение


Мне нужен был очень простой, но в то же время мощный кеширующий модуль с понятной логикой. При этом он должен быть пригодным для работы на односерверном, но в тоже время нагруженном проекте.
Так же немаловажным моментом является возможность прозрачно менять стратегию кеширования в зависимости от текущего уровня нагрузки проекта.
Т.е.решение должно удовлетворять требованию изменять стратегию кеширования по мере роста нагрузки на проект и по мере изменения аппаратных возможностей (речь об ОЗУ) сервера.

Архитектура


Основными логическими единицами являются:
  • Cacher - фронтен к кеширующим классам.
  • Cacher_Backend - собственно сами кеширующие классы.
  • Слоты - кеширование и доступ к кешу осуществляется через слоты.
  • Теги - для упрощения управления кешем, и, главным образом, для переуеширования.
  • Типы кеширования - для прозрачного изменения стратегии кеширования. Т.е. конкретный кеширующий бекенд подключается только через слот (или тег), которые в свою очередь оперируют типами. Таким образом для изменения тратегии кеширования нужно всего лишь поменять привязку типов к бекендам.


Использование


class Cacher


Требует наличия классов унаследованных от Cacher_Backend - семейство классов, реализующих бэкэнд для класса Cacher
Все операции с кешем осуществляется на низшем уровне через тот или иной бекенд
Бэкэндом может быть файловая система, shared memory, memcache, Sqlite и другие системы кеширования
Для работы с классом представляются слоты и теги. Слоты реализованы в виде набора дружественных функций и неявно зашиты в интерфейс текущего класса

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

define AnyObj // может быть класс, массив или дрогой объект. На основании эого объекта слот функция вычислит ключь и, возможно другиие параметры (бэкэнд и время жизни).
Cacher::Slot('AniObj',AniObj); // Инициализируем слот кеширования. Первый параметр для определения имени слота, второй - наш объект

Получаем данные
if (false === ($CacheData = Cacher::get())) { // Если данные из кеша получить не удалось...
$CacheData = GetFromAnyExternal(); // Получаем данные из внешнего хранилища
Cacher::addTag(Cacher::newTag('AniTagData',AniTagDataObj)); // Создаем и сразуже добавляем новый тег к слоту перед сохрананеием в кеш
$tag2 = Cacher::newTag('AniTagData2',AniTagDataObj1) // Создаем новый тег
Cacher::addTag($tag2); // добавляем новый тег к слоту перед сохрананеием в кеш
Cacher::set($CacheData); // Кешируем данные
}
...
...
Если затем нужно сбросить какой нибудь тег, то нужно будет сделать так:
Cacher::newTag('AniTagData2',AniTagDataObj1)->clear() // Очищаем кеш тега

четверг, 28 октября 2010 г.

define vs const в php

Как известно, при разработке крупных веб приложений помимо архитектуры постоянно приходится задумываться так же и о производительности. Этим постом я хотел бы открыть серию постов по тестированию php на производительность.
Речь пойдет о сравнении способа хранения констант в приложении на php
А именно сравниваются два подхода:
define('CONST1', 'val11' );
define('CONST2', 'val12' );
define('CONST2', 'val13' );

и
class Consts{
 const CONST1 = 'val1';
 const CONST2 = 'val2';
 const CONST3 = 'val3';
}
 


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

Тест 1. Инициализация


Инициализируем 100 констант при помощи define
define('CACHER_TYPE_1', 'b60861c4492f88589429aab0c67abdd4' );
/*
      ...
   */
define('CACHER_TYPE_100', 'a66aedeafbc3f1e9fcbaa6a9e8060739' );


memory_start: 114.7578125Кб
time: 0.442981719971 ms
memory_finish: 120.8515625Кб
memory_diff: 6.09375Кб

$ab -n 1000 http://test/test/mem_class.php

Requests per second: 714.52 [#/sec] (mean)
Time per request: 1.400 [ms] (mean)


Теперь инициализируем через константы класса

class SlotType{
 const TYPE_CACHER_1 = 'b60861c4492f88589429aab0c67abdd4';
/*
      ...
   */
 const TYPE_CACHER_100 = 'a66aedeafbc3f1e9fcbaa6a9e8060739';
}

memory_start: 114.7578125Кб
time: 0.0340938568115 ms
memory_finish: 114.9921875Кб
memory_diff: 0.234375Кб

$ab -n 1000 http://test/test/mem_class.php

Requests per second: 818.27 [#/sec] (mean)
Time per request: 1.222 [ms] (mean)

Тест 2. Чтение


Считываем все константы определенные через define:
$var = CACHER_TYPE_1 . CACHER_TYPE_2 . /*...*/ . CACHER_TYPE_100;
time: 0.4 ms
memory_diff: 9.3Кб
ab -n1000:
Requests per second: 488.63 [#/sec] (mean)
Time per request: 2.047 [ms] (mean)

Считываем
$var = SlotType::TYPE_CACHER_1 . SlotType::TYPE_CACHER_2 . /*...*/ . SlotType::TYPE_CACHER_100;
time: 0.12 ms
memory_diff: 3.5Кб
ab -n1000:
Requests per second: 609.62 [#/sec] (mean)
Time per request: 1.640 [ms] (mean)

Вывод


Надо сказать, результат меня несколько удивил. Я ожидал, что по крайней мере скорость обработки с define будет выше. Оказывается Использование варианта
class Consts{
 const CONST1 = 'val1';
 const CONST2 = 'val2';
 const CONST3 = 'val3';
}
 

не только удобней, но и эффективней как по скорости исполнения, так и по расходу памяти.

среда, 27 октября 2010 г.

php Counter

Выложил на github.com свой класс Counter
В основном сделал это что бы потестить сам GitHub
Адрес страницы на гитхабе: http://github.com/valmat/MC_Counter
Как использовать:

class Counter
Это образец реализации счетчика на memcache
Можно построить другие реализации на общем интерфейсе
Сохранение результатов применения значений счетчика осуществляется по заданному числу.
Можно реализовать сохранение по заданному интервалу времени
*
Конструктор принимает три аргумента: ключ, имя слота, и идентификатор для инициализации слота.
Для чего это сделано: инримент счетчика должен быть очень быстрой операцией.
Не целесообразно тратить время и сстемные ресурсы на создание объетов, которые е будут использовны.
Поэтому передается только имя слот класа, который создается только в случае необходимости.
К таким случаям относитсяя обмен данными между локальным и постоянным хранилищем счтчика.
Слоты необхоимы, так как Counter не может знать о способе хранения данных в постоянном хранилище и путях доступа к ним.
Для предотвращения состаяния гонки, необходим механизм блокировок.
При наличии блокировки, процессы не получившие эксклюзивные права на получение данных будут писать во временное хранилище, а процесс,
установивший блокировку по окончанию своей работы инкриментирует счетчик данными из временного хранилища
*
При сбросе данных в постоянное хранилище по условию достежения кратности значения счетчика ($this->Val%$this->upd_delim),
блокировка не требуется, т.к. в этом случае (при достаточно большом значении $this->upd_delim) в текущий момент времени только один процесс
приходит к неоходимости сброса данных

Пример использования:
*
$cnt = new Counter('anykey', 'AnySlot',15);
echo $cnt->increment();
echo $cnt->get();
echo $cnt->set(11);

понедельник, 18 октября 2010 г.

Восстановление удаленных и поврежденных данных в Linux

Когда то давно, лет десять назад случалось мне отформатировать раздел жесткого диска под виндой. На диске была важная и нужная информация, поэтому встала задача данные восстановить. Помню путем продолжительного гугления были найдены несколько замечательных программ и кряков к ним. И данные были хоть и частично, но восстановлены. Назывались эти программы, вроде бы easy recovery, recover4all и какая то еще.
И вот на днях мне принесли жесткий диск с разделом, на который была поставлена винда по верх старой и вся нужная владельцу винта информация была благополучно потерта.
Поскольку сейчас винды у меня нет, то была выгуглена чудесная Линуксовая утилита под названием foremost
Вот, все таки, за что я люблю Линукс, это за лаконичность и изящность решений (ну и за логичность архитектуры, конечно).
Для восстановления данных потребовалась всего одна строчка в терминале:
#foremost -t jpg -o /dev/sdb1 -i ~/bak

Теперь по порядку, что к чему.

  • # - запускаем от root'а что бы не было проблем с чтением

  • -t - восстанавливаемых файлов. Можно написать -t all что бы восстановить файлы всех типов, либо одно из значений из списка: avi, bmp, dll, doc, exe, gif, htm, jar, jpg, mbd, mov, mpg, pdf, png, ppt, rar, rif, sdw, sx, sxc, sxi, sxw, vis, wav, wmv, xls, zip

  • -o /dev/sdb1 - здесь указываем раздел, который нужно сканировать. Поддерживаются разные файловые системы. Тот диск, который приносили мне был с ntfs.

  • -i ~/bak - куда складывать результат


Если запустить с опцией -t all, то будут созданы разные каталоги под каждый тип файлов, что само по себе очень удобно.
Я особо не вглядывался что он там на восстанавливал, но при беглом обзоре можно было заключить, что в своей массе почти все файлы были восстановлены корректно. Было несколько битых фотографий, но так ведь раздел был не пустой. Его не просто отформатировали но и успели по писать на него.
PS есть в репозитарии Ubuntu.
Т.е. установить можно так:
sudo apt-get install foremost