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.

Комментариев нет: