Hoje enfrentei um problema difícil no trabalho, um cliente pediu para recuperar um backup de um banco que acidentalmente teve seus dados apagados, como levei algum tempo para juntar as peças e montar o quebra cabeça resolvi postar aqui pra compartilhar com todos essa experiência.

Então, vamos ao cenário:

  1. Cliente pede para recuperar o backup de um banco no MySQL
  2. Percebi que não tinhamos backup em dump daquele banco, somente backup em tarball de todo o /var/lib/mysql (normalmente é lá que ficam os arquivos contendo os dados e índices dos bancos de dados)

A partir deste ponto normalmente se pensa que basta recuperar o diretório com o nome do banco de dentro do tarball, ou seja extrair do tarball /var/lib/mysql/nome_banco. Acontece que isso geralmente funciona, mas para bancos com tabelas MyISAM. Bancos com tabelas InnoDB possuem uma pequena diferença no MySQL, seus dados não ficam autocontidos no diretório de nome do banco, mas sim dentro do arquivo /var/lib/mysql/ibdata1, este arquivo vai conter os dados de todos os bancos que utilizarem a engine InnoDB, e é justamente por causa disso que NÃO podemos restaurar o backup de um banco específico sobrescrevendo o ibdata1, pois senão iremos voltar dados para o passado no banco de dados de TODOS os usuários!!!

O que então precisamos fazer?

Pré-requisitos:

  1. Ter uma máquina extra (física ou virtual)
  2. O MySQL instalado nesta máquina extra e sem estar sendo utilizado em produção

A primeira coisa que devemos fazer é copiar para a máquina extra o /var/lib/mysql/ibdata1 e o /var/lib/mysql/nome_do_banco que foram extraídos do nosso tarball com o backup. Antes de fazer alguma alteração nos dados do MySQL vamos parar o banco com o comando (em distribuição debian):

invoke-rc.d mysql stop

Depois de parar o MySQL vamos fazer uma cópia do /var/lib/mysql só por precaução:

cp -a /var/lib/mysql /var/lib/mysql.20090617

Agora vamos sobrescrever o /var/lib/mysql/ibdata1 com aquele que extraímos do tarball e em seguida copiar o diretório contendo os demais arquivos do banco, aquele /var/lib/mysql/nome_do_banco.

Para garantir vamos ajustar as permissões:

chown -R mysql:mysql /var/lib/mysql/ibdata1 /var/lib/mysql/nome_do_banco

Neste ponto já podemos levantar o MySQL novamente:

invoke-rc.d mysql start

Nos logs do MySQL você vai perceber que ele vai acusar diversos erros, pois os dados de outros bancos que estão contidos no ibdata1 não possuem o seus respectivos diretórios no /var/lib/mysql, apenas ignore estes erros já que você está trabalhando em um sistema de produção, o objetivo aqui é conseguir um dump dos dados do banco que precisa ser recuperado.

O próximo passo então é gerar o dump dos dados com o comando:

mysqldump -uroot -p"senha_de_root" --databases nome_do_banco > dump.sql

Caso o MySQL te retorne erros de conexão ao executar esse comando você deve tentar novamente até conseguir, isso acontece por causa daqueles erros que citei anteriormente pelos bancos que não existem (comigo não foram mais do que duas tentativas).

Bem, é isso ai, agora já temos um arquivo com o dump de todos os dados contidos no banco que precisamos recuperar, basta enviar para o servidor de produção e importar, mas o comando pra fazer isso eu vou deixar como lição de casa! :P

Um abraço e até a próxima!