web-dev-qa-db-fra.com

session_start () prend très longtemps

Mon site fonctionne très lentement (et je ne savais pas pourquoi). Il est basé sur Zend Application, je faisais des dizaines de sites de ce type, alors je suis sûr que mon code est correct.

J'ai installé xdebugger sur le serveur, j'ai essayé de le profiler et de deviner quoi? php :: session_start () a pris 48,675 secondes. Quarante huit secondes et demi! C'est incroyable! Quelle pourrait être la raison de cela? C'est une opération courante, pourquoi pourrait-il exécuter SO long? Comment réparer un tel comportement, quelle configuration modifier? Recherche sur Google, mais n'a pas trouvé de bonne réponse (presque partout, il y a une question, mais pas de réponse). Merci avant!

xdebugger profiling results

21
ABTOMAT

Mon hypothèse serait la routine de récupération de place, qui s'exécute à l'intérieur de la fonction native session_start(). Peut-être que vous avez fait quelque chose qui conserve beaucoup d'anciens fichiers de session, comme changer la durée de vie maximale? Ou peut-être avez-vous décidé que ce serait une bonne idée de les stocker dans une base de données, mais vous avez oublié de créer un index approprié? La routine GC (stat ()) native de chaque fichier de session vérifie l'expiration. Cela prend du temps s'il y a beaucoup de fichiers construits.

edit : pour vous aider pour le débogage uniquement , désactivez le nettoyage de place en définissant temporairement session.gc-probabilité :

session.gc-probability = 0

Assurez-vous que les paramètres restent, je ne sais pas ce que le framework zend pourrait faire ici.

P.S. Il est difficile de suggérer une solution sans en connaître la cause. Ma réponse est destinée à vous guider vers l'identification de la cause.

19
goat

session_start (avec des sessions stockées dans des fichiers) bloque en PHP. Ce problème apparaît donc si vous essayez de démarrer plusieurs sessions de serveur pour la même session de navigateur (AJAX ou plusieurs onglets/fenêtres de navigateur). Chaque session_start attendra la fermeture des autres sessions.

Voir ici: http://konrness.com/php5/how-to-prevent-blocking-php-requests/

Essayez de passer de fichiers à la base de données de sessions.

18
Christian Davén

J'ai eu ce problème et je suis surpris que personne n'ait posté cette réponse spécifique. Ce n'est peut-être pas ça, mais ça vaut la peine de vérifier.

PHP verrouille le fichier de session pendant le traitement d'une page afin que cette page puisse y avoir un accès exclusif. Pensez-y, le fichier sess_184c9aciqoc n'est pas une base de données, de sorte que deux appels de la même session ne peuvent y accéder simultanément. Donc, si vous avez beaucoup d'appels ajax, vous pouvez obtenir un "embouteillage". Une fois que vous commencez à utiliser des scripts avancés, vous devez vous méfier. à propos, voici une fonction pour stocker un tableau d'horodatages. J'ai utilisé cela pour comprendre que le début de la session était le coupable:

//time function for benchmarking
if( function_exists('gmicrotime')){
    function gmicrotime($n=''){
        #version 1.1, 2007-05-09
        //store array of all calls
        global $mT;
        list($usec, $sec) = explode(' ',microtime());
        if(!isset($mT['_base_']))$mT['_base_']=$sec;
    $t=round((float)$usec + (float)(substr($sec,-4)),6);
    $mT['all'][]=$t;
    if($n){
        if(isset($mT['indexed'][$n])){
            //store repeated calls with same index.  If in a loop, add a $i if needed
            if(is_array($mT['indexed'][$n])){
                $mT['indexed'][$n][]=$t;
            }else{
                $mT['indexed'][$n]=array($mT['indexed'][$n],$t);
            }
        }else $mT['indexed'][$n]=$t;    
    }
    //return elapsed since last call (in the local array)
    $u=$mT['all'];
    if(count($u)>1){
        $mT['_total_']=$u[count($u)-1] - $u[0];
        return round(1000*($u[count($u)-1]-$u[count($u)-2]),6);
    }
}
gmicrotime('pageStart');
}

alors j'appelle comme suit:

gmicrotime('beforeSessionStart');
session_start();
gmicrotime('afterSessionStart');

do_something_slow();
gmicrotime('afterSlowProcess');
//etc..
echo '<pre>';
print_r($mT);  

J'espère que c'est utile!

5
Samuel Fullman

Une autre approche pourrait être que vous ayez défini un memory_limit volumineux dans PHP.ini.

C'est ce que j'ai fait pour télécharger d'énormes dumps mysql dans PHPMyAdmin et augmenter le temps de chargement. Peut-être (comme indiqué ci-dessus) de nombreux fichiers de session s'accumulent-ils maintenant que PHP dispose de suffisamment d'espace. La valeur par défaut est 128M, je pense. J'avais quadruplé ça.

2
PeerBr

Si vous avez plusieurs appels ajax simultanés sur la même page, cela peut entraîner votre problème.

0
Nicolas Finelli

Je viens d'avoir ce problème. session_start prenait environ 5 secondes.

Mon problème était que j'avais déclaré des variables au-dessus. 

J'ai déplacé session_start vers le haut et cela prend maintenant quelques millisecondes.

0
Shane Zammit

Dans mon cas, il s'agissait de paramètres de serveur memcache incorrects dans /etc/php.d/memcached.iniIci contient des informations sur les propriétés de memcache et ici explique comment configurer le stockage dans memcache.

0
vikramaditya234

Une façon d'éviter ce problème est de demander à PHP de stocker les sessions dans une table de base de données au lieu de fichiers.

Tout d’abord, je vais vous donner quelques liens en tant que véritable crédit pour cette solution:

http://www.tonymarston.net/php-mysql/session-handler.html

http://shiflett.org/articles/storing-sessions-in-a-database

http://culttt.com/2013/02/04/how-to-save-php-sessions-to-a-database/

Ensuite, une implémentation de code que j'ai tirée de ces lectures:

<?php

class TLB_Sessions_in_Database
{
    private $debug;
    private $dbc;

    function __construct()
    {
        $this->debug = false;

        session_set_save_handler(
            array($this, '_open'),
            array($this, '_close'),
            array($this, '_read'),
            array($this, '_write'),
            array($this, '_destroy'),
            array($this, '_clean')
        );
    }

    function _open()
    {
        if( $this->debug ) echo '_open:'.PHP_EOL;

        if( ($this->dbc = mysql_connect(DB_Host, DB_USER, DB_PASSWORD)) !== false )
        {
            $select_db = mysql_select_db(DB_NAME, $this->dbc);
            $set_charset = mysql_set_charset(DB_CHARSET, $this->dbc);

            if( $this->debug ) echo '- return: '.(( $select_db && $set_charset ) ? 'true' : 'false').PHP_EOL;

            return( $select_db && $set_charset );
        }
        else
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( false );
    }

    function _close()
    {
        if( $this->debug ) echo '_close:'.PHP_EOL;

        return( mysql_close($this->dbc) );
    }

    function _read($session_id)
    {
        if( $this->debug ) echo '_read:'.PHP_EOL;

        $session_id = mysql_real_escape_string($session_id);

        $sql = "SELECT `session_data` FROM `".DB_NAME."`.`php_sessions` WHERE `session_id` = '".$session_id."'";

        if( $this->debug ) echo '- query: '.$sql.PHP_EOL;

        if( ($result = mysql_query($sql, $this->dbc)) !== false )
        {
            if( !in_array(mysql_num_rows($result), array(0, false), true) )
            {
                $record = mysql_fetch_assoc($result);

                return( $record['session_data'] );
            }
        }
        else
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( '' );
    }

    function _write($session_id, $session_data)
    {
        if( $this->debug ) echo '_write:'.PHP_EOL;

        $session_id = mysql_real_escape_string($session_id);
        $session_data = mysql_real_escape_string($session_data);

        //$sql = "REPLACE INTO `php_sessions` (`session_id`, `last_updated`, `session_data`) VALUES ('".$session_id."', '".time()."', '".$session_data."')";
        $sql = "INSERT INTO `".DB_NAME."`.`php_sessions` (`session_id`, `date_created`, `session_data`) VALUES ('".$session_id."', NOW(), '".$session_data."') ON DUPLICATE KEY UPDATE `last_updated` = NOW(), `session_data` = '".$session_data."'";

        if( ($result = mysql_query($sql, $this->dbc)) === false )
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( $result );
    }

    function _destroy($session_id)
    {
        if( $this->debug ) echo '_destroy:'.PHP_EOL;

        $session_id = mysql_real_escape_string($session_id);

        $sql = "DELETE FROM `".DB_NAME."`.`php_sessions` WHERE `session_id` = '".$session_id."'";

        if( ($result = mysql_query($sql, $this->dbc)) === false )
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( $result );
    }

    function _clean($max)
    {
        if( $this->debug ) echo '_clean:'.PHP_EOL;

        $sql = 'DELETE FROM `'.DB_NAME.'`.`php_sessions` WHERE `last_updated` < DATE_SUB(NOW(), INTERVAL '.$max.' SECOND)';

        if( ($result = mysql_query($sql, $this->dbc)) === false )
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( $result );
    }
}

new TLB_Sessions_in_Database();

FIN.

0