Sphinx query log parser – анализ query performance

Posted in Sphinx Search, Tips And Tricks on June 2nd, 2010 by Yaroslav Vorozhko – Be the first to comment

Написал простой скриптик на awk для парсинга Sphinx query.log файла.

Парсинг всего файла:

CODE:
  1. awk '{ s += $6 } END { print "seconds: ", s, " average: ", s/NR, " queries: ", NR }' query.log

Парсинг за конкретный период, например за второе Июня:

CODE:
  1. awk '{ if($2=="Jun" && $3==2) {s += $6; r++} } END {print "total seconds: ", s, "average: ", s/r, " total queries: ", r}' query.log

В приведенных скриптах $N - это номер строки в лог файле.

NR - это общее количество записей в файле разделенных переводом строки.

Пример лог файла:

[Wed Jun  2 11:20:52.379 2010] 0.002 sec [ext2/0/rel 2024 (0,10)] [wordpress] spectrum
[Wed Jun  2 11:20:52.384 2010] 0.003 sec [ext2/0/rel 2 (0,1000) @post_type] [wordpress] spectrum
[Wed Jun  2 11:20:52.709 2010] 0.002 sec [ext2/0/rel 963 (0,10)] [wordpress] tin
[Wed Jun  2 11:20:52.713 2010] 0.002 sec [ext2/0/rel 2 (0,1000) @post_type] [wordpress] tin
[Wed Jun  2 11:20:52.997 2010] 0.003 sec [ext2/0/rel 1154 (0,10)] [wordpress] xi
[Wed Jun  2 11:20:53.004 2010] 0.004 sec [ext2/0/rel 2 (0,1000) @post_type] [wordpress] xi
[Wed Jun  2 11:20:53.029 2010] 0.003 sec [ext2/0/rel 1945 (0,10)] [wordpress] nasa
[Wed Jun  2 11:20:53.035 2010] 0.003 sec [ext2/0/rel 2 (0,1000) @post_type] [wordpress] nasa
[Wed Jun  2 11:21:09.359 2010] 0.005 sec [ext2/0/rel 22308 (0,10)] [wordpress] september

На выводе получится:

seconds:  566.738  average:  0.00948642  queries:  59742

Надеюсь это краткое описание языка awk поможет вам написать парсер для своих лог файлов.

Спасибо!

Как увеличить скорость процесса индексации Sphinx Search

Posted in Development, Sphinx Search on May 12th, 2010 by Yaroslav Vorozhko – 2 Comments

Индексирование - это одна из двух важных операций выполняемых Sphinx Search (далее Sphinx). Если учитывать, что индексирование миллиона документов может занять от 20-30 минут на среднем сервере, то можно сказать, что индексирование одна из самых важных операций, которую стоит продумать очень тщательно.

Почему надо оптимизировать скорость индексации документов?

  1. Индексация очень “тяжелый” процесс для системы, каждый раз когда выполняется индексация, система использует много CPU и IO ресурсов
  2. Переиндексирование и объединение (merge) индексов занимает вдвое больше места на диске, чем объем всего индекса
  3. Индексирование замедляет выполнение других задач, например поиска по документам или выполнение sql запросов
  4. Загруженная система “тормозит” работу веб сайта, а из-за этого сайт теряет часть своих пользователей.

В этой статье вы узнаете как избежать всех выше перечисленных проблем.

Источник данных

Sphinx поддерживает два SQL источника данных - это MySQL и PostgreSQL. Sphinx работает таким образом, что на основе слов из источника данных формирует индекс, который любит очень разрастаться в размере и занимать все дисковое пространство и память.

Не будем останавливаться на оптимизации баз данных, а скажу одно, проверьте, что sql запросы, которые будут выбирать данные для индекса - работаю быстро. Это можно сделать с помощью команды sql EXPLAIN. Если же вас все таки не устраивает производительность вашей баз данных, то за дополнительными советами вы можете обратиться на сайт www.mysqlperformanceblog.com.

Итак, первое правило такое: индексируйте только те поля таблиц, по которым собираетесь выполнять поиск. Например не стоит включать в индекс большие текстовые поля, если по ним не будет поиска. Особенно это важно, если вы используете Sphinx не как полнотекстовый поиск, а как key-value базу данных.

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

