用Python備份MYSQL 數據庫

ybw8 9年前發布 | 20K 次閱讀 Python Python開發

 工作需要,對公司的MYSQL數據庫進行備份,趕上剛剛開始學python,看了一套簡單的python教學視頻,簡單的寫了個備份腳本,個人表示 對python 的class 、function、build-in function 、私有變量、全局變量 等等,該怎么用,啥時候用等 毫無概念 ,僅此記錄一下吧,也歡迎路過的pythoner賜教。

個人已知的一些問題:

   1、該腳本必須要求 mysql配置文件內的所有行為 key=value的格式,并且不能存在多余的注釋,否則ConfigParser模塊解析配置文件時會出錯,由于沒研究過ConfigParser是不是有容錯的方法可以調用,也沒時間寫容錯處理,而是通過整理my.ini 配置文件使其符合ConfigParser的要求解決的。后面會附上我用的mysql配置文件。

   2、大量使用類私有成員變量,因為完全不知道python 變量、類方法、等等啥時候該私有化,以及有啥區別,只知道類私有成員變量在別的腳本中import 或者繼承時,是不可見的。

   3、比較多的進行文件操作,以及傳值操作,目前只保證按正確格式傳值沒問題,沒有做多余的容錯處理。    4、大量的在進行字符串拼接,第一次寫運維相關腳本,由于要調用系統命令,和傳遞很多參數,也不會subprocess模塊,不知道別人寫運維腳本都具體咋做,就直接拼接了。

   5、其他未知的bug、未發現的邏輯錯誤等等。

環境:

- Server :             Dell PowerEdge T110

- OS:                   CentOS 6.3_x86_64

- PythonVersion:    2.7.3

- MysqlVersion:      5.5.28 linux x86_64

MysqlBackupScript.py

#!/usr/bin/env python
# coding: utf8
# script MysqlBackupScript
# by Becareful
# version v1.0

"""
This scripts provides auto backup mysql(version == 5.5.x) database .
"""

import os
import sys
import datetime         #用于生成備份文件的日期
import linecache        #用于讀取文件的指定行
import ConfigParser     #解析mysql配置文件


