程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> 使用 python 管理 mysql 開發工具箱,pythonmysql

使用 python 管理 mysql 開發工具箱,pythonmysql

編輯:MySQL綜合教程

使用 python 管理 mysql 開發工具箱,pythonmysql


這篇博文接著上篇文章《使用 python 管理 mysql 開發工具箱 - 1》,繼續寫下自己學習 python 管理 MySQL 中的知識記錄。

一、MySQL 的讀寫分離

學習完 MySQL 主從復制之後,可以考慮實現 MySQL 的讀寫分離,從而提高 MySQL 系統的整體性能。具體控制讀寫的路由功能可以交給應用程序或者MySQL-Proxy 程序來實現。讀寫分離其實就是讓 Client 寫入 master,而讀數據從 slave 節點,這樣減少了 master 既寫又讀的壓力。這裡沒有具體介紹如何實現讀寫分離的功能,後續研究一下 MySQL Proxy 程序,這是 MySQL 官方提供的實現讀寫分離的程序。

 

二、slave 節點的負載均衡

1. 使用 DNS 來實現負載均衡

往往 slave 節點是多個,實現 slave 節點的負載均衡是非常重要的。其實可以采用 dns 的功能,一個域名指向多個 slave 的 IP 地址,這樣 Client 每次解析到的 slave 地址都是平均分布的,簡單的實現了負載均衡的功能。

2. 健康檢查監控

我們自己需要實現一個監控程序,檢查 slave 的健康情況,包括如下幾個方面:

  • 是否能連接 slave 節點,判斷 timeout 是否會超時即可
  • 檢查 slave 狀態,是否能正常工作。執行 show slave status\G; 查看 IO/SQL Running 是否正常。
  • 主從同步時間間隔是否過長。如果 Second_behind_master > 2 認為太慢了

監控程序掃描所有 slave 節點,判斷上述指標,把健康的 slave 節點加入到 DNS 解析記錄裡邊,有問題的剔除出去。

 

三、DNS 基本安裝和配置

1. 安裝 rpm 包

[root@vip ~]# yum install bind -y

2. 修改配置文件named.conf

options {
    listen-on port 53 { any; };    # 修改為any
    listen-on-v6 port 53 { ::1; };
    ... ... ... ...
    allow-query     { any; };      # 修改為any

添加內容:

zone "example.com" IN {
    type master;
    file "example.com.zone";
};

3. 添加設置區域zone文件

[root@vip ~]# vim /var/named/example.com.zone     # 添加如下內容
$TTL 1D
@   IN SOA  ns.example.com. root.example.com. (
                    0   ; serial
                    1D  ; refresh
                    1H  ; retry
                    1W  ; expire
                    3H ); minimum
    NS  ns.example.com.
ns  A   192.168.0.8
www A   192.168.0.2

4. 啟動named服務

[root@vip ~]# service named start

5. 測試dns解析

[root@vip ~]# host www.example.com. localhost
Using domain server:
Name: localhost
Address: :: 1 #53
Aliases:     # 成功解析OK。
www.example.com has address 192.168.0.2

 

四、DNS 實現動態記錄更新

DNS動態更新必要性:

  • 某個slave出現故障,DNS應該將該slave剔除,不要解析這個slave節點
  • 復制比較慢,拖後腿的slave節點也應該剔除出去。

考慮:類似keepalived的健康檢查。

1. 生成key文件

[root@vip ~]# dnssec-keygen -a HMAC-MD5 -b 256 -n HOST -r /dev/urandom dnskey

生成 2 個文件:

[root@vip ~]# ls Kexample.com.+157+46922.*
Kexample.com.+157+46922.key  Kexample.com.+157+46922.private

2. 修改配置文件named.conf,讓dns支持更新:添加如下代碼

key "example.com" {    # 該key為新增加內容
    algorithm HMAC-MD5;
    secret "25z/5wjwD4GsMgQluWagfkQ9TSqpoJzYbh/I/QEZo2M=";   # secret內容參考Kexample.com.+157+46922.key文件內容
};

zone "example.com" IN {
    type master;
    file "example.com.zone";
    allow-update { key "example.com"; };   # 增加一行
};

3. 創建update.txt文件

使用nsupdate前需要創建個文件,告訴nsupdate怎麼樣去更新update.txt,內容如下:

server 127.0.0.1
debug yes 
zone example.com.
update delete s.db.example.com. A
update add s.db.example.com. 86499 A 192.168.0.1
update add s.db.example.com. 86499 A 192.168.0.2
update add s.db.example.com. 86499 A 192.168.0.8
update add s.db.example.com. 86499 A 127.0.0.1
show 
send

4. 賦予/var/named目錄寫權限

chmod g+w /var/named

5. 手動更新dns記錄

[root@vip ~]# nsupdate -k Kdnskey.+157+42183.key update.txt

6. 驗證

[root@vip ~]# host s.db.example.com localhost
Using domain server:
Name: localhost
Address: ::1#53
Aliases: 
s.db.example.com has address 192.168.0.1
s.db.example.com has address 192.168.0.2
s.db.example.com has address 192.168.0.8
s.db.example.com has address 127.0.0.1

7. 問題總結

  • 1. 看日志文件log
  • 2. 看權限錯誤
  • 3. 看程序的用戶 ps -ef | grep named
  • 4. 看相關配置文件的權限
  • 5. iptables和selinux是否關閉

 

五、Python 實現 DNS 查詢

需要使用到 dnspython 模塊,需要執行 pip install dnspython 安裝此模塊。

參考:http://blog.chinaunix.net/uid-24690947-id-1747409.html

 

六、Python 實現 DNS 動態更新

代碼參考:

# 動態更新dns記錄
def dnsUpdate(zone, name, rdlist):
    key = dns.tsigkeyring.from_text({zone:keyring})
    up = dns.update.Update(zone, keyring=key)
    rdata_list = [dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, i) for i in rdlist]
    ttl = 60
    rdata_set  = dns.rdataset.from_rdata_list(ttl, rdata_list)
    up.replace(name, rdata_set)
    q = dns.query.tcp(up, '127.0.0.1')
