MySQL數據庫主從切換腳本自動化

      在一些實際環境中,如何實現主從的快速切換,在沒有MHA等工具的輔助下,如何避免影響線上的業務,一般都會在在業務低峯期進行主從切換,本腳本主要利用MySQL自帶的命令行工具(FLUSH TABLES WITH READ LOCK)進行鎖全庫,且由用戶自行輸入判斷多少秒內從庫BINLOG數據不在同步後,認爲主從數據已達一致性可以進行主從切換(在一些資料上說也可以用READ-ONLY來鎖庫,但需要注意如果寫入用戶具有Admin權限是不受限制),主從切換完成5秒後進行檢查主從是否同步問題.

##連接數據庫使用TCP/IP方式,需要相應的操作數據庫權限。

##目前判斷使用show master status  來判斷,可以show slave status返回的值來判斷,自行修改。

腳本:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import MySQLdb
import time
import sys
class m_s:
    def __init__(self,host,user,password,port):
        self.host=host
        self.user=user
        self.passowrd=password
        self.port=port
    def getConn(self,db="mysql"):
        try:
            conn=MySQLdb.connect(host=self.host, user=self.user, passwd=self.passowrd, db=db, port=self.port, charset="utf8")
            cur = conn.cursor()
            return cur
        except Exception as e:
            return e
    def execSQLlock(self,*args):
        flush_sql="FLUSH TABLES WITH READ LOCK"
        cur.execute(flush_sql)
    def execIo(self,cur,command):
        cur.execute(command)
        db_pos = cur.fetchall()
        for value in db_pos:
            value=value
        return value
    def exeStop(self,cur,command):
        cur.execute(command)
        db_pos = cur.fetchall()
        return db_pos
    def execSQLstatus(self,*args):
        n=0
        self.execSQLlock(cur)
        flush_m = "flush logs"
        cur.execute(flush_m)
        while True:
            data=[]
            slave_pos=[]
            n=n+1
            exe_sql = "select Command,State,Info,Id from information_schema.processlist"
            cur.execute(exe_sql)
            plist = cur.fetchall()
            for li in range(len(plist)):
                if plist[li][0] == "Query" and plist[li][1] == "Waiting for global read lock":
                    lock_id = "kill " + str(plist[li][3])
                    print plist[li][2]
                    cur.execute(lock_id)
            slave_pos.append(self.execIo(cur1, "show master status")[1])
            data.append(self.execIo(cur1,"show slave status")[6]) ##從庫的遊標
            time.sleep(1)
            slave_pos.append(self.execIo(cur1, "show master status")[1])
            data.append(self.execIo(cur,"show master status")[1])##從庫的遊標
            print ".......",data,slave_pos
            if data[0]==data[1] and slave_pos[0]==slave_pos[1]:
                try:
                    print "第%s次判斷數據已經同步....."%n
                    if n==c_time:
                        print "開始主從切換工作........"
                        self.exeStop(cur1,"stop slave") ##停止從庫同步
                        new_pos=self.exeStop(cur1,"show master status")#獲取新主庫的FILE和POS的值,遊標爲還沒切換前的從庫
                        #print "獲取新主庫的FILE和POS的值,遊標爲還沒切換前的從庫",new_pos
                        self.exeStop(cur,"reset master;")##主庫釋放從庫主從信息......
                        ##在從庫執行new_change 指向新的主庫
                        self.exeStop(cur1,"reset slave all")
                        new_change="change master to master_host='"+str(args[1])+"'"+",master_user='"+args[2]+"'"+",master_password='"+args[3]+"',master_port="+str(args[4])+",MASTER_LOG_FILE='"+str(new_pos[0][0])+"'"+",MASTER_LOG_POS="+str(new_pos[0][1])
                        print new_change
                        self.exeStop(cur,new_change)##在原來主庫上執行change master to.....
                        #print "在原來主庫上執行change master to...."
                        self.exeStop(cur,"start slave")  ##在原來主庫上執行change master to.....
                        time.sleep(5)
                        s_pos=self.exeStop(cur,"show slave status;")
                        #print s_pos[0][10],s_pos[0][11]
                        if s_pos[0][10]=="Yes" and s_pos[0][11]=="Yes":
                            self.exeStop(cur1,"reset slave all")
                            print  "主從切換成功!"
                            print "\n"
                            while True:
                                print "等待其他操作完成,即將unlock tables主庫......"
                                try:
                                    stop = raw_input("輸入終止命令q即完成此次操作:\n")
                                    if stop == "q":
                                        sys.exit()
                                        # break
                                except Exception as e:
                                    print "good bye"

                        else:
                            print   s_pos[0][19]
                        break
                except Exception as e:
                    return e
            else:
                print "主從數據未達到一致性..........",n
                n=0
                data=[]

if __name__ =="__main__":
    c_time=int(raw_input("多少秒後進行主從切換..>>"))
    print "****************************************************\n"

    print "請根據提示輸入指定信息:"
    m_host = raw_input("目前主庫的地址:")
    m_user = raw_input("目前主庫的登陸用戶名:")
    m_password = raw_input("目前主庫的密碼:")
    m_port = int(raw_input("目前主庫的端口:"))
    print "****************************************************\n"
    s_host = raw_input("目前從庫的地址:")
    s_user = raw_input("目前從庫的登陸用戶名:")
    s_password = raw_input("目前從庫的密碼:")
    s_port = int(raw_input("目前從庫的端口:"))
    M = m_s(m_host, m_user, m_password, m_port)
    S = m_s(s_host,s_user,s_password,s_port)
    cur = M.getConn()  ##獲取主庫遊標
    cur1 = S.getConn()  ##獲取從庫遊標
    print "*****************************************************\n"
    print "主從同步用戶信息.........\n"
    s_user1 = raw_input("輸入主從同步的用戶>>:")
    s_password1 = raw_input("輸入主從同步的密碼:")
    s_port1 = int(raw_input("輸入主從同步的端口:"))

    M.execSQLstatus(cur,s_host,s_user1,s_password1,s_port1)



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章