class DatabaseArgs(object):
    """

    """

    __MYSQL_BASE_DIR = r'/usr/local/mysql'            #mysql安裝目錄
    __MYSQL_BIN_DIR = __MYSQL_BASE_DIR + '/bin'       #mysql二進制目錄
    __MYSQL_CONFIG_FILE = r'/usr/local/mysql/my.cnf'  #mysql配置文件

    __ONEDAY = datetime.timedelta(days=1)             #一天的時長,用于計算下面的前一天和后一天日期
    __TODAY = datetime.date.today()      #當天日期格式為 YYYY-MM-DD
    __YESTERDAY = __TODAY - __ONEDAY                  #計算昨天日期
    __TOMORROW = __TODAY + __ONEDAY                   #計算明天日期
    __WEEKDAY = __TODAY.strftime('%w')                #計算當天是一星期的星期幾

    __MYSQL_DUMP_ARGS = {                             #用一個字典存儲mysqldump 命令備份數據庫的參數
        'MYISAM': ' -v -E -e -R --triggers -F  -n --opt --master-data=2 --hex-blob -B ',
        'INNODB': ' -v -E -e -R --triggers -F --single-transaction -n --opt --master-data=2 --hex-blob -B '
    }

    __DUMP_COMMAND = __MYSQL_BIN_DIR + '/mysqldump'   #mysqldump 命令的 路徑 用于dump mysql數據
    __FLUSH_LOG_COMMAND = __MYSQL_BIN_DIR + '/mysqladmin'    #mysqladmin 命令的路徑 ,用于執行 flush-logs 生成每天增量binlog

    __BACKUP_DIR = r'/backup/'                        # 指定備份文件存放的目錄

    __PROJECTNAME = 'example'                         # 指定需要備份的數據庫對應的項目名,將來會生成 projectname-YYYY-MM-DD.sql 等文件
    __DATABASE_LIST = []                              # 指定需要備份的數據庫名,可以是多個,使用列表
    __HOST = 'localhost'
    __PORT = 3306
    __USERNAME = 'root'
    __PASSWORD = ''
    __LOGINARGS = ''                                  # 如果在localhost登陸,需要密碼,可以設定登陸的參數,具體在下面有說明
    __LOGFILE = __BACKUP_DIR + '/backup.logs'

    def __init__(self, baseDir=__MYSQL_BASE_DIR, backDir=__BACKUP_DIR, engine='MYISAM', projectName=__PROJECTNAME,
                 dbList=__DATABASE_LIST, host=__HOST, port=__PORT, user=__USERNAME, passwd=__PASSWORD):

        """
            實例化對象時傳入的參數,如不傳入默認使用類的私有成員變量作為默認值
    :param baseDir:    
    :param backDir:
    :param engine:
    :param projectName:
    :param dbList:
    :param host:
    :param port:
    :param user:
    :param passwd:
    """
        self.__MYSQL_BASE_DIR = baseDir
        self.__BACKUP_DIR = backDir
        self.__PROJECTNAME = projectName
        self.__DATABASE_LIST = dbList
        self.__HOST = host
        self.__PORT = port
        self.__USERNAME = user
        self.__PASSWORD = passwd
        self.__ENGINE = self.__MYSQL_DUMP_ARGS[engine]
        #下面定義了如需登陸時,參數 其實就是生成 這樣的格式  “-hlocalhost -uroot --password=‘xxxx’”
        self.__LOGINARGS = " -h" + self.__HOST + " -P" + str(
            self.__PORT) + " -u" + self.__USERNAME + " --password='" + self.__PASSWORD + "'"
        self.checkDatabaseArgs()   #調用檢查函數

    def __getconfig(self, cnf=__MYSQL_CONFIG_FILE, item=None):  # 解析mysql配置文件的小函數,簡單封裝了下,傳入一個值作為my.cnf的key去查找對應的value

        __mycnf = ConfigParser.ConfigParser()
        __mycnf.read(cnf)
        try:
            return __mycnf.get("mysqld", item)
        except BaseException, e:
            sys.stderr.write(str(e))
            sys.exit(1)

    def __getBinlogPath(self): #  取每天需要增量備份的binlog日志的絕對路徑,從mysql的binlog.index文件取倒數第二行

        __BINLOG_INDEX = self.__getconfig(item='log-bin') + '.index'

        if not os.path.isfile(__BINLOG_INDEX):
            sys.stderr.write('BINLOG INDEX FILE: [' + __BINLOG_INDEX + ' ] NOT FOUND! \n')
            sys.exit(1)
        else:
            try:
                __BINLOG_PATH = linecache.getline(__BINLOG_INDEX, len(open(__BINLOG_INDEX, 'r').readlines()) - 1)
                linecache.clearcache()
            except BaseException, e:
                sys.stderr.write(str(e))
                sys.exit(1)
            return __BINLOG_PATH.strip()

    def flushDatabaseBinlog(self):  # 調用此函數,將會執行  mysqladmin flush-logs ,刷新binlog日志
        return os.popen(self.__FLUSH_LOG_COMMAND + self.__LOGINARGS + ' flush-logs')

    def dumpDatabaseSQL(self):  #|通過mysqladmin 對指定數據庫進行全備
        if not os.path.isfile(self.__BACKUP_DIR + '/' + self.__PROJECTNAME + '/' +  str(self.__YESTERDAY) + '-' + self.__PROJECTNAME + '.sql'):
            return os.popen(self.__DUMP_COMMAND + self.__LOGINARGS + self.__ENGINE + ' '.join(
                self.__DATABASE_LIST) + ' >> ' + self.__BACKUP_DIR + '/' + self.__PROJECTNAME + '/' + str(
                self.__YESTERDAY) + '-' + self.__PROJECTNAME + '.sql')
        else:
            sys.stderr.write('Backup File [' + str(self.__YESTERDAY) + '-' + self.__PROJECTNAME + '.sql]  already exists.\n')



    def dumpDatabaseBinlog(self):#通過copy2() 將需要備份的binlog日志復制到指定備份目錄

        if not os.path.isfile(self.__BACKUP_DIR + '/' + self.__PROJECTNAME + '/' + str(self.__YESTERDAY) + '-' + os.path.split(self.__getBinlogPath())[1]):
            from shutil import copy2
            try:
                copy2(self.__getBinlogPath(), self.__BACKUP_DIR + '/' + self.__PROJECTNAME + '/' + str(self.__YESTERDAY) + '-' + os.path.split(self.__getBinlogPath())[1])
            except BaseException, e:
                sys.stderr.write(str(e))
        else:
            sys.stderr.write('Binlog File [' + str(self.__YESTERDAY) + '-' + os.path.split(self.__getBinlogPath())[1] + '] already exists\n' )


    def checkDatabaseArgs(self):  #對一些必要條件進行檢查
        __rv = 0

        if not os.path.isdir(self.__MYSQL_BASE_DIR):  #檢查指定的mysql安裝目錄是否存在
            sys.stderr.write('MYSQL BASE DIR: [ ' + self.__MYSQL_BASE_DIR + ' ] NOT FOUND\n')
            __rv += 1

        if not os.path.isdir(self.__BACKUP_DIR):   #檢查指定的備份目錄是否存在,如不存在自動創建
            sys.stderr.write('BACKUP DIR: [ ' + self.__BACKUP_DIR + '/' + self.__PROJECTNAME +  ' ] NOT FOUND ,AUTO CREATED\n')
            os.makedirs(self.__BACKUP_DIR + '/' + self.__PROJECTNAME)

        if not os.path.isfile(self.__MYSQL_CONFIG_FILE): #檢查mysql配置文件是否存在
            sys.stderr.write('MYSQL CONFIG FILE: [' + self.__MYSQL_CONFIG_FILE + ' ] NOT FOUND\n')
            __rv += 1

        if not os.path.isfile(self.__DUMP_COMMAND):  #檢查備份數據庫時使用的mysqldump命令是否存在
            sys.stderr.write('MYSQL DUMP COMMAND: [' + self.__DUMP_COMMAND + ' ] NOT FOUND\n')
            __rv += 1

        if not os.path.isfile(self.__FLUSH_LOG_COMMAND): #檢查刷新mysql binlog日志使用的mysqladmin命令是否存在
            sys.stderr.write('MYSQL FLUSH LOG COMMAND: [' + self.__DUMP_COMMAND + ' ] NOT FOUND\n')
            __rv += 1

        if not self.__DATABASE_LIST:  #檢查需要備份的數據庫列表是否存在
            sys.stderr.write('Database List is None \n')
            __rv += 1

        if __rv:   # 判斷返回值,由于上述任何一步檢查失敗,都會導致 __rv 值 +1 ,只要最后__rv != 0就直接退出了。
            sys.exit(1)


def crontab():  # 使用字典,來進行相關參數傳遞,并實例化對象,調用相關方法進行操作

    zabbix = {
        'baseDir': '/usr/local/mysql/',
        'backDir': '/backup/',
        'projectName': 'Monitor',
        'dbList': ['zabbix'],
        'host': 'localhost',
        'port': 3306,
        'user': 'root',
        'passwd': 'xxxxxxx'
    }

    monitor = DatabaseArgs(**zabbix)
    monitor.dumpDatabaseSQL()
    monitor.dumpDatabaseBinlog()
    monitor.flushDatabaseBinlog()

if __name__ == '__main__':
    crontab()

my.cnf

[client]
port                            = 3306
socket                          = /mysql/var/db.socket

[mysqld]
socket                          = /mysql/var/db.socket
datadir                         = /mysql/db/
skip-external-locking           = 1
skip-innodb                     = 0 
key_buffer_size                 = 256M
max_allowed_packet              = 10M
table_open_cache                = 2048
sort_buffer_size                = 4M
read_buffer_size                = 4M
read_rnd_buffer_size            = 8M
myisam_sort_buffer_size         = 64M
myisam_max_sort_file_size       = 1G
myisam_repair_threads           = 1
myisam_recover                  = DEFAULT
thread_cache_size               = 32
query_cache_size                = 32M
query_cache_min_res_unit        = 2k
bulk_insert_buffer_size         = 64M
tmp_table_size                  = 128M
thread_stack                    = 192K
skip-name-resolve               = 1
max_connections                 = 65500
default-storage-engine          = myisam
federated                       = 0
server-id                       = 1
slave-skip-errors               = all
#log                            = /var/log/sql_query.log
slow-query-log                  = 1
slow-query-log-file             = /mysql/log/sql_query_slow.log
long-query-time                 = 5
log-queries-not-using-indexes   = 1
log-slow-admin-statements       = 1
log-bin                         = /mysql/var/log/binlog/bin-log
log-error                       = /mysql/var/log/mysql.err
master-info-file                = /mysql/var/log/master.info
relay-log                       = /mysql/var/log/relay-bin/relay-bin
relay-log-index                 = /mysql/var/log/relay-bin/relay-bin.index
relay-log-info-file             = /mysql/var/log/relay-bin/relay-bin.info
binlog_cache_size               = 8M
binlog_format                   = MIXED
max_binlog_cache_size           = 20M
max_binlog_size                 = 1G
binlog-ignore-db                = mysql
binlog-ignore-db                = performance_schema
binlog-ignore-db                = information_schema
replicate-ignore-db             = mysql
replicate-ignore-db             = performance_schema
replicate-ignore-db             = information_schema

innodb_data_home_dir            = /mysql/ibdata/
innodb_data_file_path           = ibdata:156M:autoextend
innodb_log_group_home_dir       = /mysql/ibdata/
log-slave-updates               = 0
back_log                        = 512
transaction_isolation           = READ-COMMITTED
max_heap_table_size             = 246M
interactive_timeout             = 120
wait_timeout                    = 120
innodb_additional_mem_pool_size = 16M
innodb_buffer_pool_size         = 512M
innodb_file_io_threads          = 4
innodb_thread_concurrency       = 8
innodb_flush_log_at_trx_commit  = 2
innodb_log_buffer_size          = 16M
innodb_log_file_size            = 128M
innodb_log_files_in_group       = 3
innodb_max_dirty_pages_pct      = 90
innodb_lock_wait_timeout        = 120
innodb_file_per_table           = 1
innodb_open_file                = 327500
open_files_limit                = 327500

[mysqldump]
quick                           = 1
max_allowed_packet              = 50M

[mysql]
auto-rehash                     = 1
socket                          = /mysql/var/db.socket
safe-updates                    = 0

[myisamchk]
key_buffer_size                 = 256M
sort_buffer_size                = 256M
read_buffer                     = 2M
write_buffer                    = 2M

[mysqlhotcopy]
interactive-timeout             = 100

最終生成的備份目錄結構是這樣的

[root@zabbix backup]# find ./
./
./Monitor
./Monitor/2013-03-16-bin-log.000008
./Monitor/2013-03-14-bin-log.000006
./Monitor/2013-03-16-Monitor.sql
./Monitor/2013-03-15-Monitor.sql
./Monitor/2013-03-15-bin-log.000007
./Monitor/2013-03-14-Monitor.sql

~END~


 本文由用戶 ybw8 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!