# 調用
dnsUpdate('example.com', 's.db', alive)

 

七、MySQL 從服務器狀態檢查

按照檢查的要求,對 slave 進行健康檢查,代碼如下:

#!/usr/bin/env python
#encoding: utf-8

import MySQLdb

# 通過shell命令獲取key列表格式
# mysql -S /tmp/slave01.sock -e "show slave status\G" | awk -F: 'NR!=1{print $1}' | awk '{printf "\""$1"\",\n"}' > a.txt
keys = (
    "Slave_IO_State",
    "Master_Host",
    "Master_User",
    "Master_Port",
    "Connect_Retry",
    "Master_Log_File",
    "Read_Master_Log_Pos",
    "Relay_Log_File",
    "Relay_Log_Pos",
    "Relay_Master_Log_File",
    "Slave_IO_Running",
    "Slave_SQL_Running",
    "Replicate_Do_DB",
    "Replicate_Ignore_DB",
    "Replicate_Do_Table",
    "Replicate_Ignore_Table",
    "Replicate_Wild_Do_Table",
    "Replicate_Wild_Ignore_Table",
    "Last_Errno",
    "Last_Error",
    "Skip_Counter",
    "Exec_Master_Log_Pos",
    "Relay_Log_Space",
    "Until_Condition",
    "Until_Log_File",
    "Until_Log_Pos",
    "Master_SSL_Allowed",
    "Master_SSL_CA_File",
    "Master_SSL_CA_Path",
    "Master_SSL_Cert",
    "Master_SSL_Cipher",
    "Master_SSL_Key",
    "Seconds_Behind_Master",
    "Master_SSL_Verify_Server_Cert",
    "Last_IO_Errno",
    "Last_IO_Error",
    "Last_SQL_Errno",
    "Last_SQL_Error",
)

# 模擬一下slave節點列表, 設置注意實驗時設置某些實例為不健康狀態
conf = {
    'master':'127.0.0.1:3306',
    'slave':[
            '127.0.0.1:3307',
            '192.168.0.8:3307',
            '127.0.0.1:3308',
            '192.168.0.8:3308',
            '127.0.0.1:3309',
            '192.168.0.8:3309',
    ]
}

# 檢查slave節點的狀態是否正常
def checkSlaveStatus(host, port):
    try:
        conn = MySQLdb.connect(host=host, port=port, user='root', connect_timeout=1)
    except Exception, e:
        print e
        return False
    cur = conn.cursor()
    cur.execute('show slave status')
    data = cur.fetchall()    # 只獲取到了冒號後邊的value, key沒有獲取到, 和sql shell顯示不同.

    # 將keys和data組合為字典的結構
    data = dict(zip(keys, data[0]))
    
    # IO/SQL Running 是否正常
    if data['Slave_IO_Running'] == 'No' or data['Slave_SQL_Running'] == 'No':
        return False
    elif data['Seconds_Behind_Master'] > 2:  # 主從復制時間持續超過2秒, 太慢了
        return False

    # 到這裡肯定是沒問題的了
    return True

# 將ip:port解析為主機+端口
def parseIP(s):
    host, port = s.split(':')
    return host, int(port)

if __name__ == '__main__':
    #host = '127.0.0.1' # 寫IP好像連不上, 需要授權相應的主機
    #port = 3307
    alive = []
    for ip in conf['slave']:
        host, port = parseIP(ip)
        print checkSlaveStatus(host, port)

 

八、MySQL 從服務器狀態更新

對 slave 健康狀態檢查後,將健康的節點列表記錄,更新到 DNS 記錄中。代碼如下:

#!/usr/bin/env python
#encoding: utf-8

import MySQLdb
import dns.query
import dns.update
import dns.tsigkeyring

