Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 21-04-2008 09:55:02

whitespirit
Membre
Date d'inscription: 25-01-2008
Messages: 393

8sec pour affiche une page

Bonjour,

Je travail en localhost et c'est le temps que met une page à s'afficher. Voilà bien longtemps que c'était long, mais je n'avais pas vraiment pris conscience que cela pouvait être un problème après avoir fais une démonstration du développement en cours au client : "Ce sera aussi long une fois installé ?" m'a t'il dit.

Pour vos application, grossmodo combien de temps attendez vous pour afficher une page ? Je parle d'application "lourde" mettant en place au moins un plugin de gestion d'Acl. A chaque fois que l'utilisateur tente d'acceder à une page, je vérifie s'il est bien connecté, s'il a le droit d'acceder au module, controlleur et action. Je recherche également les menus accessibles depuis sa page. Bref, je me dis que c'est certainement ces opérations (entre autre) qui font ramer, non ?

Lorsque je test un crm tel que VTiger, je constate aussi qu'il y'a un délai de 8-10sec par page.

Qu'en pensez vous ? C'est un délai justifiable ?

Merci et à bientôt

Hors ligne

 

#2 21-04-2008 09:58:46

phpman
Membre
Date d'inscription: 20-03-2008
Messages: 138

Re: 8sec pour affiche une page

8s non ce n'est en aucun cas justifiable sur une appli, web et c'est surement pas le controle des acl de l'auth et la génération du menu qui te prennent 8s, c'est impossible, doit surement y avoir un probleme quelque part ou alors tes pages sont vraiment lourdes (calculs en php ...)
Mais 8s c'est assez énorme, à chaque fois que j'ai vu des pages aussi lourdes, ça venait d'un probleme de conception (statistiques calculées en php au lieu de faire ça en SQL, index oubliés en base ...)

Tu as essayé Zend_profiler voir si y a pas quelquechose qui cloche?


fout ça (à l'arrache big_smile) dans ton bootstrap :

Code:

try {
    $frontController->dispatch(); // dispatche !
    
    $tempsTotal       = $profileur->getTotalElapsedSecs();
    $nombreRequetes   = $profileur->getTotalNumQueries();
    $tempsLePlusLong  = 0;
    $requeteLaPlusLongue = null;
    
    foreach ($profileur->getQueryProfiles() as $query) {
        if ($query->getElapsedSecs() > $tempsLePlusLong) {
            $tempsLePlusLong  = $query->getElapsedSecs();
            $requeteLaPlusLongue = $query->getQuery();
        }
    }

    echo 'Exécution de ' . $nombreRequetes . ' requêtes en ' . $tempsTotal . ' secondes' . "<br/>";
    echo 'Temps moyen : ' . $tempsTotal / $nombreRequetes . ' secondes' . "<br/>";
    echo 'Requêtes par seconde: ' . $nombreRequetes / $tempsTotal . ' seconds' . "<br/>";
    echo 'Requête la plus lente (secondes) : ' . $tempsLePlusLong . "<br/>";
    echo "Requête la plus lente (SQL) : <br/>" . $requeteLaPlusLongue . "<br/>";
    } catch (Exception $exception) { // attrape toute exception
        exit($exception->getMessage().'<br/>'.
            $exception->getfile().' à la ligne '.$exception->getLine().'<br/>'    );
        
}

Hors ligne

 

#3 21-04-2008 10:16:14

philippe
Administrateur
Lieu: Grenoble
Date d'inscription: 01-03-2007
Messages: 1624

Re: 8sec pour affiche une page

8s c'est énorme, surtout pour une appli genre VTiger qu'un utilisateur est sensé utiliser toute la journée. Il va rapidement péter un cable.

En gros pour mes sites, je vise dans les 2s pour renvoyer le fond de page. Ensuite on peut atteidre 4 ou 5 s pour l'affichage complet de la page avec toutes les images/css/js...

Mes alertes de supervisions remontent quand le fond de page met plus de 4s à s'afficher.

A+, Philippe


twitter : @plv ; kitpages.fr : Création de sites internet à Grenoble et Paris

Hors ligne

 

#4 21-04-2008 10:17:12

phpman
Membre
Date d'inscription: 20-03-2008
Messages: 138

Re: 8sec pour affiche une page

En plus c'est 8s en local ... hmm

Hors ligne

 

#5 21-04-2008 10:24:30

philippe
Administrateur
Lieu: Grenoble
Date d'inscription: 01-03-2007
Messages: 1624

Re: 8sec pour affiche une page

euh... ça... si il a une machine comme la mienne (un vieux portable dell...) ça peut aller nettement moins vite qu'à distance smile


twitter : @plv ; kitpages.fr : Création de sites internet à Grenoble et Paris

Hors ligne

 

#6 21-04-2008 10:46:01

whitespirit
Membre
Date d'inscription: 25-01-2008
Messages: 393

Re: 8sec pour affiche une page

C'est ça le pire, 8s en local. Pourtant je n'ai pas l'impression de faire des traitements vraiment hors ZF. J'utilise 1 plugin pour gérer l'acl, j'ai 5 helpers qui sont chargés et appelé avant chaque page. Avant l'affichage de chaque page, je fais quand même beaucoup de requêtes et étant donné que j'utilise Zend_DB_Table, il est vrai que je joue beaucoup avec les objets Rowset et Row.

Par contre, niveau index oublié en base, tu veux dire quoi ? Je vais mettre dans la semaine, mon appli en ligne, et vous me direz comment elle se comporte mais j'angoisse déjà.

Par contre, le code pour utiliser le profiler cité plus haut ne m'affiche aucun résultat dans ma page. Comment puis-je faire ? (peut-être parceque j'utilise le layout ?)

Je compte beaucoup sur votre aide, car cette situation est très stressante.

Hors ligne

 

#7 21-04-2008 11:01:40

phpman
Membre
Date d'inscription: 20-03-2008
Messages: 138

Re: 8sec pour affiche une page

Si tu fais des requetes avec jointure, tu dois avoir des index sur tes champs ou tu fais ta jointure, sinon ça va ramer sec big_smile.

C'est simple, mets un "explain" devant tes "select ...", ça va t'afficher le nombre d'éléments parcouru sur chaque table de ta requete.
Si t'as 3 tables et des index bien foutus tu devrais avoir N*1*1, sinon tu peux vite arriver à des dixaines de millions de combinaisons possibles!
Bref voir cette doc qui explique très bien comment optimiser tout ça et traiter les jointures mal faites :
http://dev.mysql.com/doc/refman/5.0/fr/explain.html

Au cours de mes missions j'ai vu beaucoup de gens qui ne savaient pas se servir des index et encore moins des indexes multi colonnes, je t'invite donc à lire ce court document très instructif :
http://dev.mysql.com/doc/refman/5.0/fr/ … dexes.html

Sinon pour le profiler qui s'affiche pas, c'est bizarre c'est juste des echo donc ça devrait s'afficher tout en bas de ta page!

Dernière modification par sebondus (21-04-2008 11:05:01)

Hors ligne

 

#8 21-04-2008 11:03:46

ichevc02
Membre
Date d'inscription: 25-07-2007
Messages: 127

Re: 8sec pour affiche une page

Bonjour,

j'ai eu le meme soucis (frayeur) dans mon entreprise.

grâce à un thread sur ce forum on a résolu le pb :  le sujet
avant avec  un simple test de charge (avec jmeter) pas trop mechant, on mettait facilement à genou le serveur apache/php.
Dès que l'on a activé APC on a plus jamais mis le serveur en difficulté .
Je pense qu'il est vraiment dangereux d'utiliser le zend sans un cache d'opcode.

Voila ce que je fais pour profiler mes pages.
dans ton bootstrap :

Code:

<?php
$start = microtime(true); 
.....
...
$db = Zend_Db::factory($config->db->adapter, $config->db->config->toArray());
$db->getProfiler()->setEnabled(true); // Active le profiler de requete

.....
/// a la fin du bootstrap (tout a la fin) :
// meme chose que sebundus ..
$longestTime  = 0;
$longestQuery = null;
$end = microtime(true) - $start; // ici du capture le temps d'execution total du script (code+bdd)
$profiler = $db->getProfiler();
foreach ($profiler->getQueryProfiles() as $query) {
    if ($query->getElapsedSecs() > $longestTime) {
        $longestTime  = $query->getElapsedSecs();
        $longestQuery = $query->getQuery();
    }
}
$totalTime    = $profiler->getTotalElapsedSecs();
$queryCount   = $profiler->getTotalNumQueries();
Zend_Registry::get('logger')->log("temps total execution de la page: $end avec temps total bdd: $totalTime, nbRequetes : $queryCount", Zend_Log::ALERT);
Zend_Registry::get('logger')->log("requete la plus longue : $longestTime , : $longestQuery", Zend_Log::ALERT);

tu verra comme ca si le pb viens du temps d'exécution requetes SQL ou du code.

Dernière modification par ichevc02 (21-04-2008 11:14:41)

Hors ligne

 

#9 21-04-2008 12:18:04

whitespirit
Membre
Date d'inscription: 25-01-2008
Messages: 393

Re: 8sec pour affiche une page

Voici les résultats rétournés :

Code:

totalTime :3.5678353309631 <br /> 
queryCount : 1549 <br>
Requête plus longue : SELECT count(*) as RecordCount from ROLE_MENU where ID_MENU = 5 AND  ID_ROLE = 1

Je ne sais pas comment interpreter ces résultats ? C'est grave docteur ?

J'ai activé le module APC (simplement dans php.ini), faut-il faire autre chose ?

Je modelise mes bds en utilisant la méthode Merise depuis Windesign. J'ai bien compris l'intéret d'utiliser un index, mais avant de vraiment me pencher dans les docs, pouvez-vous m'indiquer rapidement comment je dois choisir l'index ?

Voici par exemple une table créé par défaut depuis windesign

Code:

--
-- Structure de la table `ROLE_MENU`
--

CREATE TABLE `role_menu` (
  `ID_ROLE_MENU` int(11) NOT NULL auto_increment,
  `ID_MENU` int(11) NOT NULL,
  `ID_ROLE` int(11) NOT NULL,
  PRIMARY KEY  (`ID_ROLE_MENU`),
  KEY `I_FK_ROLE_MENU_MENU` (`ID_MENU`),
  KEY `I_FK_ROLE_MENU_ROLE` (`ID_ROLE`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;

Hors ligne

 

#10 21-04-2008 12:34:19

stf
Membre
Date d'inscription: 03-04-2008
Messages: 156

Re: 8sec pour affiche une page

whitespirit a écrit:

Voici les résultats rétournés :

Code:

queryCount : 1549 <br>

C'est énorme pour une seule page yikes ...

Ca sent la requete dans une boucle ca !

Hors ligne

 

#11 21-04-2008 13:44:23

whitespirit
Membre
Date d'inscription: 25-01-2008
Messages: 393

Re: 8sec pour affiche une page

Merci, j'avance petit à petit, j'ai trouvé une sacré boucle foreach qui lance un bon nombre de fois une série de requête :

Code:

        foreach ($droitRowSet as $row)
        {
            $nom_role         = $row->FindParentRow('role')->NOM;            
            $nom_privilege     = $row->FindParentRow('privilege')->NOM;            
            $nom_ressource     = $row->FindParentRow('ressource')->NOM;            
            
            //-- Si le rôle est celui de l'admin, on ne fait rien car par défaut il a tous les droits --//
            if (strcmp($this->str_name_admin, $nom_role) != 0 ) 
            {
                if ($row->IS_ALLOW == 1)
                    $this->allow($nom_role,$nom_ressource,$nom_privilege);    
                else
                    $this->deny($nom_role,$nom_ressource,$nom_privilege);    
            }                        
        }

Ce code charge les ACLs à chaque fois que l'utilisateur essaie d'acceder à une page. Chez moi, les Acls sont décrit dans une table Droit contenant 3 champs (id_role, id_ressource, id_privilege). Avant de tenter d'acceder à une page, je charge les acls à partir de ma table. Lorsque je supprime cette ligne, je n'ai que 57 appels.

J'ai essayé d'utiliser une variable dans le Registry indiquant si les acls sont déjà chargés mais si je ne recharge pas à chaque fois les acls, ceux-ci ne sont pas conserver dans aucune session. Est-ce normal ?

Selon vous, comment sortir de ce guepier ? (

Hors ligne

 

#12 21-04-2008 13:52:29

phpman
Membre
Date d'inscription: 20-03-2008
Messages: 138

Re: 8sec pour affiche une page

stf a écrit:

whitespirit a écrit:

Voici les résultats rétournés :

Code:

queryCount : 1549 <br>

C'est énorme pour une seule page yikes ...

Ca sent la requete dans une boucle ca !

C'est ce que j'allais dire big_smile

whitespirit a écrit:

Merci, j'avance petit à petit, j'ai trouvé une sacré boucle foreach qui lance un bon nombre de fois une série de requête :

Code:

        foreach ($droitRowSet as $row)
        {
            $nom_role         = $row->FindParentRow('role')->NOM;            
            $nom_privilege     = $row->FindParentRow('privilege')->NOM;            
            $nom_ressource     = $row->FindParentRow('ressource')->NOM;            
            
            //-- Si le rôle est celui de l'admin, on ne fait rien car par défaut il a tous les droits --//
            if (strcmp($this->str_name_admin, $nom_role) != 0 ) 
            {
                if ($row->IS_ALLOW == 1)
                    $this->allow($nom_role,$nom_ressource,$nom_privilege);    
                else
                    $this->deny($nom_role,$nom_ressource,$nom_privilege);    
            }                        
        }

Ce code charge les ACLs à chaque fois que l'utilisateur essaie d'acceder à une page. Chez moi, les Acls sont décrit dans une table Droit contenant 3 champs (id_role, id_ressource, id_privilege). Avant de tenter d'acceder à une page, je charge les acls à partir de ma table. Lorsque je supprime cette ligne, je n'ai que 57 appels.

J'ai essayé d'utiliser une variable dans le Registry indiquant si les acls sont déjà chargés mais si je ne recharge pas à chaque fois les acls, ceux-ci ne sont pas conserver dans aucune session. Est-ce normal ?

Selon vous, comment sortir de ce guepier ? (

Je comprends pas trop ce que contient ton $droitRowSet

Dernière modification par sebondus (21-04-2008 13:52:45)

Hors ligne

 

#13 21-04-2008 15:07:08

Steph
Nouveau membre
Date d'inscription: 08-04-2008
Messages: 6
Site web

Re: 8sec pour affiche une page

Pourquoi charger les droits de l'utilisateur à chaque fois ? Tu les charge une fois, lors de la connexion, tu les mets en registery et tu verifies a partir de celui-ci. Ca t'evites de refaire appel à la bdd a chaque page.

Hors ligne

 

#14 21-04-2008 16:34:47

whitespirit
Membre
Date d'inscription: 25-01-2008
Messages: 393

Re: 8sec pour affiche une page

HOUUURRAAAAAAAAA.... J'ai réduit : 37 requêtes !!! En fait, je stocke mes acl permettant de faire $acl->allow($role, $ressource, $privilege) dans la table Droit contenant 3 champs [role][ressource][privilege].  Quand je réécrirais cette partie de code, j'utiliserai la sérialisation (là, je suis encore à ma première réalisation ZF)

Mission 1 : CLEAR
---------------------
Dans mon bootstrap, je test si l'acl est déjà présent dans le registry :

Code:

if (Zend_Registry::isRegistered('acl') ) 
{
    Zend_Loader::loadClass('MyAcl');                                //-- Charge les ACL
    $acl = new MyAcl($auth); 
    Zend_Registry::set('acl', $acl);                                //-- Enregistre dans le Registry    
    
    Zend_Loader::loadClass('MyPluginAuth');                                //-- Plugin  Gestion des acl et authentification
    $frontController->registerPlugin(new MyPluginAuth($auth, $acl));    //-- Enregistrement du plugin
}

Du coup, j'ai 36 requêtes exécutés. C'est encore énorme ?

Mission 2 :
------------

Dès que l'on a activé APC on a plus jamais mis le serveur en difficulté .

Il s'agit bien du module php à activer, c'est bien ça ?

Mission 3 :
------------
Comment choisir les index d'une base ?

Bon, j'ai résolu à 50% mon pb de lenteur, si vous avez d'autre astuces, n'hésitez pas à m'en faire part. En attendant je vous remercie, en fait je ne m'étais pas rendu compte du pb d'acl, c'est sûr que j'aurai pu résoudre ce pb très rapidement, mais je n'avais jamais encore utilisé le profiler.

Existe t-il un profiler pour le code ? Bon, il y'a Zend Studio mais je n'arrive pas à exécuter le debugger, il ne trouve pas le driver my_sql.dll.

A bientot

Dernière modification par whitespirit (21-04-2008 16:36:45)

Hors ligne

 

#15 21-04-2008 18:25:09

Julien
Membre
Date d'inscription: 16-03-2007
Messages: 501

Re: 8sec pour affiche une page

Jamais de requêtes dans une boucle malheureux ! Il y a toujours moyen de faire autrement (jointure, union ...). Ne pas oublier aussi les index (commande explain).
Ne pas oublier les moteurs de stockages : par exemple copier une table de droits dans une table avec un engine memory (create table like ...) au démarrage de l'appli peut s'avérer très intéréssant (à mesurer au cas par cas)...

N'oublie pas aussi Zend_Cache, tu caches tes requêtes de manière à les charger une fois seulement depuis le SGBD (le ttl sera à mesurer), et tu peux même cacher tes pages (http://devzone.zend.com/article/3372-Fr … -Framework). Nous bossons actuellement sur la un système qui permet de gérer le cache HTTP, ce sera encore plus rapide comme ca, car le serveur ne sera même plus contacté.

Ensuite évidemment, un cache d'OPCodes est indispensable, et je conseille même d'optimiser PHP par la compilation (bon ça c'est le dernier niveau)

Pour ceux qui font des benchs, n'oubliez pas que Windows, c'est pas top pour faire des tests, je vous conseille vivement de les faire tourner sous Linux.

Hors ligne

 

#16 21-04-2008 21:09:24

dinoxyz
Membre
Date d'inscription: 31-03-2007
Messages: 70

Re: 8sec pour affiche une page

En plus du debugger, j'utilise d'autres outils lancer le soir comme :

  PHPDocumentator : qui génère une documentation de l'API et du logiciel;
  PHP_CodeSniffer: qui contrôle les standards de PHP;
  PHP Depend : qui contrôle la qualité de conception et bien d'autre petit truc;
  Rats : Rough Auditing Tool for Security;
  spikephpcoverage : si tu utilises les tests unitaires avec SimpleTest;
  et selenium qui peut-être automatisé

Tu peux en rajouter d'autre avec Phing (un ant en php) ou Xinc (un intégration continue en php) à la fin tu te retrouve avec un belle petite documentation le matin (Xinc) ou quand tu codes la journée (Phing) qui te permettes d'améliorer la qualité de ton code.

Voilà, j'espère que je t'aurai un petit peu aidé dans tes recherches, mais bienvenu dans l'amélioration de code et failles de sécurités connus qui seront améliorés par ces systèmes.

Dernière modification par dinoxyz (22-04-2008 22:32:17)


Système : Ubuntu (Linux)
Version : PHP 5.2.1
Mode debug actif

Hors ligne

 

#17 22-04-2008 06:54:13

whitespirit
Membre
Date d'inscription: 25-01-2008
Messages: 393

Re: 8sec pour affiche une page

Merci de ces réponses.

Mais, qu'est-ce que tu entends par "pas de requêtes dans une boucle". Par exemple, lorsque je liste mes clients, je fais un fetchAll(). Pour chaque client, lorsque j'affiche une ligne d'enregistrement, j'utilise $row->FindByParent() dans la bouche foreach($rowset as $row) pour retrouver les informations parents ou externes. C'est donc une erreur monumentale ?

Sinon, je ne sais pas ce qu'est un moteur de stockage, et je ne me suis pas encore intéressé au cache de ZF (quels sont les infos à mettre dans le cache). J'espère qu'il n'est pas trop tard.

Plus j'avance dans mon appli, plus elle prend de l'importance, et plus je me retrouve face à des problèmes non prévus dans l'analyse de départ. Merci pour votre aide à tous.

Dernière modification par whitespirit (22-04-2008 07:12:49)

Hors ligne

 

#18 22-04-2008 07:49:23

ndesaleux
Membre
Date d'inscription: 16-04-2007
Messages: 196
Site web

Re: 8sec pour affiche une page

whitespirit a écrit:

Mais, qu'est-ce que tu entends par "pas de requêtes dans une boucle". Par exemple, lorsque je liste mes clients, je fais un fetchAll(). Pour chaque client, lorsque j'affiche une ligne d'enregistrement, j'utilise $row->FindByParent() dans la bouche foreach($rowset as $row) pour retrouver les informations parents ou externes. C'est donc une erreur monumentale ?

En fait il faut mieux faire une seule requete de X sec que N requete de X / N seconde, car meme si le temps d'execution SQL est le meme ou sensiblement, tu dois interroggé le serveur SQL a chaque requete (ca engendre un temps de latence supplémentaire, un transfert d'info inutile, ...). En gros, c'est plus un probleme de performance et de conception. Pourquoi faire en plusieurs fois ce que tu peux faire en une.

whitespirit a écrit:

Plus j'avance dans mon appli, plus elle prend de l'importance, et plus je me retrouve face à des problèmes non prévus dans l'analyse de départ. Merci pour votre aide à tous.

Ca c'est relativement normal, ca doit être 1 de tes premiers projets, le ZF est encore jeune et il a peut etre quelques soucis de performance ce qui t'oblige a te pencher sur des problematique d'optimisation.
- Supprimer le code mort
- Systeme de cache (opcode, html, sql)
- Analyse de performance du code (PHP et SQL)
- ...

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages