在一些實際環境中,如何實現主從的快速切換,在沒有MHA等工具的輔助下,如何避免影響線上的業務,通常都會在在業務低峯期進行主從切換,本腳本主要利用MySQL自帶的命令行工具(FLUSH TABLES WITH READ LOCK
)進行鎖全庫,且由用戶自行輸入判斷多少秒內從庫BINLOG數據不在同步後,認爲主從數據已達一致性能夠進行主從切換(在一些資料上說也能夠用READ-ONLY來鎖庫,但須要注意若是寫入用戶具備Admin權限是不受限制),主從切換完成5秒後進行檢查主從是否同步問題.python
鏈接數據庫使用TCP/IP方式,須要相應的操做數據庫權限。mysql
目前判斷使用show master status 來判斷,能夠show slave status返回的值來判斷,自行修改。sql
yum install MySQL-python
腳本:switch_master_slave.py
數據庫
#!/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)
# python switch_master_slave.py 多少秒後進行主從切換..>>5 **************************************************** 請根據提示輸入指定信息: 目前主庫的地址:192.168.56.100 目前主庫的登錄用戶名:wanbin 目前主庫的密碼:mysql 目前主庫的端口:3306 **************************************************** 目前從庫的地址:192.168.56.200 目前從庫的登錄用戶名:wanbin 目前從庫的密碼:mysql 目前從庫的端口:3306 ***************************************************** 主從同步用戶信息......... 輸入主從同步的用戶>>:repl 輸入主從同步的密碼:wanbin 輸入主從同步的端口:3306 ....... [234L, 234L] [250L, 250L] 第1次判斷數據已經同步..... ....... [234L, 234L] [250L, 250L] 第2次判斷數據已經同步..... ....... [234L, 234L] [250L, 250L] 第3次判斷數據已經同步..... ....... [234L, 234L] [250L, 250L] 第4次判斷數據已經同步..... ....... [234L, 234L] [250L, 250L] 第5次判斷數據已經同步..... 開始主從切換工做........ change master to master_host='192.168.56.200',master_user='repl',master_password='wanbin',master_port=3306,MASTER_LOG_FILE='my3306_binlog.000018',MASTER_LOG_POS=250 switch_master_slave.py:29: Warning: Sending passwords in plain text without SSL/TLS is extremely insecure. cur.execute(command) switch_master_slave.py:29: Warning: Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information. cur.execute(command) 主從切換成功! 等待其餘操做完成,即將unlock tables主庫...... 輸入終止命令q即完成這次操做: 等待其餘操做完成,即將unlock tables主庫...... 輸入終止命令q即完成這次操做: q 等待其餘操做完成,即將unlock tables主庫...... 輸入終止命令q即完成這次操做: q