Третье правило: разбивайте большие индексы на более мелкие в соответствии какому либо критерию. Например, год можно разбить по кварталам и уменьшить индекс в 4 раза. Если вам известна, какая категория товаров в какое время была добавлена, то вы можете производить поиск, только в одном из четырех индексов, а для поиска по всем данным, можно использовать распределенный индекс, который будет включать все четыре квартальных индекса. Прежде чем решить какую схему использовать с одним монолитным индексом или четырьмя распределенными, проверьте запросы которые вы будете выполнять к sphinx. Если большинство запросов потребует использование индекса за весь год, то возможно вам и не стоит разбивать индекс по кварталам. Смотрите ниже как может повлиять использование распределенных индексов на общую производительность запросов.

Четвертое правило: используйте ranged (ограниченные) запросы по количеству выбираемых записей. Это уменьшит нагрузку на sphinx и на базу данных.

Аттрибуиты

Каждый атрибут по умолчанию занимает 32 или 64 бита, и учитывая, что обычно Sphinx используется для индексирования по меньшей мере миллионов документов, то в Sphinx была предусмотрена возможность задавать определенный размер для атрибута.

Пятое правило: ограничивайте длину атрибуту битовой маской, там где это возможно. Например количество стран не превышает размера в 16 бит, поэтому такой атрибут стоит ограничить 2 байтами. А это уменьшит размер атрибута в 2 раза на 32 битной платформе и в 4 раза на 64 битной, что в свою очередь существенно уменьшит общий размер индекса. Конечно, лучшим вариантом будет ограничить каждый атрибут с минимальным запасом длины. Но, в таком случае, незабывайте периодически проверять атрибуты, чтоб неожиданно не выйти за пределы размера атрибута.

Распределенные (distributed) индексы

Про распределенные индексы вы должны знать, что скорость работы такого индекса зависит от скорости самого медленного агента. В большой системе с тысячами индексов, десятками sphinx агентами и несколькими серверами тяжело обнаружить проблему “медленного агента”. Но, как показала практика, всегда найдется какой нибудь перезагруженный sphinx агент, который замедляет 20% всех запросов. Избежать этой проблемы можно с помощью регулярного поэтапно тестирования каждого агента и переноса нагрузки на других агентов. Много информации про скорость выполнения запросов вы можете получить исследуя логи shpinx.

Поэтому шестое правило следующее: регулярно тестируйте sphinx запросы и анализируйте логи.

Конфигурационные параметры индексера

При переиндексации, опция inplace_enable позволяет уменьшить вдвое требуемое дисковое пространство при переиндексации. Но, с другой стороны включение этой опции замедлит производительности индексации на 5-10%. Эта опция будет полезна на серверах с очень ограниченным количеством дискового пространства, правда при потере производительности индексации. По умолчанию опция отключена и следует заметить, что она влияет только на indexer не затрагивая никоим образом searchd.

С помощью mem_limit можно контролировать количество выделяемой оперативной памяти для индексации. Наиболее оптимальным вариантом будет установка от 256Mb до 1024Mb. Слишком низкие значения могут привести к ухудшению скорорсти индексации. Слишком высокие могут привести к timeout с MySQL базой. Так как буффер пул необходимо будет обработать большой, то возможна потеря соединения. По умолчанию данный параметр равен 32Mb. Максимальное значение 2047Mb.

Опция max_iops влияет на количество I/O(read, write) операций работы с диском в секунду. Если во время индексации, производительность поиска существенно уменьшается, то стоит подумать о настройке max_iops. По умолчанию данная опция имеет значение 0, т.е. неограничено (unlimited). Также стоит обратить внимание на опцию max_iosize, которая позволяет установить размер буфера чтения/записи при индексации. По умолчанию эта опция равна 0, т.е. размер буфера не ограничен. С помощью утилиты fio вы можете вычислить количество I/O операций в секунду, а также узнать размер I/O кеша. После того как вы определили характеристики вашего диска, попытайтесь потестировать indexer и searchd с разными настройками max_iops и max_iosize.

Вывод

  • Формируйте свой основной sql запрос (sql_query) грамотно.
  • Не включайте все поля сразу, а выбирайте только те, которые будете использовать.
  • Используйте условия (where) в sql выборке, чтоб не перегружать индекс ненужными данными.
  • Разбивайте большие монолитные индексы, на более мелкие в соответствии какому либо критерию, например по кварталу или году.
  • Используйте возможность пошаговой выборки (ranged queries), это уменьшит вероятность блокировки базы данных на время выборки.
  • Ограничивайте короткие атрибуты битовой маской.
  • Тестируйте sphinx запросы и анализируйте логи.

