Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Mário Monteiro

Escalando o MySQL em projeto de sistemas - Parte 02

Recommended Posts

Escalando o MySQL em projeto de sistemas - Parte 02

 

Autor: Wagner Bianchi

 

Como já salientado no artigo anterior, voltamos a falar sobre alguns pontos nos quais é preciso ter atenção redobrada quando da concepção de sistemas ou mesmo ao lidar com ambientes problemáticos. Lembrando que o nosso foco é trazer à tona os principais tópicos a serem observados no ambiente e, consequentemente, chegarmos ao momento em que exploraremos os recursos voltados para a administração e disponibilidade do servidor de bancos de dados MySQL, garantindo sua escalabilidade e melhor performance - dois pontos bastante valorizados e de difícil alcance em sistemas legados ou em empresas que esbarram no meio do caminho em políticas restritivas (Teoria das Restrições) ou mesmo no famoso empurra-empurra entre desenvolvedores, DBAs e analistas de infra-estrutura.

 

A realidade atual é que não basta somente saber criar tabelas, ou mesmo "guardar dados" no "banco", ou ainda saber escrever uma boa consulta. O conhecimento relacionado com a estrutura de armazenamento da informação, iniciando a partir dos tipos de dados apropriados para garantir velocidade e boas respotas até a análise do desperdício de espaço em disco - que na minha opinião não é tão relevante quando a aplicação necessita muito de desempenho para gerar riqueza para a empresa. Essa proposição é factível quando se analisa aplicações que gerenciam departamentos de venda ou mesmo instituições financeiras que possuem sistemas web para empréstimo de vencimentos - qual seria melhor, "velocidade provida por melhor performance do sistema ou economizar espaço em disco?". Talvez você até pense que estamos discutindo quem nasceu primeiro, "o ovo ou a galinha", mas na verdade, você sabe a resposta.

 

Me sinto extremamente atraído por assuntos que tratam da estratégia de operações na administração de servidores de bancos de dados como um todo, desde a sua implementação, que é a participação na concepção do design do banco de ddaos (modelos), até a atuação na garantia de disponibilidade do servidor. O motivo principal é que o que começa errado pode ser bem mais caro do que pensamos e, segundo um dos mais renomados engenheiros de software, o Sr. Roger Pressman, as chances de um projeto naufragar são bem maiores quando não se pensa corretamente e falta competência nas área envolvidas, além do empenho da equipe em fazer da melhor forma, sempre.

 

Ainda pensando em software, ao iniciar um projeto de software, sabendo do desenvolvimento das classes de abstração com o servidor de bancos de dados MySQL, precisamos ter em mente a importância de criarmos recursos para a manipulação de dados em mais de um servidor. Isso porque, atualmente, os sistema produzem uma grande quantidade de dados/informação em um curto espaço de tempo, o que poderá nos levar a duas estratégias quanto ao crescimento do ambinete na busca de se acompanhar o crescimento do negócio:

 

* Crescimento vertical: é a estratégia de mobilizar esforços no processamento em uma só máquina grande e robusta, geralmente muito caras e de difícil reposição. Neste caso, os gestores e os analistas envolvidos no problema, preferem comprar sempre mais hardware do que se pensar em adequar melhor os aplicativos aos padrões de boa performance;

* Crescimento horizontal: é a estratégia de crescer o ambiente de tecnolgia da informação, com máquinas baratas e de fácil reposição, dando mais disponibilidade ao mesmo em caso de falha em tais máquina, ou seja, pensar melhor que problemas vão acontecer e que se pode gastar menos, obtendo mais do software que se utiliza, que é o caso do MySQL Cluster e a idéia da utilização do ambinete replicado com a auxílio do MySQL Proxy, MEMCACHED e outros recursos;

 

Em relação a estas duas vertentes de crescimento, tenho a salientar que o crescimento horizontal é o mais inteligente e mais barato, enquanto que o crescimento vertical também é uma boa opção, mas oferece mais riscos. Imagine ter uma máquina enorme (mainframe), com processadores com tecnologia RISC, que suporta o seu servidor de bancos de dados de produção. A pergunta é: "se essa máquina parar (o que também é difícil), consegue-se colocar outra no lugar ou mesmo concertá-la em tempo hábil a não perder os SLAs ou mesmo causar muito prejuízo à empresa?". Eis a questão. Máquinas pequenas, "ao atrevessar a rua", você conseguirá repor, sem falar que são mais fáceis de manusear - com um bom piloto, podem oferecer tanto desempenho quanto máquinas grandes. Várias máquinas pequenas exigirão mais da rede, gerarão mais tráfego (latência), mas, rede se arruma bem mais rápido que uma máquina enorme e é bem mais barato. Sem dizer que, segundo Raphael Diniz, engenheiro de software da empresa EAC Software, em Belo Horizonte, Minas Gerais, "você pode escalar o hardware sob demanda, não precisando despender um investimento muito grande de uma só vez".

 

