2009-04-16

Оптимизация Zend Framework Optimization

Сейчас я заканчиваю писать достаточно крупный проект на PHP. В основу положена Zend Framework.

Удачным образом выяснилось, что один клиент нагружает процессор сервера до 30% (сервер не первый в мире, но и не последний. Такая ситуёвина недопустима ни при каких обстоятельствах).

Вначале провёл стандартный просмотр кода "свежим" взглядом, выкинул лишнее.
Затем перечитал советы по оптимизации фреймвёрка.
Эффект был, но несущественный.

Потом провёл профайлинг при помощи XDebug (у меня в Висте он склонен ронять Apache) и WinCacheGrind (в нём удобно анализировать результат). Больше всего смотрел на поле "Total Self".
И выяснилось, что уйму времени берёт парсинг локали. Это лечится так: http://framework.zend.com/manual/en/zend.locale.html#zend.locale.cache.
Но большого эффекта это не дало. Вместо локали на первое место вылезла уйма операций чтения файлов (кеш файловый, так надо), и нагрузка осталась примерно такой же. Выяснилось, что каждый раз, когда запрашивается кеш, идёт по два запроса к файловой системе (is_file и fopen). При этом суммарный объём кеша не такой уж и большой.

Решение было такое:
  1. в класс Zend_Cache_Backend_File добавил
    private static $FILE_CACHE = array();
  2. в методе _fileGetContents в самое начало добавил
    if (isset(self::$FILE_CACHE[$file]) && self::$FILE_CACHE[$file]) {
    return self::$FILE_CACHE[$file];
    }
  3. перед return этого метода добавил
    self::$FILE_CACHE[$file] = $result;
И это дало замечательный результат

Не знаю, насколько это решение универсально. Планирую поделиться этим опытом с создателями Zend Framework, и, может быть, они согласятся с ним или укажут на недостатки или предложат альтернативы.



Currently I am finishing writing quite a major project in PHP. It is based on Zend Framework.

A good way it turned out that one client can load server processor by up to 30% (the server is not the first in the world, but not the last. In any case, this is unacceptable).

Firstly, I did a code review, threw out something.
Then I reviewed once more optimization tips of the framework.
The effect was, but it was not enough.

After that I did a profiling with XDebug (on my Vista, it tends to drop Apache) and WinCacheGrind (it is convenient to analyze the results). Mostly I looked at the column "Total Self".
And it turned out that parsing a locale takes a lot of resources. This is treated that way: http://framework.zend.com/manual/en/zend.locale.html#zend.locale.cache.
However, there was no effect. Instead of the locale, resources were spent to lots of file readings (the cache stores data in files. It cannot be changed), and the load remained approximately the same. It turned out that every time the cache is requested, there are two requests to the file system (is_file and fopen). The total size of cache is not so great.

The solution was the following:
1. in class Zend_Cache_Backend_File I added
private static $ FILE_CACHE = array ();
2. in method _fileGetContents I added at the very beginning
if (isset (self:: $ FILE_CACHE [$ file]) & & self:: $ FILE_CACHE [$ file])) {
return self:: $ FILE_CACHE [$ file];
}
3. before the return of this method I added
self:: $ FILE_CACHE [$ file] = $ result;
And it had a remarkable result!

I do not know how universal is this solution. I am going to share this experience with the founders of Zend Framework, and maybe they agree with it or point to the shortcomings or suggest alternatives.

Web-optimizator

У одного клиента возникла жалоба, что сайт медленно перезагружается. А перезагрузок требуется много. Решением явился Web-optimizator.

Эта вещь делает много клиентской оптимизации на сервере (минимизирует и архивирует отсылаемые данные, устанавливает правильные заголовки и т.д.). Если воспользоваться YSlow, то станет видно, что всё, кроме CDNа получает оценку А (заголовок Expires не ставится только на саму страницу, за это Б).

У меня была идея по улучшению и желание помочь, так что теперь я в числе разработчиков. Это один из первых моих вкладов в мир открытых кодов :-)



One customer complained the site became slow to refresh. But a lot of reloads is required. The solution was a Web Optimizer.

This library makes a lot of optimization for the client side on the server (it minimizes and gZips the data sent, sets the correct headers, etc.). If you use YSlow, it becomes clear that all but CDNa receives a mark of A (Expires header is not set for the page itself, that's why it is B).

I had the idea for the improvement and desire to help, so now I am one of the developers. This is one of my first contributions to the world of open source :-)