Создание простого доступа к ресурсам из ZF контроллера

Posted in PHP, Tips And Tricks, ZendFramework on March 22nd, 2010 by Yaroslav Vorozhko – 2 Comments

Было бы очень хорошо иметь возможность доступа к загружаемым в bootstrap ресурсам из контроллеров приложения. Например, я хотел бы получить доступ к "DB" ресурсу из контроллера следующим образом $this->db;
Для этого напишем Action Helper, который будет загружать определенные ресурсы в контроллер приложения:

CODE:
  1. class My_ResourceInjector extends Zend_Controller_Action_Helper_Abstract
  2. {
  3.     protected $_resources;
  4.  
  5.     public function __construct(array $resources = array())
  6.     {
  7.         $this->_resources = $resources;
  8.     }
  9.  
  10.     public function preDispatch()
  11.     {
  12.         $bootstrap  = $this->getBootstrap();
  13.         $controller = $this->getActionController();
  14.         foreach ($this->_resources as $name) {
  15.             if ($bootstrap->hasResource($name)) {
  16.                 $controller->$name = $bootstrap->getResource($name);
  17.             }
  18.         }
  19.     }
  20.  
  21.     public function getBootstrap()
  22.     {
  23.         return $this->getFrontController()->getParam('bootstrap');
  24.     }
  25. }

и инициализируем его в bootstrap:

CODE:
  1. class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
  2. {
  3.     protected function _initResourceInjector()
  4.     {
  5.         Zend_Controller_Action_HelperBroker::addHelper(
  6.             new My_ResourceInjector(array(
  7.                 'db',
  8.                 'layout',
  9.                 'navigation',
  10.             ));
  11.         );
  12.     }
  13. }

Код выше, создаст ссылки на ресурсы: db, layout и navigation. Это значит, что теперь вы можете получить к ним прямой доступ из контроллеров.

CODE:
  1. class FooController extends Zend_Controller_Action
  2. {
  3.     public function barAction()
  4.     {
  5.         $this->layout->disableLayout();
  6.         $model = $this->getModel();
  7.         $model->setDbAdapter($this->db);
  8.         $this->view->assign(
  9.             'model'      => $this->model,
  10.             'navigation' => $this->navigation,
  11.         );
  12.     }
  13.  
  14.     // ...
  15. }

Этото решение ведет к некоторому упрощению - теперь нет необходимости вытягивать bootstrap из объекта инициализации, а потом вытягивать ресурс.
Но, у этого решения есть несколько проблем: Откуда мы знаем, какие ресурсы были связаны с контроллером? Как мы можем это контролировать?
Отсюда, вытекает решение создать пул необходимых ресурсов для контроллера.
read more »

Настраиваем PHPUnit тесты в Zend Framework 1.10

Posted in Development, PHP, Testing, ZendFramework on February 9th, 2010 by Yaroslav Vorozhko – 4 Comments

В документации к Zend Framework есть описание как создавать PHPUnit тесты для контроллеров и для баз данных. Но, к сожалению они не объясняют как настроить приложения для выполнения Unit тестов.
В данной статье приведены шаги по настройке Unit тестов:
1. Установка phpunit
2. Установка xdebug
3. Настройка phpunit.xml
4. Создание TestHelper.php для инициализации приложения
5. Написание и выполнение простого теста

В первую очередь для выполнения тестов нам понадобится phpunit, который можео установить из PEAR пакета PHPUnit.

CODE:
  1. $ pear channel-discover pear.phpunit.de
  2. $ pear config-set preferred_state alpha
  3. $ pear install phpunit/PHPUnit
  4. or you may wish to install all the optional supporting packages:
  5. $ nano /usr/local/php5/etc/php.ini  // memory_limit = 32M; change this to at least 32M
  6. // if you get a permission denied error on the ZF community server, send an email to fw-servers mail list
  7. $ pear install --alldeps  phpunit/PHPUnit

Следующим шагом установим xdebug. Xdebug мы будем использовать для проверки покрытие кода тестами.

CODE:
  1. $ pecl install xdebug-beta

