array( 'host' => "127.0.0.1", 'port' => 3306, 'user' => "user", 'pass' => "password", 'master' => 1, // If the server is a master else a slave 'options' => "--quick --add-drop-table", // ou "--opt" 'compress' => "gzip", // Method to compress : none, gzip, bzip2, pigz, 7zx, xz 'dir' => "/backup/keep", // Backup dir 'max' => 3, // Number of backup to keep 'processdir' => "/backup/inprocess", // In process dir ), 'backup type/name' => array( 'db' => array(...), //List database to backup - always include a db to list tables 'rules' => array( // Rules to include or exclude database and table by name ( preg_match('/^db\.table$/') ) 'in' => array(), 'ex' => array(), ), ), ), Parallel restore ---------------- cd /to/backup/dir echo *.sql | xargs -n1 -P 16 -I % sh -c 'mysql -uuser -ppassword -hIP mydb < %' ls *.sql | xargs -n1 -P 16 -I % sh -c 'mysql -uuser -ppassword -hIP mydb < %' */ $shortopts = ''; $longopts = array( 'type:', 'config:', ); $options = getopt($shortopts, $longopts); if ($options === false || count($options) == 0) { echo "Nothing to do...\n"; exit; } $configFile = 'dbBackupConfig.php'; if (array_key_exists('config', $options)) { $configFile = $options['config']; } if (file_exists(__DIR__.'/'.$configFile)) { $config = include __DIR__.'/'.$configFile; } else { echo date('Y-m-d H:i:s')." - No config.\n"; exit; } if (!array_key_exists('mysql', $config)) { echo date('Y-m-d H:i:s')." - No config.\n"; exit; } // --- Define mysql option $backupMysql = $config['mysql']; // --- Type backup $type = strtoupper($options['type']); if (!array_key_exists($type, $config)) { echo date('Y-m-d H:i:s')." - Backup type not found !\n"; exit; } // --- Backup Options $backupParams = $config[$type]; // --- Host $backupMysqlHost = $backupMysql['host']; $backupMysqlPort = $backupMysql['port']; $backupMysqlUser = $backupMysql['user']; $backupMysqlPass = $backupMysql['pass']; $backupMysqlMaster = $backupMysql['master']; $backupMysqlOptions = $backupMysql['options']; // --- Backup Directory Options $backupCompress = $backupMysql['compress']; $backupDir = $backupMysql['dir']; $backupMax = $backupMysql['max']; // --- Backup temporary dir $backupDirProcess = $backupDir; if (array_key_exists('processdir', $backupMysql)) { $backupDirProcess = $backupMysql['processdir']; } if (!is_dir($backupDirProcess)) { echo date('Y-m-d H:i:s')." - Backup dir not found $backupDir\n"; exit; } // --- Master or Slave information if ($backupMysqlMaster) { $filePosInfo = 'position-master-'.$type.'.info'; } else { $filePosInfo = 'position-slave-'.$type.'.info'; } echo date('Y-m-d H:i:s')." - Start Backup $type.\n"; $tInit = microtime(true); $dirname = $type.'-'.date('Y.m.d.His'); $pathBackup = $backupDirProcess . '/' . $dirname; mkdir($pathBackup); // --- Connexion $link = new mysqli($backupMysqlHost, $backupMysqlUser, $backupMysqlPass, null, $backupMysqlPort); if ($link->connect_errno) { echo date('Y-m-d H:i:s')." - Error can't connect to MySQL : (" . $mysqli->connect_errno . ") " . $mysqli->connect_error."\n"; } // --- List databases $result = $link->query('SHOW DATABASES'); $databases = $tables = array(); while ($row = $result->fetch_assoc()) { $databases[] = $row['Database']; } // --- Stop Slave if ( !$backupMysqlMaster ) { echo date('Y-m-d H:i:s')." - STOP SLAVE SERVER\n"; $link->query('STOP SLAVE;'); } // --- Save replication position putMasterStatus($link, "$pathBackup/$filePosInfo", 'START', $backupMysqlMaster, 0); // --- Backup for each databases foreach ($databases as $database) { if (in_array($database, $backupParams['db'])) { $link->query('USE '.$database); $result = $link->query('SHOW TABLES'); while ($row = $result->fetch_array()) { $table = $row[0]; // --- Don't backup MEMORY table $statusResult = $link->query("SHOW TABLE STATUS LIKE '".$table."'"); $statusRow = $statusResult->fetch_assoc(); if (strtoupper($statusRow['Engine']) == 'MEMORY') { continue; } // --- Don't backup special database if ( in_array($database, array('mysql', 'test', 'information_schema', 'performance_schema', 'phpmyadmin')) ) { continue; } // --- Excluded table $stop = 0; foreach ($backupParams['rules']['ex'] as $rule) { if ( preg_match('/^'.$rule.'$/', $database.'.'.$table) ) { $stop = 1; break; } } if ($stop == 1) { continue; } // --- Included table $stop = 0; foreach ($backupParams['rules']['in'] as $rule) { if ( !preg_match('/^'.$rule.'$/', $database.'.'.$table) ) { $stop = 1; break; } } if ($stop == 1) { continue; } $files[] = $database.'.'.$table; $tDeb = microtime(true); // --- Optimize table to remove hole if ( $backupMysqlMaster ) { if ( $statusRow['Data_free'] > 0 ) { echo date('Y-m-d H:i:s') ." - OPTIMIZE on '$database.$table'\n"; $link->query('OPTIMIZE TABLE '.$database.'.'.$table); } } echo date('Y-m-d H:i:s') ." - Backup '$database.$table'"; // --- Cmd to backup the table $cmd = 'mysqldump -h' . $backupMysqlHost . ' -P' . $backupMysqlPort . ' -u' . $backupMysqlUser . ' -p' . $backupMysqlPass . ' ' . $backupMysqlOptions . ' ' . $database . ' --tables ' . $table . ' > ' . $pathBackup.'/'.$database.'.'.$table.'.sql'; // --- Execute exec($cmd); // --- Set Master or Slave position putMasterStatus($link, "$pathBackup/$filePosInfo", "$database.$table", $backupMysqlMaster, FILE_APPEND); $period = round(microtime(true)-$tDeb,3); echo " in $period s.\n"; } } } // --- Save replication position putMasterStatus($link, "$pathBackup/$filePosInfo", 'END', $backupMysqlMaster, FILE_APPEND); // --- Restart slave if ( !$backupMysqlMaster ) { echo date('Y-m-d H:i:s')." - RESTART SLAVE SERVER\n"; $link->query('START SLAVE;'); } // --- Close mysql $link->close(); // --- Compression des fichiers de dump if (in_array($backupCompress, array('gzip', 'pigz', '7z', 'xz', 'pxz'))) { foreach($files as $item) { $tDeb = microtime(true); switch($backupCompress) { case 'gzip': exec("gzip $pathBackup/$item.sql"); break; case 'pigz': exec("pigz -9 -f $pathBackup/$item.sql"); break; case '7z': exec("7za a $pathBackup/$item.7z $pathBackup/$item.sql"); break; case 'xz': exec("xz $pathBackup/$item.sql"); break; case 'pxz': exec("pxz -9 -f $pathBackup/$item.sql"); break; default: break; } if (file_exists("$pathBackup/$item.sql")) { exec("rm -f $pathBackup/$item.sql"); } $period = round(microtime(true)-$tDeb,3); echo date('Y-m-d H:i:s') ." - Compress '$item.sql' in $period s.\n"; } } // --- Rename if process dir is in use if ($backupDirProcess != $backupDir) { rename($pathBackup, $backupDir.'/'.$dirname); } // --- Delete old backup if ($backupMax > 0) { foreach ( glob("$backupDir/$type-*", GLOB_ONLYDIR) as $filename ) { $date = substr(basename($filename), strlen($type) + 1); $backupDelete[$date] = $filename; } krsort($backupDelete); $i = 0; foreach ( $backupDelete as $k => $delete ) { if ( $i >= $backupMax ) { passthru("rm -rf $delete"); echo date('Y-m-d H:i:s') ." - Delete backup $delete\n"; } $i++; } } echo date('Y-m-d H:i:s') ." - End Backup.\n"; $period = round(microtime(true) - $tInit); $hours = floor($seconds / 3600); $mins = floor(($seconds - ($hours*3600)) / 60); $secs = floor($seconds % 60); $message = "Backup Databases in $hours h $mins min $sec s ($period s) :\n"; $message.= print_r($backupParams['db'], 1); sendMail( array('supportdev@scores-decisions.com'), 'Backup MySQL '.$backupMysqlHost, $message); // --- End function putMasterStatus($link, $file, $dbTable, $master, $flags=0) { if ( $master ) { $result = $link->query('SHOW MASTER STATUS'); while ($row = $result->fetch_assoc()){ file_put_contents($file, date('Y-m-d H:i:s').", $dbTable,".$row['File'].','.$row['Position']."\n", $flags); } } else { $result = $link->query('SHOW SLAVE STATUS'); while ($row = $result->fetch_assoc()){ file_put_contents($file, date('Y-m-d H:i:s').", $dbTable,".$row['Relay_Master_Log_File'].','.$row['Exec_Master_Log_Pos']."\n", $flags); } } } function sendMail($emails, $sujet, $message) { $from = 'supportdev@scores-decisions.com'; $headers = 'Reply-To: '.$from."\n"; // Mail de reponse $headers .= 'From: "Support DEV"<'.$from.'>'."\n"; // Expediteur $to = join(' ,',$emails); //recipient $mail_body = $message; //mail body $subject = $sujet; //subject mail($to, $subject, $mail_body, $headers); }