Replicação entre servidores de bancos de dados MySQL

 

A replicação entre servidores de bancos de dados MySQL, recurso este que é parte integrante do MySQL desde versões bem antigas (versão 3.23.15), e é largamente utilizado mundo afora por vários administradores de bancos de dados, intitulados como DBAs, é uma opção bastante interessante para quem está a beira de um calapso nervoso ou mesmo verificando que existem muitas concorrências de threads que lêem e escrevem dados em um banco de dados que roda em um só servidor MySQL. Tais concorrências podem consumir muito hardware (consultas caras) fazendo com que filas sejam geradas internamente ao MySQL. Estas podem ser tratadas com algumas configurações de tuning do MySQL (falaremos delas em próximos artigos), dependendo do Storage Engine ou motor de armazenamento que estiver sendo utilizado ou ainda, separando-se as leituras e as escritas.

 

Dicas para resolução de filas no MySQL: Processadores com tecnologia hyper-threading combinados com configurações do parâmetro thread_cache_size. Esta conjunção de rescursos tem se mostrado muito poderosa, já que faz bastante proveito da arquitetura do MySQL, segundo o que eu tenho observado em minhas consultorias em várias das emrpesas aonde atuo e também, embasado no livro de Sasha Pachev, no livro Understanding MySQL Internals.

 

O ponto mais interessante a ser implementado é realmente a separação de leituras de escritas e acabar com parte da concorrência destas consultas por recursos (cpu, memória principal e secundária), mas, esse processo é muito complicado quando o sistema ou aplicação já foi arquitetada, homologada e já se encotra em funcionamento, como é o caso de muitos sistemas tidos como legados (quem os fez foi para outra empresa ou a tecnologia se tornou absoleta). Logo no início do projeto de um sistema, caso haja profissionais com competência e experiência o bastante para antever que a movimentação crescerá com o tempo, ao ponto de cosumir grande parte dos recursos do servidor (máquina) que se pretende alocar para abrigar o servidor de bancos de dados, este poderá aplicar o seu conhecimento ao projeto, dando aos desenvolvedores a idéia de que a classe de abstração com o backend ou banco de dados poderá manipular dados em mais de um servidor de bancos de dados.Assim , conseguiremos, sem traumas, por exemlo, manipular dados em dois servidores de bancos de dados estando estes em replicação.

 

Classe genérica para manipulação de leituras e escritas e dois servidores de bancos de dados em IPs diferentes:

Classe ClusterDatabase.php

<?php