# 通過shell命令獲取key列表格式
# mysql -S /tmp/slave01.sock -e "show slave status\G" | awk -F: 'NR!=1{print $1}' | awk '{printf "\""$1"\",\n"}' > a.txt
keys = (
    "Slave_IO_State",
    "Master_Host",
    "Master_User",
    "Master_Port",
    "Connect_Retry",
    "Master_Log_File",
    "Read_Master_Log_Pos",
    "Relay_Log_File",
    "Relay_Log_Pos",
    "Relay_Master_Log_File",
    "Slave_IO_Running",
    "Slave_SQL_Running",
    "Replicate_Do_DB",
    "Replicate_Ignore_DB",
    "Replicate_Do_Table",
    "Replicate_Ignore_Table",
    "Replicate_Wild_Do_Table",
    "Replicate_Wild_Ignore_Table",
    "Last_Errno",
    "Last_Error",
    "Skip_Counter",
    "Exec_Master_Log_Pos",
    "Relay_Log_Space",
    "Until_Condition",
    "Until_Log_File",
    "Until_Log_Pos",
    "Master_SSL_Allowed",
    "Master_SSL_CA_File",
    "Master_SSL_CA_Path",
    "Master_SSL_Cert",
    "Master_SSL_Cipher",
    "Master_SSL_Key",
    "Seconds_Behind_Master",
    "Master_SSL_Verify_Server_Cert",
    "Last_IO_Errno",
    "Last_IO_Error",
    "Last_SQL_Errno",
    "Last_SQL_Error",
)

# 模擬一下slave節點列表, 設置注意實驗時設置某些實例為不健康狀態
conf = {
    'master':'127.0.0.1:3306',
    'slave':[
            '127.0.0.1:3307',
            '192.168.0.8:3307',
            '127.0.0.1:3308',
            '192.168.0.8:3308',
            '127.0.0.1:3309',
            '192.168.0.8:3309',
    ]
}

keyring = '25z/5wjwD4GsMgQluWagfkQ9TSqpoJzYbh/I/QEZo2M='

# 檢查slave節點的狀態是否正常
def checkSlaveStatus(host, port):
    try:
        conn = MySQLdb.connect(host=host, port=port, user='root', connect_timeout=1)
    except Exception, e:
        print e
        return False
    cur = conn.cursor()
    cur.execute('show slave status')
    data = cur.fetchall()    # 只獲取到了冒號後邊的value, key沒有獲取到, 和sql shell顯示不同.

    # 將keys和data組合為字典的結構
    data = dict(zip(keys, data[0]))
    
    # IO/SQL Running 是否正常
    if data['Slave_IO_Running'] == 'No' or data['Slave_SQL_Running'] == 'No':
        return False
    elif data['Seconds_Behind_Master'] > 2:  # 主從復制時間持續超過2秒, 太慢了
        return False

    # 到這裡肯定是沒問題的了
    return True

# 將ip:port解析為主機+端口
def parseIP(s):
    host, port = s.split(':')
    return host, int(port)


# 動態更新dns記錄
def dnsUpdate(zone, name, rdlist):
    key = dns.tsigkeyring.from_text({zone:keyring})
    up = dns.update.Update(zone, keyring=key)
    rdata_list = [dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, i) for i in rdlist]
    ttl = 60
    rdata_set  = dns.rdataset.from_rdata_list(ttl, rdata_list)
    up.replace(name, rdata_set)
    q = dns.query.tcp(up, '127.0.0.1')
    #print q
    

if __name__ == '__main__':
    #host = '127.0.0.1' # 寫IP好像連不上, 需要授權相應的主機
    #port = 3307
    alive = []
    for ip in conf['slave']:
        host, port = parseIP(ip)
        if checkSlaveStatus(host, port):
            alive.append(host)
    # 解釋下這裡為什麼要設置slave的alive集群阈值
    # 如果不設置阈值, 那麼存在健康的slave過少, 會導致slave的雪崩現象
    # 反而會影響服務的正常運行, 保證只有在一定數量情況下才更新dns記錄.
    if float(len(alive))/len(conf['slave']) > 0.6:
        dnsUpdate('example.com', 's.db', alive)


# 注意:
# 1. dns服務一定要保證/var/named目錄組用戶有寫的權限
# 2. iptables 和 selinux 一定要設置好, 最好設置為關閉狀態.

 

九、MySQL 監控測試

通過上邊的代碼已經實現了 slave 的健康檢查,DNS 的動態更新。現在可以做一下測試:

> 執行:

[root@vip mysqlmanager]# python mysql_dns_monitor.py

> 結果:

[root@vip mysqlmanager]# host s.db.example.com localhost
Using domain server:
Name: localhost
Address: ::1#53
s.db.example.com has address 127.0.0.1   # 已經更新了記錄
s.db.example.com has address 192.168.0.8 # 更新了記錄,並解析到ip地址,表明已經成功OK.

> 擴展:
其實可以准備幾台獨立的虛擬機來做測試,每台虛擬機作為要給 slave 節點,模擬一些健康問題,看是否能夠正確檢測並更新到。

十、MySQL 從服務器信息來自CMDB

待更新。。。。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved