Balanceamento de Carga com PHP - Parte I

Filed Under (Clustering, PHP) by admin on 18-08-2009

Empresas que possuem um número alto de requisições em seus servidores ou que precisam de alta-disponibilidade em seus sistemas, adotam soluções de cluster adaptadas as sua realidade. Dos três tipos conhecidos (Alto Desempenho, Alta Disponibilidade e Balanceamento de Carga) vou tentar passar as configurações básicas para o Balanceamento de Carga para PHP.
As configurações que vou apresentar podem ser aplicadas em máquinas físicas ou em um ambiente virtualizado.

O primeiro problema a ser resolvido é o das sessões. O PHP por padrão salva os dados de sessões em arquivos dentro
de um diretório local. Em um cluster configurado para balanceamento de carga o PHP então não saberia encontrar os dados da sessão de um usuário ou qual foi o ID criado para ele e etc… Pois, cada máquina, teria seu próprio gerenciador de sessões.
Existem algumas soluções para este problema e a que vou apresentar aqui é a persistência de sessões em banco de dados. Um ponto único de gravação e leitura de sessões com o suporte  da transação gerenciada pelo banco.
O banco de dados utilizado aqui será o MySQL, mas o código PHP necessário para o gerenciamento
de sessões pode ser facilmente migrado para qualquer outro banco. Uma boa prática é usar o PDO como camada de
acesso ao banco.

Vamos ao código, o PHP permite alterar o gerenciamento de sessões através da função session_set_save_handler .
Esta função espera seis funções de callback como parâmetro que são:

open
close
read
write
destroy
gc

Então o primeiro passo é definir a classe session que implementará estes métodos:

session.class.php

<?php

class session {
    var $life_time;
    var $connection;
   
    function session($connection) {
        $this->connection = $connection;
        $this->life_time = get_cfg_var(”session.gc_maxlifetime”);
        //Olha session_set_save_handler aqui!!!
        session_set_save_handler(
            array( &$this, “open” ),
            array( &$this, “close” ),
            array( &$this, “read” ),
            array( &$this, “write”),
            array( &$this, “destroy”),
            array( &$this, “gc” )
        );
    }

    function open( $save_path, $session_name ) {
        global $sess_save_path;
        $sess_save_path = $save_path;     
        return true;
    }

    function close() {
        return true;
    }

    function read( $id ) {
        $num_rows = 0;
        $data = ”;
        $time = time();
        $newid = mysql_real_escape_string($id); //prefira PDO e bindParams ao mysql_real_escape_string
        $result =mysql_query(”SELECT `session_data` FROM `sessions` WHERE `session_id` = “.$newid.” AND `expires` > “.$time, $this->connection);
        if ($result) {
            $num_rows = mysql_num_rows($result,$this->connection);

            if($num_rows  > 0) {
                $row = mysql_fetch_array($result);
                $data = $row['session_data'];
            }
        }
        return $data;
    }
    function write( $id, $data ) {    
        $time = time() + $this->life_time;
        $newid = mysql_real_escape_string($id);     //prefira PDO e bindParams ao mysql_real_escape_string
        $newdata = mysql_real_escape_string($data);
        $sql = “REPLACE `sessions` (`session_id`,`session_data`,`expires`) VALUES(’$newid’, ‘$newdata’, $time)”;
        $rs = mysql_query($sql,$this->connection);
        return true;
    }

    function destroy( $id ) {     
        $newid = mysql_real_escape_string($id);
        $sql = “DELETE FROM `sessions` WHERE `session_id` = ‘$newid’”;
         mysql_query($sql, $this->connection);
        return true;
    }

    function gc() {
        $sql = ‘DELETE FROM `sessions` WHERE `expires` < UNIX_TIMESTAMP();’;
        mysql_query($sql,$this->connection);     
        return true; //Sempre retorna true
    }
}
?>

Agora vamos criar uma página para testes:

teste.php

<?php

require_once(”session.class.php”);

$connection = mysql_connect(”192.168.56.1″,”root”,”");
mysql_select_db(”sessions”, $connection) or die( “Erro ao selecionar a base de dados”);

$session = new session($connection);

session_start();
$_SESSION['time']= date(”H:i:s”);
$_SESSION['server']= “server 1″;
print_r($_SESSION);

?>
E por fim a tabela que irá armazenar os dados das sessões:

CREATE TABLE IF NOT EXISTS `sessions` (
  `session_id` varchar(100) NOT NULL DEFAULT ”,
  `session_data` text NOT NULL,
  `expires` int(11) NOT NULL DEFAULT ‘0′,
  PRIMARY KEY (`session_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Rode a aplicação e veja o resultado gravado na tabela.
E agora que já temos toda parte de sessão resolvida vamos para a segunda parte: as configurações de balanceamento.

Comments:

Leave a Reply