Class ClusterDatabase {
    static private $instance;  /* instancia do objeto para padrao singleton */
    static private $masterCon; /* link com o servidor de bancos de dados master */
    static private $slaveCon;  /* link com o servidor de bancos de dados slave */
    static private $dbMaster;  /* nome do servidor de bancos de dados master */
    static private $dbSlave;   /* nome do servidor de bancos de dados slave */

    /**
     * Metodo construtor privado, para evitar que a classe seja instanciada
     * por outro metodo alem do getInstance
     * @param array $masterParm
     * @param array $slaveParm
     */
    private function __construct(array $masterParm, array $slaveParm) {

        /* verifica se o array passado como parametro contem todos os
         * dados necessarios para a conexao
         */
        if(!isset($masterParm['server'])
            || !isset($masterParm['user'])
            || !isset($masterParm['password'])
            || !isset($masterParm['database'])
            || !isset($slaveParm['server'])
            || !isset($slaveParm['user'])
            || !isset($slaveParm['password'])
            || !isset($slaveParm['database'])) {
            die("É necessario passar dois arrays com os campos 'server',
                 'user', 'password' e 'database' para conectar-se aos bancos de dados. <br/>
                 O primeiro array deve conter os dados para conexão com o Servidor Master
                 e o segundo array para o Servidor Slave.");
        }

        /* tenta conectar ao servidor master */
        self::$masterCon = mysql_connect($masterParm['server'],
                $masterParm['user'], $masterParm['password']);
        if (!self::$masterCon) {
            die('Não foi possível conectar ao servidor Master: ' . mysql_error()."<br><br>");
        }

        /* tenta conectar ao servidor slave */
        self::$slaveCon = mysql_connect($slaveParm['server'],
                $slaveParm['user'], $slaveParm['password']);
        if (!self::$slaveCon) {
            die('Não foi possível conectar ao servidor Slave: ' . mysql_error()."<br><br>");
        }

        /* seleciona o banco de dados master */
        self::$dbMaster = mysql_select_db($masterParm['database'], self::$masterCon);
        if (!self::$dbMaster) {
            die ('Não foi possível selecionar (Master): ' . mysql_error());
        }

        self::$dbSlave = mysql_select_db($slaveParm['database'], self::$slaveCon);
        if (!self::$dbMaster) {
            die ('Não foi possível selecionar (Slave): ' . mysql_error());
        }
    }

    /**
     * Metodo singleton para obter uma unica instancia dessa classe
     * @param  array $masterParm
     * @param  array $slaveParm
     * @return ClusterDatabase object
     */
    static public function getInstance($masterParm, $slaveParm) {
        if(!isset(self::$instance) || !is_object(self::$instance)) {
            $class = __CLASS__;
            self::$instance = new $class($masterParm, $slaveParm);
        }
        return self::$instance;
    }

    /**
     * Faz a leitura, sempre no servidor slave
     * @param  string $query
     * @return array
     */
    public function slave($query) {
        return( mysql_query($query, self::$slaveCon) );
    }

    /**
     * Faz a escrita, sempre no servidor master
     * @param  string $query
     * @return array
     */
    public function master($query) {
        return ( mysql_query($query, self::$masterCon) );
    }

    public function showResult($result, $title = '') {
        if($title != '')
            echo "<h2>$title</h2>";

        while ($row = mysql_fetch_array($result)) {
            echo "<pre>".print_r($row, true)."</pre>";
        }
    }

}

?>

Arquivo index.php (exemplo para instanciar a classe):

 

 

 

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />

<?php

/* inclui a classe de conexao com o banco de dados */
include 'ClusterDatabase.php';

/* define os parametros de conexao para o servidor master */
$masterParm = array(
    'server'    => "localhost:3306", /* porta do master 3306 */
    'user'      => 'root',
    'password'  => '',
    'database'  => 'cluster'
);

/* define os parametro de conexao para o servidor slave */
$slaveParm = array(
    'server'    => "localhost:3307", /* porta do slave 3307 */
    'user'      => 'root',
    'password'  => 'root',
    'database'  => 'cluster'
);

/* inicia a conexao com o banco de dados */
$DB = ClusterDatabase::getInstance($masterParm, $slaveParm);

/* define a query */
$query        = 'SELECT * from test';

/* executa a query no servidor master */
$resultMaster = $DB->master($query);
$DB->showResult($resultMaster, 'Master');

/* executa a query no servidor slave */
$resultSlave  = $DB->slave($query);
$DB->showResult($resultSlave, 'Slave');
?>

Como funciona a replicação entre servidores de bancos de dados MySQL?

 

Dentro de uma topologia de replicação entre servidores de bancos de dados MySQL, temos dois tipos de servidores, um MASTER ou mestre que é aquele que recebe todas as atualizações que até então aqui neste artigo fora tratada como escritas e o outro tipo de servidor que é chamado de SLAVE ou escravo, este que acessa o servidor MASTER através de usuário previamente criado, com privilégios REPLICATION SLAVE e lê todo o log binário, recuperando para sí todos os dados que ainda não foram aplicados aos seus bancos de dados. O trabalho todo é feito por threads de I/O e de SQL.

 

A configuração da replicação será vista num próximo artigo. Nesse momento, atente-se ao fato de que, uma vez alinhados os logs binários e dado um start na replicação entre os servidores, o SLAVE não poderá ser mais atualizado, a menos que este também seja um servidor MASTER de algum outro servidor, o que requer uma pequena configuração para dar mais inteligência ao processo e para que este processo não pare (quebra da replicação).

 

Uma vez que a classe PHP colocada em evidência acima contemplará a leitura do SLAVE e encaminahrá todas as atualizações para o servidor MASTER, o seu ambiente já conta com um certo poder de escalabilidade. O hardware ficará disponível para determinados processos.

 

Conclusão

 

Você poderá achar que é uma besteira esse papo de escalabilidade ou mesmo ser muito trabalho implementar uma classe igual a essa que sugerimos, mas pense lá na frente, quando o seu sistema apresentar características de caos, consumindo muito processamento e memória, além de fazer muito swap, com trocas contínuas entre disco e memória, tudo no vermelho e seu clientes deixando de comprar, aí você vai lembrar que um dia leu sobre o assunto e o preço por não dar atenção poderá ser bem caro não só para sua empresa.

 

Caso você leitor tenha alguma sugestão para melhorarmos a classe de abstração que apresentamos neste artigo, será um prazer voltar a publicar outros artigos com as suas sugestões. Agradeço a colaboração do amigo e engenheiro de software, atualmente trabalhando na empresa da capital mineira, a EAC Software de Belo Horzonte, que colaborou com a criação da classe de abstração com dois servidores de bancos de dados MySQL.

 

No próximo artigo, trabalharemos os principais conceitos, topologias, pros e contras e a configuração de ambiente com replicação entre servidores de bancos de dados MySQL.

 

Are you ready? Happy MySQL'ing!!

 

Fonte: iMasters

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.