Archive for outubro, 2009

Trabalhando em Grupo em um mesmo branch no git

outubro 16th, 2009

Problema: Trabalhar em grupo em um branch que não seja o master usando git.

Solução:
Considerando que o repositório já está ok, e você já está conectado no remote:

Aqui estão os passos para criar o branch que a equipe vai trabalhar

# criar o branch
git checkout -b meu_branch
# enviar o branch para a origem
git push origin meu_branch
# vamos apagar esse branch local agora
git checkout master
git branch -D meu_branch

Agora cada um que vai trabalhar com este branch pode adicioná-lo assim:

git checkout --track -b meu_branch origin/meu_branch

Agora todo mundo da equipe pode trabalhar no “meu_branch” como se estivesse no master.

e para excluir o branch da origem faça:

git push origin :meu_branch

Até a proxima

Backup automático do postgres + rsync para outra máquina

outubro 15th, 2009

Aqui vou exemplificar a solução que usamos para fazer backup diário dos nossos bancos de dados, este backup é armazenado em um servidor fora do país. para fazer a sincronia, usamos o rsync.

1) Configurando login automático via chaves digitais no nosso servidor de armazenamento

Primeiro você tem que gerar as chaves no seu servidor de banco, com o usuário do banco de dados, no meu caso é o usuário “postgres”.

Você será perguntado por uma senha, deixe em branco e confirme:

$ su postgres
$ ssh-keygen -t dsa

Agora você terá sua chave, copie-a para seu servidor que irá armazenar o backup

$ scp ~/.ssh/id_dsa.pub user@server_bkp:~/

Agora acesse seu servidor via ssh e adicione a chave pública na lista de chaves autorizadas do ssh

$ ssh user@server_bkp
$ cat ~/id_dsa.pub >> ~/.ssh/authorized_keys

Volte para o seu servidor de banco no usuario do postgres e teste:

$ ssh user@server_bkp

Se você conseguiu acessar o server de backup sem digitar senha, continue no passo 2, senão, de uma revisada. qualquer dúvida comente!.

2) Instalando o rsync e script de backup

Para instalar o rsync no debian é bem simples:

$ aptitude install rsync

No nosso banco de dados os backups são feitos diariamente as 19 horas, e usamos a pasta /backup para armazena-los:

$ mkdir /backup
$ touch /backup/backup.sh
$ chmod +x /backup/backup.sh
$ chown postgres:postgres /backup -R

Agora, edite o arquivo backup.sh e coloque o conteúdo:

#!/bin/bash
 
PASTA=$(date +%m%Y)
DATA=$(date +%Y%m%d)
DIA=$(date +%d)
 
mkdir /backup/$PASTA
mkdir /backup/$PASTA/$DIA
 
LIST=$(psql -l | awk '{ print $1}' | grep -vE '^-|^\(|^List|^N[o|a]me|template[0|1]')
for d in $LIST
do
        pg_dump -i -h 127.0.0.1 -p 5432 -U postgres -F t -b -f "/backup/$DATA-$d.backup" $d
        tar -zcf /backup/$PASTA/$DIA/$DATA-$d.tar.gz /backup/$DATA-$d.backup
        rm /backup/$DATA-$d.backup
        /usr/bin/rsync -avzh --delete --progress --update /backup/ user@server_bkp:~/
done

faça um teste e rode o script com o user do postgres:

$ su postgres
$ /backup/backup.sh

Se tudo ocorrer bem, é só adicionar no crontab para executar quando você quiser:

$ su
$ pico /etc/crontab

e adicionar:

0 19    * * *   postgres    /backup/backup.sh

Reinicie o cron e o backup será feito todos os dias as 19 horas.

nginx – webserver, proxy reverso e perfeito!

outubro 15th, 2009

Nosso departamento é responsável por manter a identidade visual dos sites do Governo do Estado e ainda fazemos os sites dos orgãos que não possuem um.

No trabalho sempre tivemos um constante problema para hospedar nossos sites: hardware!. Contamos hoje com dois incríveis servidores IBM Pentium4 3Ghz com 2gb de memória e HDs scsi, um para hospedar mais de 40 sites e o outro onde fica postgres com os bancos de dados desses sites.

Ultimamente nosso problema tem crescido bastante, pois, a demanda por sites aumentou e ao mesmo tempo o número de visitas veio aumentando e, como não conseguimos de forma alguma (até agora) investimento em equipamento novo estavamos chegando em uma situação crítica, nosso servidor começava a sentar morrer com 200 conexões simultaneas!

Lembrei-me de um post do boo-box onde vi um servidor web chamado nginx (lê-se engineX) e decidi pesquisar mais e fazer testes em casa onde rodando um servidor e servindo uma página php com um usleep de meio segundo consegui mais de 2000 conexões simultaneas! uau!..

nginx_performance

Na segunda feira seguinte, sem pensar muito, fui para o nosso servidor de produção e apliquei a seguinte política de funcionamento:

  • nginx recebe todas as conexões pela porta 80
  • nginx faz proxy para o apache (que roda em outra porta) se a solicitação for para uma página php
  • nginx resolve sozinho usando php-cgi caso a requisição seja para:
    • uma fotografia
    • um arquivo
    • uma requisição para o webservice
    • um download do diário oficial
    • um banner do Governo
    • a barra padrão do Estado
    • ou um arquivo na nossa lib

Como resultado da experiência, nossos sites continuam morrendo, porém, aguentando 700 conexões simultaneas e esse valor só é alcançado quando tem muita pesquisa no banco de dados (Dias que sai algo sobre algum concurso público ou muita demissão no Diário Oficial) logo, fica claro, que o problema não é mais do webserver e sim do nosso servidor de Banco. Bom, o nosso webserver atualmente mal chega a 5% de uso, mesmo com as 700 conexões. Só espero conseguir uma maquina nova e mais eficiente para os nossos Bancos de Dados logo!.

Update:
Fomos atendidos, estamos com um Xeon Quad Core com 4Gb de memória para o Banco de dados, e, associado com uma otimização do cache do webservice alcançamos mais de 1000 conexões simultâneas sem nenhuma degradação na performance. Detalhe que o webserver ainda é um P4 3ghz com 1gb de memória em que a utilização de processamento não passa de 5%.

Autenticação de Usuários no Vórtice PHP

outubro 9th, 2009

Nesse post vou explicar como adicionar autenticação de usuários no @vorticephp, como base para o sistema vamos utilizar o exemplo que já vem com o framework.

Script de BD:

CREATE TABLE IF NOT EXISTS orgaos (
id int(11) NOT NULL AUTO_INCREMENT,
sigla varchar(50) collate utf8_unicode_ci NOT NULL,
nome varchar(150) collate utf8_unicode_ci NOT NULL,
PRIMARY KEY  (id)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8
 
CREATE TABLE IF NOT EXISTS usuarios (
id int(10) UNSIGNED NOT NULL,
nome varchar(50) NOT NULL,
email varchar(60) NOT NULL,
senha char(32) NOT NULL,
PRIMARY KEY  (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO usuarios (nome, email, senha) VALUES('Administrador', 'adm@ferrari.eti.br', md5('123'));

eu criei essa tabela com esse usuario e senha no database que já vem configurado no framework para vocês testarem localmente. Você pode configurar a conexão com o seu próprio banco de dados no arquivo app/app.php

Para iniciar vamos criar o objeto do usuário em: app/model/Usuario.php e codificar:

<?php
class Usuario{
	public function __construct($id=0, $nome='', $email='', $senha=''){
		$this->id = $id;
		$this->nome = $nome;
		$this->email = $email;
		$this->senha = $senha;
	}
}

agora que temos o objeto, vamos criar um DAO para realizar operações, crie o arquivo app/model/UsuarioDAO.php e segue o código:

<?php
class UsuarioDAO{
	public function getByEmail($email){
		$sql = "SELECT * FROM usuarios WHERE email='$email'";
		return Database::getInstance()->queryOne($sql);
	}
}

vamos para o controller de usuários, crie o arquivo app/controller/UsuarioController.php e segue o codigo inicial:

<?php
class UsuarioController extends Controller{
	public function login(){
 
	}
}

Dai a gente cria o nosso formulário de login, edite app/view/usuario/login.php:

<h2>Login</h2>
<fieldset>
	<form method="post">
		<p><label>E-mail:</label><input type="text" name="email" /></p>
		<p><label>Senha:</label><input type="password" name="senha" /></p>
		<p><input type="submit" value="Logar!" /></p>
	</form>
</fieldset>

Agora com o form criado, vamos editar a action login do controller Usuario, volte e edite o arquivo app/controller/UsuarioController.php:

<?php
class UsuarioController extends Controller{
	public function login(){
		// se um formulario foi postado
		if (post){
			// pega as variáveis do post
			$email = addslashes(p('email'));
			$senha = md5(p('senha'));
 
			// seleciona o usuario, armazena na variavel $u
			// e ainda verifica se o usuario existe
			if ($u = UsuarioDAO::getByEmail($email)){
				// verifica se a senha digitada combina com
				// a que está no BD
				if ($u->senha == $senha){
					// remove a senha do objeto
					$u->senha = null;
					// grava a session
					Session::set("u", $u);
					// Cria mensagem de sucesso e redireciona para o index
					Post::setSucesso("Olá {$u->nome}, você está logado", new Link(""));
				}else
					// Retorna erro
					Post::setErros("Senha incorreta!");
			}else
				// Retorna erro
				Post::setErros("e-mail não encontrado!");
		}
	}
}

Para ficar bonita a url vamos criar um route para esta action, edite o arquivo app/routes.php e adicione:

Route::add("^login$", "usuario:login");

Agora o formulário de login já está funcionando, vamos fazer o sistema obrigar o usuario estar logado para fazer qualquer coisa no sistema, para isso edite o arquivo app/controller/MasterController.php, como queremos que para todo o sistema sejá necessário o login, vamos adicionar um construtor nessa classe com o seguinte código:

function __construct(){
	// se a session "u" não existir, criar uma com um usuario vazio
	if (!Session::get("u")) Session::set("u", new Usuario());
 
	// Se a session u tiver um objeto vazio..
	// e o controller/action forem diferentes dos de login
	if (Session::get("u")->id == 0 && controller != 'usuario' && action != 'login'){
		// redireciona para a tela de login
		redirect(new Link("login"));
	}
}

Bom, com isso já deve estar tudo funcionando de forma eficiente e simples. Qualquer dúvida ou sugestão mande sem hexitar.