Профилирование и оптимизация
фреймворков высоконагруженных систем
            на примере Zend Framework




                         Цехановский Сергей
                                      IT 2.0
Сравнительный анализ производительности
                                         фреймворков



req/s




        Yii                     Cod                     K oh            Zen             Cak        Sym
              Fra                     eI g                  ana             d   Fra        e PH          fon
                    me                       nite                 PH               me          P               y
                      wo                            r               P                 wo
                           rk                                                           rk
Цель профилирования - выловить узкие места


            1. Xdebug

                       Временной отчет о                 Просмотр в
   Xdebug             процессе выполнения           удобочитаемом виде
                           сценариев                  в WinCacheGrind

2. Отлавливание                    3. FirePHP
медленных SQL-запросов
 Логирование SQL запросов на
                                                            Наглядное
       стороне сервера
                                    Интеграция в          отслеживание
                                     ZF с FirePHP         SQL запросов в
                                                              FireFox
            Отчет
Оптимизация: уровень сервера




• Добавление индексов для непроиндексированных полей БД


• Кэширование байт-кода
                            $role = 0;                                           0101001001010010100100101101
                                                                                 0100101010100101001010100101
   1. APC
                            $hasCard= false;
                            $cardAlready = false;                                1010010101101001010010010100
                            $tblUserRoles->delete('UserId = ' . $UserId);        0100101010100101011011010110
                            foreach ($objRoles as $objRole) {                    1010111010111101101100101011
   2. eAccelerator          if (isset($formData[$objRole->RoleId]) &&
                            $formData[$objRole->RoleId]) {
                            if ($objRole->RoleId == 8) $hasCard = true;
                                                                                 0010111111110100101001010100
                                                                                 1010100101010010000001010101
                            if ($objRole->RoleId == 13)$cardAlready = true;      0101101010101001011100101011

   3. xCache                $objUserRole = $tblUserRoles->createRow();
                            $objUserRole->RoleId = $objRole->RoleId;
                            $objUserRole->UserId = $UserId;
                                                                                 0100101010101011111101011010
                                                                                 1110101111011011001010110010
                                                                                 1111111101001010010101001010
                            $objUserRole->CreateDate = date('Y-m-d H:i:s');      1001010100100000010101010101
                            $objUserRole->CreateBy = Zend_Auth::getInstance()-   1010101010010111001010110100
                            >getIdentity()->UserId;
                            $objUserRole->save();                                1010010101101001010101010111
                            $role = $objRole->RoleId;                            1110101101010101111110101101
                            }                                                    111110101101
Оптимизация: уровень сервера
Оптимизация: уровень приложения




 Zend_Cache
                                    ранение кэша в
                                       памяти с
                                     применением
                                      Memcached
. Кэширование структуры таблиц
                                        ранение
. Кэширование информации            кэшированных
                                    фрагментов на
                                  диске в виде файлов
Оптимизация: уровень приложения




Объединение классов
                               lass 1       lass 2       lass n

. Накопительная сборка всех
используемых классов Zend в             lass 1 Class 2
один php-файл
                                            lass 3

. Накопительная сборка всех
классов, наследуемых от ZF в                lass n
один файл
Оптимизация: сборщик классов


                                     spl_autoload_register('__autoload');
               начало($str)          register_shutdown_function('__autoload');


                 $str пустое        нет                      Класс          да


                     ?                                    определён?

                           да                                     нет
                                                                                                конец
                                                     Пробуем инклудить по
Берем список классов ZF, открываем каждый
                                                         имени ($str).
файл и сливаем его содержимое в один файл                                                Пробуем определить

                                                                                           путь к классу по
                                                           Удалось               нет
  Берем список пользовательских классов,                                                       имени
                                                              ?
  открываем каждый файл и сливаем его                             да

                                                                                                                 нет
         содержимое в один файл                    Записываем в очередь на
                                                                                              удалось?
                                                     добавление в список
                                                                                                     да
                  конец                            пользовательских классов
                                                                                       Записываем в очередь на

                                                                                         добавление в список

                                                                                              классов ZF
Оптимизация: файл конфигурации



Zend/Application.php
public function __construct($environment, $options = null)
{
$this->_environment = (string) $environment;
require_once 'Zend/Loader/Autoloader.php';
$this->_autoloader = Zend_Loader_Autoloader::getInstance();
if (null !== $options) {
                  $session = new Zend_Session_Namespace('iniconf');
                  if (!$sessOptions = $session->arrConfig) {
                  if (is_string($options)) {
                  $options = $this->_loadConfig($options);
                  $session->config = $options;
                  Zend_Registry::set('conf', $options);
                  $options=$options->toArray();
                  $session->arrConfig = $options;
               } elseif ($options instanceof Zend_Config) {
               $options = $options->toArray();
               } elseif (!is_array($options)) {
               throw new Zend_Application_Exception('Invalid options provided; must be location of config file, a config object, or an array');
               }
               } else {
               Zend_Registry::set('conf', $session->config);
               $options = $sessOptions;
               }
               $this->setOptions($options); }
}
Оптимизация: инициализация модулей



Zend/Application/Resource/Modules.php ф-ия init()
$uri = $_SERVER['REQUEST_URI'];

$ar = explode('/', $uri);
$mdl = (''!=$ar[1]) ? $ar[1]:'default';

foreach ($modules as $module => $moduleDirectory) {
if ($mdl == $module) {
                                                      одуль 1   одуль 2   одуль n
…………………………………………
}                                                                ласс
}




                                                      одуль 1   одуль 2   одуль n
                                                                 ласс
Оптимизация: генерация пути



ZendControllerActionHelperViewRenderer.php, initView
if (empty($path)) {
$uri = $_SERVER['REQUEST_URI'];
$ar = explode('/', $uri);
$mdl = (''!=$ar[1]) ? $ar[1]:'default';

$path = APPLICATION_PATH . '/modules/' . $mdl . '/views';

//$path = $this->_getBasePath(); - тяжелая ф-ия,
if (empty($path)) {
require_once 'Zend/Controller/Action/Exception.php';
                   throw new
Zend_Controller_Action_Exception('ViewRenderer initialization
failed: retrieved view base path is empty');
                   }
}
Результаты оптимизации




      Исходный проект 48 r/s



Включение eAccelerator 57 r/s



 Объединение классов 85 r/s



   Ручная оптимизация 98 r/s
Спасибо за внимание!

Профилирование и оптимизация фреймворков высоконагруженных систем на примере Zend Framework

  • 1.
    Профилирование и оптимизация фреймворковвысоконагруженных систем на примере Zend Framework Цехановский Сергей IT 2.0
  • 2.
    Сравнительный анализ производительности фреймворков req/s Yii Cod K oh Zen Cak Sym Fra eI g ana d Fra e PH fon me nite PH me P y wo r P wo rk rk
  • 3.
    Цель профилирования -выловить узкие места 1. Xdebug Временной отчет о Просмотр в Xdebug процессе выполнения удобочитаемом виде сценариев в WinCacheGrind 2. Отлавливание 3. FirePHP медленных SQL-запросов Логирование SQL запросов на Наглядное стороне сервера Интеграция в отслеживание ZF с FirePHP SQL запросов в FireFox Отчет
  • 4.
    Оптимизация: уровень сервера •Добавление индексов для непроиндексированных полей БД • Кэширование байт-кода $role = 0; 0101001001010010100100101101 0100101010100101001010100101 1. APC $hasCard= false; $cardAlready = false; 1010010101101001010010010100 $tblUserRoles->delete('UserId = ' . $UserId); 0100101010100101011011010110 foreach ($objRoles as $objRole) { 1010111010111101101100101011 2. eAccelerator if (isset($formData[$objRole->RoleId]) && $formData[$objRole->RoleId]) { if ($objRole->RoleId == 8) $hasCard = true; 0010111111110100101001010100 1010100101010010000001010101 if ($objRole->RoleId == 13)$cardAlready = true; 0101101010101001011100101011 3. xCache $objUserRole = $tblUserRoles->createRow(); $objUserRole->RoleId = $objRole->RoleId; $objUserRole->UserId = $UserId; 0100101010101011111101011010 1110101111011011001010110010 1111111101001010010101001010 $objUserRole->CreateDate = date('Y-m-d H:i:s'); 1001010100100000010101010101 $objUserRole->CreateBy = Zend_Auth::getInstance()- 1010101010010111001010110100 >getIdentity()->UserId; $objUserRole->save(); 1010010101101001010101010111 $role = $objRole->RoleId; 1110101101010101111110101101 } 111110101101
  • 5.
  • 6.
    Оптимизация: уровень приложения Zend_Cache ранение кэша в памяти с применением Memcached . Кэширование структуры таблиц ранение . Кэширование информации кэшированных фрагментов на диске в виде файлов
  • 7.
    Оптимизация: уровень приложения Объединениеклассов lass 1 lass 2 lass n . Накопительная сборка всех используемых классов Zend в lass 1 Class 2 один php-файл lass 3 . Накопительная сборка всех классов, наследуемых от ZF в lass n один файл
  • 8.
    Оптимизация: сборщик классов spl_autoload_register('__autoload'); начало($str) register_shutdown_function('__autoload'); $str пустое нет Класс да ? определён? да нет конец Пробуем инклудить по Берем список классов ZF, открываем каждый имени ($str). файл и сливаем его содержимое в один файл Пробуем определить путь к классу по Удалось нет Берем список пользовательских классов, имени ? открываем каждый файл и сливаем его да нет содержимое в один файл Записываем в очередь на удалось? добавление в список да конец пользовательских классов Записываем в очередь на добавление в список классов ZF
  • 9.
    Оптимизация: файл конфигурации Zend/Application.php publicfunction __construct($environment, $options = null) { $this->_environment = (string) $environment; require_once 'Zend/Loader/Autoloader.php'; $this->_autoloader = Zend_Loader_Autoloader::getInstance(); if (null !== $options) { $session = new Zend_Session_Namespace('iniconf'); if (!$sessOptions = $session->arrConfig) { if (is_string($options)) { $options = $this->_loadConfig($options); $session->config = $options; Zend_Registry::set('conf', $options); $options=$options->toArray(); $session->arrConfig = $options; } elseif ($options instanceof Zend_Config) { $options = $options->toArray(); } elseif (!is_array($options)) { throw new Zend_Application_Exception('Invalid options provided; must be location of config file, a config object, or an array'); } } else { Zend_Registry::set('conf', $session->config); $options = $sessOptions; } $this->setOptions($options); } }
  • 10.
    Оптимизация: инициализация модулей Zend/Application/Resource/Modules.phpф-ия init() $uri = $_SERVER['REQUEST_URI']; $ar = explode('/', $uri); $mdl = (''!=$ar[1]) ? $ar[1]:'default'; foreach ($modules as $module => $moduleDirectory) { if ($mdl == $module) { одуль 1 одуль 2 одуль n ………………………………………… } ласс } одуль 1 одуль 2 одуль n ласс
  • 11.
    Оптимизация: генерация пути ZendControllerActionHelperViewRenderer.php,initView if (empty($path)) { $uri = $_SERVER['REQUEST_URI']; $ar = explode('/', $uri); $mdl = (''!=$ar[1]) ? $ar[1]:'default'; $path = APPLICATION_PATH . '/modules/' . $mdl . '/views'; //$path = $this->_getBasePath(); - тяжелая ф-ия, if (empty($path)) { require_once 'Zend/Controller/Action/Exception.php'; throw new Zend_Controller_Action_Exception('ViewRenderer initialization failed: retrieved view base path is empty'); } }
  • 12.
    Результаты оптимизации Исходный проект 48 r/s Включение eAccelerator 57 r/s Объединение классов 85 r/s Ручная оптимизация 98 r/s
  • 13.