Теперь откройте ваш php.ini файл и пропишите загрузку xdebug.

CODE:
  1. zend_extension=/usr/lib/..../..../php5/20060613/xdebug.so

read more »

Ускоряем PHP с HipHop

Posted in HipHop, PHP, Performance on February 4th, 2010 by Yaroslav Vorozhko – 1 Comment

Сегодня Facebook анонсировал релиз HipHop.

Коротко, что такое HipHop для PHP:

  • HipHop - это компилятор кода PHP в C++. Т.е. он преобразует PHP код в C++ код для дальнейшей компиляции. Это не другой язык. И это не компилятор времени исполнения (JIT).
  • HipHop будет выпущен Facebook под opensource лицензией, под такой же как и основной код PHP. Facebook возлагает надежды, что разработчики улучшать HipHop и расширят его функциональность, таким образом HipHop сможет заменить больший набор функций PHP.
  • HipHop был одним из проектов в Facebook по улучшению его производительности. Все таки Facebook, второй сайт по объему траффика в интерент и в основном построенный на PHP. HipHop запущен на большинстве LAMP PHP серверах Facebook и в среднем улучшил производительность этих серверов в два раза.
  • HipHop достигает этого, путем исследования вашего PHP приложения и на его основе строить C++ проект. C++ проект потом компилируется и запускается на собственном веб серврере. Это дает возможность исключить PHP Zend engine и Apache из цепочки.
  • Учитывая что, некоторые возможности PHP не поддерживаются. Также, дополнения к PHP написанные на C, должны быть переписаны в HipHop C++ дополнения.
  • Преимущества в скороости HipHop достигаются благодаря статическому анализу, который парсит ваш PHP код ищя пути преобразования динамических частей в статические.
    Учитывая это, ваше улучшение производительности, может сильно варьроваться - более структурированный код получить наибольший прирост в производительности.

Что значит HipHop для вас:

  • Если ваш проект использует sharing хостинг - то ничего.
  • Если ваш проект использует 2 или менее серверов - то ничего.
  • Если у вас нет выделенного development и deployment окружения и у вас нет разработчика знающего C++ - то ничего.
  • Если вы разработчик open source приложения - то немного.
  • Если вы shared хостинг компания - то немного.
  • Если PHP не bottleneck вашего приложения - то пока еще ничего.
  • Если ваше приложения использует много серверов, и в основном на них работает PHP, а также у вас есть все исходники PHP кода, у вас есть немного знаний C/C++, тогджа ответ возможно.
  • Если вы разрабатываете php framework, то ответ иногда.
  • Если у вас есть сильно-связанные части архитектуры, которые удовлетворяют требованиям выше и эти части слабо связаны (через API) с остальной системой, то ответ много что.
  • Если вы обдумываете какой язык выбрать для реализации вашей системы, то ответ очень много.
  • Если вы обдумываете аргумент, переписать весь сайт на другой язык, то вы потеряли свой аргумент.

Есть очень много языковы возможностей, хороших или плохих, которые PHP должен поддерживать, а HipHop нет. Потому как HipHop уникальное решение, он никгода не заменит Zend Engine.

Статья является частичным переводом статьи Terry Chay Faster PHP fo shizzle—HipHop for PHP

В конце марта 2010 г. в Санкт-Петербурге пройдет первая в России конференция по Zend Framework

Posted in Events on February 1st, 2010 by Yaroslav Vorozhko – Be the first to comment

На днях закончился прием тезисов по планируемым докладам. Примечательно, что в состав докладчиков вошли ведущие участники русскоязычного сообщества ZF, опытнейшие специалисты и лично один из создателей фрэймворка!

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

Каждый предстоящий доклад возможно обсудить на форуме ZF-сообщества. Ваше мнение очень важно для авторов!

Планируемые доклады

Жизненный цикл предложений (proposals) в проекте Zend Framework

Александр Веремьев (Zend Technologies, Zend Framework Core команда)

Zend_Search_Lucene в деталях

Александр Веремьев (Zend Technologies, Zend Framework Core команда)

Zend Framework и производительность

Александр Махомет (создатель сообщества ZendFramework.ru)

Zend Framework и MVC, «толстая» модель

Александр Стешенко (Norada Corporation, PHP-разработчик)

ФотоСтрана.ru: Прототипирование с использованием ZF (история боевого применения Zend Framework в highload-проекте)

Леонид Жаворонков (ФотоСтрана.ru, тимлид)

Использование очередей сообщений в повседневных проектах

Денис Баклыков (Обновление, веб-разработчик)

Zend Framework и Doctrine

Степан Танасийчук (руководитель веб-студии stfalcon.com)

Zend Framework и мультиязычность

Степан Танасийчук (руководитель веб-студии stfalcon.com)

История проекта e-Штаб

Анатолий Ларин (e-Легион, веб-программист)

Что нового несет нам Zend Framework 2.0?

Надежда Блинова (Wizartech, веб-программист), Георгий Туревич (Wizartech, ведущий веб-программист)

Интеграция Zend Framework c Javascript-фрэймворками jQuery и Dojo Toolkit

Георгий Туревич (Wizartech, ведущий веб-программист)

Смело обсуждайте доклады и регистрируйтесь!

За последними новостями можно следить здесь:
RSS-канал: feeds.feedburner.com/zfconf
Twitter: @zfconf
Группа Вконтакте: vkontakte.ru/club14951507

К участию также приглашаются информационные и финансовые спонсоры.

IE7 не показывает скрытый html после удаления CSS класса который его скрывал с помощью jQuery

Posted in Development, Javascript, Tips And Tricks on December 24th, 2009 by Yaroslav Vorozhko – 1 Comment

Проблема

У IE7 и IE6 есть такая особенность, что когда вы удалете класс, который скрывал (display:none) содержимое строки таблицы (тег tr) с помощью jQuery метода removeClass(), то сожержимое строки таблицы (тег tr) все равно не будет отображаться.

Пример

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

CODE:
  1. <table>
  2. <tr>
  3.     <td>Your name: </td>
  4.     <td><input type="text" name='name'></td>
  5. </tr>
  6. <tr>
  7.     <td>Your email: </td>
  8.     <td><input type="text" name='email'></td>
  9. </tr>
  10. <tr>
  11.     <td colspan='2'><a href="javascript:void(0);" onClick="showAdvFields();" id="showAdvFields">+ Show advanced options</a></td>
  12. </tr>
  13. <tr class='hide'>
  14.     <td>Your twitter: </td>
  15.     <td><input type="text" name='twitter'></td>
  16. </tr>
  17. <tr>
  18.     <td></td>
  19.     <td><input type="submit" value='Submit'></td>
  20. </tr>
  21. </table>
  22.  
  23. <scripty type="text/javascript">
  24. //$j - это ссылка на jQuery.
  25. function showAdvFields()
  26. {
  27.     if ($j("tr").hasClass('hide')){
  28.         $j("tr.hide").addClass('showAdv');
  29.         $j("tr.hide").removeClass('hide');
  30.         $j("#showAdvFields").html(" - Hide advanced options");
  31.        
  32.     } else {
  33.         $j("tr.showAdv").addClass('hide');
  34.         $j("tr.showAdv").removeClass('showAdv');
  35.         $j("#showAdvFields").html(" + Show advanced options");
  36.     }
  37. }
  38. </script>

Решение

Во первых перестаньте использовать барузер Internet Explorere и переходите на FireFox и Google Chrome :). А если у вас нет выбора, то решение использовать функцию jQuery show, которая решает проблему совместимости с IE.
Вот так я изменил метод показа и скрытия строки таблицы.

CODE:
  1. function showAdvFields()
  2. {
  3.     if ($j("tr").hasClass('hide')){
  4.         $j("tr.hide").addClass('showAdv');
  5.         $j("tr.hide").show();
  6.         $j("tr.hide").removeClass('hide');
  7.         $j("#showAdvFields").html(" - Hide advanced options");
  8.        
  9.     } else {
  10.         $j("tr.showAdv").addClass('hide');
  11.         $j("tr.showAdv").hide();
  12.         $j("tr.showAdv").removeClass('showAdv');
  13.         $j("#showAdvFields").html(" + Show advanced options");
  14.     }
  15. }

Вывод

Не используйте доморощенные решения, читайте документацию и используйте стандартные методы. Я добавил вызов $j("tr.hide").show(), что помогло решить проблему показа и вызвов $j("tr.showAdv").hide() что решило проблему скрытия строки.

Можно конечно обойтись и без класса hide, но такое решения было очень практично.