天天看點

美團點評DBProxy讀寫分離使用說明

目的

      因為業務架構上需要實作讀寫分離,剛好前段時間美團點評開源了在360Atlas基礎上開發的讀寫分離中間件DBProxy,關于其介紹在官方文檔已經有很詳細的說明了,其特性主要有:讀寫分離、負載均衡、支援分表、IP過濾、sql語句黑名單、DBA平滑下線DB、從庫流量配置、動态加載配置項。本文大緻簡單的介紹自己在使用中如何快速安裝和使用DBProxy。

環境

Ubuntu 16.04.1 LTS      

注意:由于DBProxy在16.04上面會有報錯,因為在Ubuntu16.04上面libmysqlclient-dev源是MySQL5.7,詳細的問題可以看這篇文章。是以需要重新設定其源,若是16.04以下版本可以跳過此步。

add-apt-repository 'deb http://archive.ubuntu.com/ubuntu trusty universe'
      

源替換了之後,還需要把16.04的源先注視掉,不然還是會裝MySQL5.7。最後在update:

sudo apt-get update      

安裝

① 安裝依賴包:

apt-get install libmysqlclient-dev libgcrypt11-dev  pkg-config lua5.1-0 liblua5.1-0-dev libtool flex bison openssl  libssl-dev libjemalloc1 libjemalloc-dev  libevent-dev autoconf gettext libffi-dev      

② 安裝 glib-2.42.0 

wget http://ftp.gnome.org/pub/GNOME/sources/glib/2.42/glib-2.42.0.tar.xz      

由于目前确認有效的glib2版本是2.42.0-1.el6,CentOS、Ubuntu和Debian預設源中的版本都不是2.42.0-1.el6,會導緻make報錯,是以在上面增加對glib的下載下傳編譯安裝。

解壓:
xz -d glib-2.42.0.tar.xz 
tar xvf glib-2.42.0.tar

編譯:
cd glib-2.42.0
autoreconf -ivf
./configure --prefix=/usr/local/glib-2.42
make
make install      

③ 安裝DBProxy

下載下傳:
git clone https://github.com/Meituan-Dianping/DBProxy.git

安裝:
cd DBProxy/
sh autogen.sh      

注意:

不使用預設的glib,使用上面新編譯的版本,變更glib編譯選項,替換原始的bootstrap.sh的内容:

vi bootstrap.sh
+++++++++++++++++++++++++++

#!/bin/sh 
base=$(cd "$(dirname "$0")"; pwd)
cd $base
./configure --prefix=/usr/local/mysql-proxy CFLAGS="-g -O0" \
GLIB_CFLAGS="-I/usr/local/glib-2.42/include/glib-2.0 -I/usr/local/glib-2.42/lib/glib-2.0/include" \
GLIB_LIBS="-L/usr/local/glib-2.42/lib -lglib-2.0" \
GMODULE_CFLAGS="-pthread -I/usr/local/include/glib-2.0 -I/usr/local/lib/glib-2.0/include" \
GMODULE_LIBS="-L/usr/local/glib-2.42/lib -Wl,--export-dynamic -lgmodule-2.0 -pthread -lrt" \
GTHREAD_CFLAGS="-pthread -I/usr/local/glib-2.42/include/glib-2.0 -I/usr/local/glib-2.42/lib/glib-2.0/include" \
GTHREAD_LIBS="-L/usr/local/glib-2.42/lib -lgthread-2.0 -pthread -lrt"
+++++++++++++++++++++++++++

sh bootstrap.sh
make
make install      

成功編譯安裝完成之後,預設安裝路徑是:

/usr/local/mysql-proxy      

④ 啟動DBProxy

建立配置檔案目錄:

mkdir /usr/local/mysql-proxy/conf      

初始化配置檔案:建議配置檔案和DBProxy執行個體名保持一緻。

cp script/source.cnf.samples /usr/local/mysql-proxy/conf/source.cnf      

腳本啟動:

$install_path/mysql-proxyd $instance_name(執行個體名) start/restart/stop 

root@dbtest:/usr/local/mysql-proxy# ./bin/mysql-proxyd source start
OK: MySQL-Proxy of source is started

root@dbtest:/usr/local/mysql-proxy# ps -ef | grep mysql
root     23000     1  0 02:44 ?        00:00:00 /usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/mysql-proxy/conf/source.cnf
root     23001 23000  0 02:44 ?        00:00:00 /usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/mysql-proxy/conf/source.cnf      

到此安裝結束,接着介紹下配置檔案。

配置檔案

根據需要,把配置檔案改名成proxy_test.cnf(/usr/local/mysql-proxy/conf),對應的執行個體名為proxy_test,具體的配置資訊如下:

[mysql-proxy]
#設定DBProxy程序的所屬使用者以及日志的所屬使用者等 該指令在非root使用者啟動時不生效,隻有在root使用者下,配置存在的user時才會生效
#user=mysql
#管理接口的使用者名
admin-username=guest
#管理接口的密碼
admin-password=guest
#dbproxy監聽的管理接口IP和端口
admin-address=0.0.0.0:3309
#使用者名與其對應的加密過的MySQL密碼,密碼使用PREFIX/bin目錄下的加密程式encrypt加密,将其替換為你的MySQL的使用者名和加密密碼!
pwds=dxy_proxy:uK6+XM9x2YRDabHitUtqIK5KOLfO
#dbproxy監聽的工作接口IP和端口
proxy-address=0.0.0.0:3308
#dbproxy後端連接配接的MySQL主庫的IP和端口
proxy-backend-addresses=192.168.200.202:3306
#dbproxy後端連接配接的MySQL從庫的IP和端口,@後面的數字代表權重,用來作負載均衡,若省略則預設為1,可設定多項,用逗号分隔
proxy-read-only-backend-addresses=192.168.200.132:3306@3
#在原有配置從庫的基礎上,可以對從庫指定tag名
#例如:proxy-read-only-backend-addresses=xx.xx.xx.xx:3306$tag_mt@10,xx.xx.xx.xx:3306
#執行個體名稱,用于同一台機器上多個dbproxy執行個體間的區分
instance=proxy_test
#日志存放的路徑
log-path=/var/log/dbproxy_log/
#SQL日志的開關,可設定為OFF、ON、REALTIME,OFF代表不記錄SQL日志,ON代表記錄SQL日志,REALTIME代表記錄SQL日志且實時寫入磁盤,預設為OFF
sql-log=REALTIME
#日志級别,分為message、warning、critical、error、debug五個級别
log-level=message
#工作線程數,對dbproxy的性能有很大影響,可根據情況适當設定,預設是1。DBProxy的線程分這幾類:日志等輔助功能的線程、主線程、工作線程。這個參數指的是工作線程數
event-threads=16
#設定dbproxy的運作方式,設為true時為守護程序方式,設為false時為前台方式,一般開發調試時設為false,線上運作時設為true
daemon=true
#設定dbproxy的運作方式,設為true時dbproxy會啟動兩個程序,一個為monitor,一個為worker,monitor在worker意外退出後會自動将其重新開機,設為false時隻有worker,沒有monitor,一般開發調試時設為false,線上運作時設為true
keepalive=1
#分表設定,此例中person為庫名,mt為表名,id為分表字段,3為子表數量,可設定多項,以逗号分隔,若不分表則不需要設定該項
#tables = person.mt.id.3
#是否限制WHERE語句。ON: SELECT 後必須有WHERE 語句
select-where-limit=OFF
#dbproxy前面挂接的LVS的實體網卡的IP(注意不是虛IP),若有LVS且設定了client-ips則此項必須設定,否則可以不設定
#lvs-ips = 192.168.1.1
#DBProxy最大連接配接數
max-connections=1000
#長等待的門檻值,超過該值則認定為同步等待時間過長,列印warning(機關ms)
long-wait-time=500
#慢查詢門檻值,查詢執行時間超過該門檻值則認為是慢查詢(機關ms)
long-query-time=3000
#0:不統計,1:僅統計總體的響應時間,其中包括慢查詢,2:進行直方圖統計;預設為1。
query-response-time-stats=2
#SQL日志檔案最大大小,機關為位元組,預設為1G
sql-log-file-size=1073741824
#保留的最大SQL日志檔案個數,預設為0,不保留曆史檔案,僅保留目前檔案
sql-log-file-num=50
#背景MySQL版本号,預設為5.5
mysql-version=5.6
#DBProxy 用戶端連接配接的 timeout,如果連接配接到 DBProxy 的連接配接空閑超過此值,DBProxy 會關閉此連接配接(機關ms)
wait-timeout=86400
#DBProxy 連接配接池中連接配接的空閑時間
db-connection-idle-timeout=3600
#連接配接池中連接配接的生存周期
db-connection-max-age=7200
#背景MySQL最大連接配接數,預設為0,表示不限制
backend-max-thread-running=0
#指定當 backend 的 thread running 數超過 backend-max-thread-running時,新來連接配接等待的時間(機關ms)
thread-running-sleep-delay=10
#SQL過濾統計緩存的SQL模闆數,預設為0
#lastest-query-num=10000
#設定某類語句記入黑名單時,要滿足的查詢的執行時間,超過此值的查詢會被做為放到黑名單的候選(機關ms)
#query-filter-time-threshold=10000
#設定某類語句記入黑名單時,要滿足的查詢的執行頻率,超過此值的查詢會被做為放到黑名單的候選,當同時滿足時間和頻率都超過指定值時,此類查詢會被放入黑名單
#query-filter-frequent-threshold=10.000000
#SQL過濾頻率統計時間視窗内的最小執行次數,根據頻率和該參數計算時間視窗
#access-num-per-time-window=10
#手動過濾SQL是否生效,預設為OFF
#manual-filter-flag=OFF
#自動過濾SQL是否生效,預設為OFF
#auto-filter-flag=OFF
#Shutdown DBProxy時,空閑事務的等待時間, 機關是s
shutdown-timeout=600
#設定SQL的類型: client: 用戶端的SQL日志、連接配接、關閉資訊; backend: 背景MySQL執行的語句及其狀态;all: client + backend
sql-log-mode=backend
#設定trace的DBProxy子產品,設定後子產品的運作情況會列印到admin日志中
log-trace-modules=0
#設定proxy使用者白名單,隻能從本參數指定的主機進行通路DBProxy,為空時不對使用者限制
user-hosts=
#移除backend時最長等待時間。在删除過程中,如果目前待删除的庫正在事務中,則可以設定等待時間,沒有設定等待時間,則參考該值,機關是s。
remove-backend-timeout=1024
#percentile統計功能的開關 ON:打開 OFF:關閉,預設OFF
#percentile-switch=OFF
#設定百分占比,預設95
#percentile=95
#配置監控backends的使用者資訊
#backend-monitor-pwds=
#日志緩沖大小(日志條數),預設500
#sql-log-buffer-size=
#設定check state線程查詢backend的資訊的時間間隔,預設為4s
check-state-interval=4
#設定check state線程查詢backend的資訊時的連接配接逾時,預設為1s
check-state-conn-timeout=1      

具體的參數說明可以見官網。按照配置檔案進行相關的設定,如日志目錄、非root使用者開啟DBProxy等。相關操作如下:

1:建立啟動使用者
useradd dbproxy

2:建立日志目錄
mkdir /var/log/dbproxy_log/

3:修改相應目錄檔案權限
cd /usr/local/
chown -R dbproxy.dbproxy mysql-proxy/

cd /var/log/
chown -R dbproxy.dbproxy dbproxy_log/

4:啟動
root@dbtest:/usr/local/mysql-proxy# ./bin/mysql-proxyd proxy_test start
2017-04-12 11:35:46.762: (message)mysql-proxy-cli.c:795(main_cmdline)running as user: dbproxy (1001/1001)
OK: MySQL-Proxy of proxy_test is started

      

root@dbtest:/usr/local/mysql-proxy# ps -ef | grep mysql

dbproxy 25254 1 0 12:35 ? 00:00:00 /usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/mysql-proxy/conf/proxy_test.cnf

dbproxy 25255 25254 0 12:35 ? 00:00:00 /usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/mysql-proxy/conf/proxy_test.cnf

到此DBProxy已經正式啟動了,後面就需要對其進行管理,在配置檔案中設定了管理使用者和proxy使用者的賬号、密碼已經主從的相關資訊,當然裡面大部分資訊都可以在管理接口進行set的動态修改設定。

DBProxy管理操作

admin接口(3309),proxy接口(3308)管理

1)admin 使用者,通過admin接口通路

在配置檔案裡配置了管理接口的位址、端口和使用者、密碼。登入:

mysql -uguest -pguest -P3309 -h127.0.0.1      

和登陸mysql一樣的指令,但是在指令行隻能執行特定的指令,通過下面的指令來檢視可以執行的操作。

select * from help;      

通過下面的指令檢視使用者資訊,包括admin和proxy使用者:

[email protected] : (none) 12:53:17>select * from pwds;
+-----------+------------------------------+-------+----------+-------+
| username  | password                     | hosts | backends | type  |
+-----------+------------------------------+-------+----------+-------+
| %         |                              |       |          | proxy |
| dxy_proxy | uK6+XM9x2YRDabHitUtqIK5KOLfO |       |          | proxy |
| guest     | uqmOY9A=                     |       |          | admin |
+-----------+------------------------------+-------+----------+-------+      
字段名稱 含義
username 使用者名
password 密碼(encrypted_pwd)
hosts 使用者對應的白名單ip
backends proxy使用者名下綁定的bakcend(以tag名的形式标記)
type 類型資訊。proxy:proxy端口的使用者 admin:admin 端口的使用者

不能添加、删除admin使用者,隻能修改admin使用者的使用者名、密碼和通路IP。

① 修改使用者名和密碼:alter admin user $user:$pwd

[email protected] : (none) 12:55:32>alter admin user zjy:zjy;
Empty set (0.00 sec)

[email protected] : (none) 01:01:15>^DBye
root@dbtest:~# mysql -uguest -pguest -P3309 -h127.0.0.1
Warning: Using a password on the command line interface can be insecure.
ERROR 1045 (28000): unknown user
root@dbtest:~# mysql -uzjy -pzjy -P3309 -h127.0.0.1
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.0.99-agent-admin

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

[email protected] : (none) 01:03:31>select * from pwds;
+-----------+------------------------------+-------+----------+-------+
| username  | password                     | hosts | backends | type  |
+-----------+------------------------------+-------+----------+-------+
| %         |                              |       |          | proxy |
| dxy_proxy | uK6+XM9x2YRDabHitUtqIK5KOLfO |       |          | proxy |
| zjy       | p7aS                         |       |          | admin |
+-----------+------------------------------+-------+----------+-------+
3 rows in set (0.00 sec)      

② 限制通路IP。設定連接配接admin端口的ip白名單,進而加強對admin賬号的安全管理,限制部分ip對admin端口的登入請求,即隻有在白名單内的ip才能夠允許連接配接admin端口(不設定時,預設不限制),

添加白名單:alter admin user hosts $ip,$ip ,多個用逗号分隔。

mysql> add admin user hosts 192.168.200.64,192.168.200.25;
Empty set (0.03 sec)

mysql> select * from pwds;
+-----------+------------------------------+-------------------------------+----------+-------+
| username  | password                     | hosts                         | backends | type  |
+-----------+------------------------------+-------------------------------+----------+-------+
| %         |                              |                               |          | proxy |
| sbtest    | rr6fdddI                     |                               |          | proxy |
| guest     | uqmOY9A=                     | 192.168.200.25,192.168.200.64 |          | admin |
| dxy_proxy | uK6+XM9x2YRDabHitUtqIK5KOLfO |                               |          | proxy |
+-----------+------------------------------+-------------------------------+----------+-------+
4 rows in set (0.00 sec)

mysql> ^DBye
# mysql -uguest -pguest -P3309 -h127.0.0.1  #限制IP,連不上了
Warning: Using a password on the command line interface can be insecure.
ERROR 1045 (28000): unpermitted host

從200.64上連接配接: #在白名單裡,可以連接配接
$ mysql -uguest -pguest -P3309 -h192.168.200.24
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.0.99-agent-admin
...      

删除白名單:remove admin user hosts $ip,$ip

[email protected] : (none) 12:28:54>remove admin user hosts 192.168.200.64;
Empty set (0.00 sec)

[email protected] : (none) 12:31:13>select * from pwds;
+-----------+------------------------------+----------------+----------+-------+
| username  | password                     | hosts          | backends | type  |
+-----------+------------------------------+----------------+----------+-------+
| %         |                              |                |          | proxy |
| sbtest    | rr6fdddI                     |                |          | proxy |
| guest     | uqmOY9A=                     | 192.168.200.25 |          | admin |
| dxy_proxy | uK6+XM9x2YRDabHitUtqIK5KOLfO |                |          | proxy |
+-----------+------------------------------+----------------+----------+-------+
4 rows in set (0.00 sec)

[email protected] : (none) 12:31:15>^DBye   
$ mysql -uguest -pguest -P3309 -h192.168.200.24    #不在白名單
Warning: Using a password on the command line interface can be insecure.
ERROR 1045 (28000): unpermitted host      

③ 儲存修改到配置檔案。要是通過管理接口進行的一些修改,僅在當時是有效,若DBProxy重新開機之後則會丢失配置,通過 save config來持久到配置檔案。

mysql> save config;
Empty set (0.01 sec)      

2)Proxy 使用者,通過proxy接口通路

能添加、删除proxy使用者和通路IP,不能修改proxy使用者的使用者名、密碼。

這裡結合程式一起說明:比如有2套程式需要通路資料庫sbtest,程式所在IP:192.168.200.64和192.168.200.25;DBproxy所在IP:192.168.200.24,後端資料庫所在IP(配置檔案裡已經設定):192.168.200.202(M),192.168.200.132(S)。

① 添加和删除proxy使用者:add pwd $user:$pwd

#明文密碼
mysql> add pwd sbtest:sbtest;
Empty set (0.00 sec)

#加密密碼
先擷取加密密碼:
:/usr/local/mysql-proxy/bin# ./encrypt sbtest
rr6fdddI
再添加賬号:
mysql> add enpwd sbtest:rr6fdddI;
Empty set (0.00 sec)

mysql> select * from pwds;
+-----------+------------------------------+-------+----------+-------+
| username  | password                     | hosts | backends | type  |
+-----------+------------------------------+-------+----------+-------+
| %         |                              |       |          | proxy |
| sbtest    | rr6fdddI                     |       |          | proxy |
| guest     | uqmOY9A=                     |       |          | admin |
| dxy_proxy | uK6+XM9x2YRDabHitUtqIK5KOLfO |       |          | proxy |
+-----------+------------------------------+-------+----------+-------+      

② 限制通路IP,允許200.64/25通路DBPrxoy。這裡比較特别,在使用者的白名單的上一層還有一個系統白名單,即username是%,大緻的驗證流程如下:

美團點評DBProxy讀寫分離使用說明

大緻的意思是設定了系統白名單則需要首先通過系統白名單驗證,要是也設定了使用者白名單則再通過使用者白名單驗證,若均沒有設定白名單則直接通路不需要驗證(預設)。是以我們這裡系統白名單沒有設定,隻需要設定使用者白名單即可。既然系統白名單有設定,為了安全還是設定一下,大緻流程如下:

系統白名單設定:

添加:add user hosts %@host[|host];

mysql> add user hosts %@192.168.200.%|192.168.201.%;
Empty set (0.00 sec)

mysql> select * from pwds;
+-----------+------------------------------+-----------------------------+----------+-------+
| username  | password                     | hosts                       | backends | type  |
+-----------+------------------------------+-----------------------------+----------+-------+
| %         |                              | 192.168.200.%|192.168.201.% |          | proxy |
| sbtest    | rr6fdddI                     |                             |          | proxy |
| guest     | uqmOY9A=                     |                             |          | admin |
| dxy_proxy | uK6+XM9x2YRDabHitUtqIK5KOLfO |                             |          | proxy |
+-----------+------------------------------+-----------------------------+----------+-------+      

系統白名單設定了允許200和201網段的IP通路,其他IP通路不了。

删除指定的白名單:remove user hosts %@192.168.201.%;

删除所有白名單:remove user host %;

#删除指定的白名單
mysql> remove user hosts %@192.168.201.%;
Empty set (0.00 sec)

mysql> select * from pwds;
+-----------+------------------------------+---------------+----------+-------+
| username  | password                     | hosts         | backends | type  |
+-----------+------------------------------+---------------+----------+-------+
| %         |                              | 192.168.200.% |          | proxy |
| sbtest    | rr6fdddI                     |               |          | proxy |
| guest     | uqmOY9A=                     |               |          | admin |
| dxy_proxy | uK6+XM9x2YRDabHitUtqIK5KOLfO |               |          | proxy |
+-----------+------------------------------+---------------+----------+-------+
4 rows in set (0.00 sec)

#删除所有白名單
mysql> remove user hosts %;
Empty set (0.00 sec)

mysql> select * from pwds;
+-----------+------------------------------+-------+----------+-------+
| username  | password                     | hosts | backends | type  |
+-----------+------------------------------+-------+----------+-------+
| %         |                              |       |          | proxy |
| sbtest    | rr6fdddI                     |       |          | proxy |
| guest     | uqmOY9A=                     |       |          | admin |
| dxy_proxy | uK6+XM9x2YRDabHitUtqIK5KOLfO |       |          | proxy |
+-----------+------------------------------+-------+----------+-------+
4 rows in set (0.00 sec)      

當添加完系統白名單之後,若使用者白名單沒設定,隻要是200和201網段的都可以用賬号通路。好像還是不太安全,後面繼續使用者白名單設定。

mysql> select * from pwds;
+-----------+------------------------------+-----------------------------+----------+-------+
| username  | password                     | hosts                       | backends | type  |
+-----------+------------------------------+-----------------------------+----------+-------+
| %         |                              | 192.168.200.%|192.168.201.% |          | proxy |
| sbtest    | rr6fdddI                     |                             |          | proxy |
| guest     | uqmOY9A=                     | 192.168.200.%               |          | admin |
| dxy_proxy | uK6+XM9x2YRDabHitUtqIK5KOLfO |                             |          | proxy |
+-----------+------------------------------+-----------------------------+----------+-------+

通過非200和201網段通路:
$ mysql -usbtest -psbtest -P3308 -h192.168.200.24
Warning: Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied(host is forbidden) for user 'sbtest'@'192.168.204.187' (using password: YES)      

使用者白名單設定:根據上面的條件設定具體的白名單

添加:add user hosts $user@host[|host];

mysql> add user hosts [email protected]|192.168.200.25;
Empty set (0.00 sec)

mysql> select * from pwds;
+-----------+------------------------------+-------------------------------+----------+-------+
| username  | password                     | hosts                         | backends | type  |
+-----------+------------------------------+-------------------------------+----------+-------+
| %         |                              | 192.168.200.%|192.168.201.%   |          | proxy |
| sbtest    | rr6fdddI                     | 192.168.200.25|192.168.200.64 |          | proxy |
| guest     | uqmOY9A=                     | 192.168.200.%                 |          | admin |
| dxy_proxy | uK6+XM9x2YRDabHitUtqIK5KOLfO |                               |          | proxy |
+-----------+------------------------------+-------------------------------+----------+-------+      

若在非上面指定的白名單(IP)中執行則報錯:

$mysql -usbtest -psbtest -P3308 -h192.168.200.24
Warning: Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied(host is forbidden) for user 'sbtest'@'192.168.200.55' (using password: YES)      

删除使用者白名單:remove user hosts $user@$host|$host

mysql> remove user hosts [email protected]|192.168.200.64;
Empty set (0.00 sec)

mysql> select * from pwds;
+-----------+------------------------------+-----------------------------+----------+-------+
| username  | password                     | hosts                       | backends | type  |
+-----------+------------------------------+-----------------------------+----------+-------+
| %         |                              | 192.168.200.%|192.168.201.% |          | proxy |
| sbtest    | rr6fdddI                     |                             |          | proxy |
| guest     | uqmOY9A=                     | 192.168.200.%               |          | admin |
| dxy_proxy | uK6+XM9x2YRDabHitUtqIK5KOLfO |                             |          | proxy |
+-----------+------------------------------+-----------------------------+----------+-------+
4 rows in set (0.00 sec)      

若系統白名單設定不允許200網段登陸,則直接不會走到驗證使用者白名單這不,直接退出。

mysql> remove user hosts %@192.168.200.%;
Empty set (0.00 sec)

mysql> select * from pwds;
+-----------+------------------------------+-------------------------------+----------+-------+
| username  | password                     | hosts                         | backends | type  |
+-----------+------------------------------+-------------------------------+----------+-------+
| %         |                              | 192.168.201.%                 |          | proxy |
| sbtest    | rr6fdddI                     | 192.168.200.25|192.168.200.64 |          | proxy |
| guest     | uqmOY9A=                     | 192.168.200.%                 |          | admin |
| dxy_proxy | uK6+XM9x2YRDabHitUtqIK5KOLfO |                               |          | proxy |
+-----------+------------------------------+-------------------------------+----------+-------+
4 rows in set (0.00 sec)

#系統白名單隻允許201網段通路。即使使用者白名單允許200網段通路也不行:
$mysql -usbtest -psbtest -P3308 -h192.168.200.24
Warning: Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied(host is forbidden) for user 'sbtest'@'192.168.200.64' (using password: YES)      

③ 權限相關,proxy使用者必須在後端資料庫裡存在并且保持一緻的密碼。

通過上面設定了白名單,加強了資料庫的安全,這裡還有另一個需要注意的:通路的賬号(sbtest)需要在後端資料庫(MS)裡面存在并且密碼和DBproxy設定的一樣,而且擁有相應的權限,否則報錯:

$mysql -usbtest -psbtest -P3308 -h192.168.200.24  #可以通路DBproxy... 
[email protected] : (none) 02:45:29>show databases;   #不能執行指令,因為後端資料庫沒有賬号或則密碼錯誤。
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    431
Current database: *** NONE ***

ERROR 1105 (07000): Internal Error: I have no server backend, closing connection      

把上面的配置持久化到配置檔案(save config)

user-hosts=%@192.168.200.%|192.168.201.%,[email protected]|192.168.200.64
admin-user-hosts=192.168.200.%      

backends管理

DBProxy啟動之前需要在配置檔案中配置backend資訊。backend按照讀寫分類,可分為讀寫backend庫(可以讀寫操作)和隻讀backend庫(僅可以讀操作),其中在配置檔案中讀寫backend庫是必須配置的。連接配接DBProxy的用戶端所發送的sql語句,根據DBProxy内部的政策,會将sql語句發送至特定的backend庫執行。具體的說明可以看文檔。

配置檔案參數:

proxy-backend-addresses:配置主庫IP:Port
proxy-read-only-backend-addresses:配置從庫IP:Port@權重,多個,号分隔。      
select * from backends;
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
| backend_ndx | address              | hostname | state | type | weight | tag  | threads_running |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
|           1 | 192.168.200.202:3306 |          | up    | rw   | 0      | NULL | 0               |
|           2 | 192.168.200.132:3306 |          | up    | ro   | 3      | NULL | 0               |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+      

要是配置檔案裡沒有配置,也可以到admin接口裡進行設定:

添加一個主庫:add master $ip:$port

添加一個從庫:add slave $ip:$port

[email protected] : (none) 04:31:55>select * from backends;
Empty set (0.00 sec)

[email protected] : (none) 04:31:57>add master 192.168.200.202:3306;
Empty set (0.00 sec)

[email protected] : (none) 04:32:00>add slave 192.168.200.132:3306;
Empty set (0.00 sec)

[email protected] : (none) 04:32:13>select * from backends;
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
| backend_ndx | address              | hostname | state | type | weight | tag  | threads_running |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
|           1 | 192.168.200.202:3306 |          | up    | rw   | 0      | NULL | 0               |
|           2 | 192.168.200.132:3306 |          | up    | ro   | 1      | NULL | 0               |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
2 rows in set (0.00 sec)

[email protected] : (none) 04:32:18>      

當已經存在一個主庫,再添加一個主庫會報錯:

[email protected] : (none) 04:32:18>add master 192.168.200.202:3306;
ERROR 1105 (07000): there is already one RW backend      

DBProxy隻允許一主一從或一主多從,不能多主。

删除backends:

remove backend $backend_ndx [timeout $int]

timeout的意義是:在删除過程中,如果目前待删除的庫正在事務中,則可以設定等待時間,沒有設定等待時間,則參考系統全局的remove-backend-timeout的值。若目前backend中有連接配接在事務中,則等待該事務完成,若超過等待時間,該事務仍舊沒有執行完,則強制對backend進行删除。

[email protected] : (none) 04:34:24>select * from backends;
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
| backend_ndx | address              | hostname | state | type | weight | tag  | threads_running |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
|           1 | 192.168.200.202:3306 |          | up    | rw   | 0      | NULL | 0               |
|           2 | 192.168.200.132:3306 |          | up    | ro   | 1      | NULL | 0               |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
2 rows in set (0.00 sec)

[email protected] : (none) 04:36:02>remove backend 2;
Empty set (0.00 sec)

[email protected] : (none) 04:36:42>remove backend 1 timeout 100;
Empty set (0.00 sec)

[email protected] : (none) 04:36:48>select * from backends;
Empty set (0.00 sec)      
backend_ndx 每個backend的索引值,該值是動态變化的,從1開始依次排序,主庫序号靠前
address backend的主機ip和port
hostname 顯示ip位址對應的主機名稱
state 顯示backend的狀态。狀态有:UP/DOWN/REMOVING/OFFLINE/OFFLING
代表backend的類型。類型有:rw:主庫,可進行讀寫操作 ro:從庫,隻可進行讀取操作
weight 代表從庫的權重。主庫權重為0,代表其沒有權重屬性;從庫的權重最小值為1
tag backend的标簽名
threads_running 目前backend上正在運作的并發線程數

這裡說明一下state和weight的意義,tag的說明可以看文檔,這裡不做說明。

state:proxy根據其狀态進行讀寫政策,當狀态是down或則是offline的時候,表示已經不可用,讀寫都不會配置設定過來,會分流到其他的從庫或則主庫。即:當一主一從,從down了,之後的讀寫都會分到主上去。直到state正常之後就會自動分流回來。這個可以通過sql日志(日志目錄下的sql目錄中)看到。如:

美團點評DBProxy讀寫分離使用說明

這裡有個不足是DBProxy不關心主從複制的可靠性和穩定性,若從延遲大,讀的操作還是會到延遲的從上去,不會自動的下線從庫。這裡需要DBA自己介入,通過判斷延遲的門檻值去admin接口執行set offline來手動更新state字段,使延遲大的從先下線。

set offline $backend_ndx [timeout $int];set online $backend_ndx;timeout的意義和上面的一緻。

mysql> select * from backends;
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
| backend_ndx | address              | hostname | state | type | weight | tag  | threads_running |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
|           1 | 192.168.200.202:3306 |          | up    | rw   | 0      | NULL | 0               |
|           2 | 192.168.200.132:3306 |          | up    | ro   | 1      | NULL | 0               |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
2 rows in set (0.00 sec)

mysql> set offline 2;
Empty set (0.00 sec)

通過檢視日志(/var/log/dbproxy_log/sql),看到這時的讀都去了主庫。

mysql> select * from backends;
+-------------+----------------------+----------+---------+------+--------+------+-----------------+
| backend_ndx | address              | hostname | state   | type | weight | tag  | threads_running |
+-------------+----------------------+----------+---------+------+--------+------+-----------------+
|           1 | 192.168.200.202:3306 |          | up      | rw   | 0      | NULL | 0               |
|           2 | 192.168.200.132:3306 |          | offline | ro   | 1      | NULL | 0               |
+-------------+----------------------+----------+---------+------+--------+------+-----------------+
2 rows in set (0.00 sec)

mysql> set online 2;
Empty set (0.00 sec)

mysql> select * from backends;
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
| backend_ndx | address              | hostname | state | type | weight | tag  | threads_running |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
|           1 | 192.168.200.202:3306 |          | up    | rw   | 0      | NULL | 0               |
|           2 | 192.168.200.132:3306 |          | up    | ro   | 1      | NULL | 0               |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
2 rows in set (0.00 sec)

通過檢視日志(/var/log/dbproxy_log/sql),看到這時的讀都去了從庫。      

若把主庫set offline,讀不受影響;寫不能執行。要是有多個從,可以通過weight實作負載均衡:

alter slave weight $backend_index $weight

mysql> select * from backends;
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
| backend_ndx | address              | hostname | state | type | weight | tag  | threads_running |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
|           1 | 192.168.200.202:3306 |          | up    | rw   | 0      | NULL | 0               |
|           2 | 192.168.200.132:3306 |          | up    | ro   | 1      | NULL | 0               |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
2 rows in set (0.00 sec)

mysql> alter slave weight 2 100;
Empty set (0.00 sec)

mysql> select * from backends;
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
| backend_ndx | address              | hostname | state | type | weight | tag  | threads_running |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
|           1 | 192.168.200.202:3306 |          | up    | rw   | 0      | NULL | 0               |
|           2 | 192.168.200.132:3306 |          | up    | ro   | 100    | NULL | 0               |
+-------------+----------------------+----------+-------+------+--------+------+-----------------+
2 rows in set (0.00 sec)      

權重越大,其被讀的幾率就越大,要是某一個從庫性能比較好,權重可以設定的大一點。這裡補充一下,通過上面的sql日志的截圖,為什麼寫一次之後馬上讀取卻還是在主上呢?這個是由于DBProxy的限制造成的:update、insert、delete、replace之後,下一條 sql有可能 去讀 affected row 的行數。有的select 語句帶有特殊函數的,為了随後的sql 查上次語句的某些狀态,這種可能需要上下文資訊的,DBProxy暫時未把背景連接配接放回連接配接池。是以第一個讀會使用上次操作的背景連接配接,以後就走從庫了。

平滑關閉DBProxy

支援DBProxy立即關閉和平滑關閉。立即關閉是指立即結束DBProxy程序;平滑關閉是指若有正在執行的事務,等待shutdown-timeout時間,如果仍有執行的事務,則直接結束DBProxy程序。

shutdown [NORMAL|IMMEDIATE]; #NORMAL:平滑下線 IMMEDIATE:立即下線 

mysql> shutdown normal;
Empty set (0.01 sec)      

介紹到這裡,大緻已經能讓基本的讀寫分離功能用起來了,DBProxy裡還有很多其他功能,包括為SLAVE打TAG、指定從指定從庫上讀取,指定到主上讀等等。這裡暫時沒用到就不介紹了,所有的内容在手冊裡有了詳盡的介紹,有興趣的可以去檢視。再看文檔都時候遇到過一些問題,這裡感謝DBProxy開發同學<紫氣東來>的解惑。

DBProxy性能測試

在上DBProxy中間件的時候必須還要做個測試,因為用DBProxy進行資料庫操作畢竟多了一層通路,不知道性能上有多大的折損。這裡通過sysbench進行相關的測試來大緻了解一下大概能有多大的差别。關于sysbench的安裝和使用可以看sysbench 安裝、使用和測試,也可以參考使用sysbench對mysql壓力測試。

1)安裝,用最新版的sysbench,其他版也沒問題。

1:安裝依賴包
apt-get install make automake libtool pkg-config libaio-dev vim-common libmysqlclient-dev

2:下載下傳
git clone https://github.com/akopytov/sysbench.git

3:安裝
cd sysbench
sh autogen.sh 
./configure --prefix=/usr/local/sysbench-1.1
make
make install      

2)使用,最新版1.1的使用方法和0.4.12,甚至是0.5都有了差别,可以通過help來調整

dxy@redis2:/usr/local/sysbench-1.1$ ./bin/sysbench --version
sysbench 1.1.0-6bb15d7
dxy@redis2:/usr/local/sysbench-1.1$ ./bin/sysbench cpu help
sysbench 1.1.0-6bb15d7 (using bundled LuaJIT 2.1.0-beta2)

cpu options:
  --cpu-max-prime=N upper limit for primes generator [10000]

dxy@redis2:/usr/local/sysbench-1.1$ ./bin/sysbench ./share/sysbench/oltp_read_write.lua help
sysbench 1.1.0-6bb15d7 (using bundled LuaJIT 2.1.0-beta2)

oltp_read_write.lua options:
  --distinct_ranges=N           Number of SELECT DISTINCT queries per transaction [1]
  --sum_ranges=N                Number of SELECT SUM() queries per transaction [1]
  --skip_trx[=on|off]           Don't start explicit transactions and execute all queries in the AUTOCOMMIT mode [off]
  --secondary[=on|off]          Use a secondary index in place of the PRIMARY KEY [off]
  --create_secondary[=on|off]   Create a secondary index in addition to the PRIMARY KEY [on]
  --index_updates=N             Number of UPDATE index queries per transaction [1]
  --range_size=N                Range size for range SELECT queries [100]
  --auto_inc[=on|off]           Use AUTO_INCREMENT column as Primary Key (for MySQL), or its alternatives in other DBMS. When disabled, use client-generated IDs [on]
  --delete_inserts=N            Number of DELETE/INSERT combination per transaction [1]
  --tables=N                    Number of tables [1]
  --mysql_storage_engine=STRING Storage engine, if MySQL is used [innodb]
  --non_index_updates=N         Number of UPDATE non-index queries per transaction [1]
  --table_size=N                Number of rows per table [10000]
  --pgsql_variant=STRING        Use this PostgreSQL variant when running with the PostgreSQL driver. The only currently supported variant is 'redshift'. When enabled, create_secondary is automatically disabled, and delete_inserts is set to 0
  --simple_ranges=N             Number of simple range SELECT queries per transaction [1]
  --order_ranges=N              Number of SELECT ORDER BY queries per transaction [1]
  --range_selects[=on|off]      Enable/disable all range SELECT queries [on]
  --point_selects=N             Number of point SELECT queries per transaction [10]      

3)測試,這裡測試選擇通過select、insert、update和混合模式進行測試說明,自帶的lua腳本有:

$ ls -lh /usr/local/sysbench-1.1/share/sysbench/
total 64K
-rwxr-xr-x 1 root root 1.5K  4月 12 17:35 bulk_insert.lua
-rw-r--r-- 1 root root  14K  4月 12 17:35 oltp_common.lua
-rwxr-xr-x 1 root root 1.1K  4月 12 17:35 oltp_delete.lua #删
-rwxr-xr-x 1 root root 2.0K  4月 12 17:35 oltp_insert.lua #寫
-rwxr-xr-x 1 root root 1.3K  4月 12 17:35 oltp_point_select.lua
-rwxr-xr-x 1 root root 1.7K  4月 12 17:35 oltp_read_only.lua #隻讀
-rwxr-xr-x 1 root root 1.8K  4月 12 17:35 oltp_read_write.lua #讀寫
-rwxr-xr-x 1 root root 1.1K  4月 12 17:35 oltp_update_index.lua  #更新索引字段
-rwxr-xr-x 1 root root 1.2K  4月 12 17:35 oltp_update_non_index.lua #更新非索引字段
-rwxr-xr-x 1 root root 1.5K  4月 12 17:35 oltp_write_only.lua #隻寫
-rwxr-xr-x 1 root root 1.9K  4月 12 17:35 select_random_points.lua
-rwxr-xr-x 1 root root 2.1K  4月 12 17:35 select_random_ranges.lua
drwxr-xr-x 4 root root 4.0K  4月 12 17:35 tests      

進入執行檔案目錄 cd /usr/local/sysbench-1.1

①:讀寫混合(oltp_read_write.lua)

直連資料庫:

./bin/sysbench --test=./share/sysbench/oltp_read_write.lua --mysql-host=192.168.200.202 --mysql-port=3306 --mysql-user=sbtest --mysql-password=sbtest --mysql-db=sbtest  --report-interval=10  --max-requests=0 --time=300 --threads=4 --tables=3  --table-size=500000 prepare/run/cleanup        

代理連資料庫

./bin/sysbench --test=./share/sysbench/oltp_read_write.lua --mysql-host=192.168.200.24 --mysql-port=3308 --mysql-user=sbtest --mysql-password=sbtest --mysql-db=sbtest  --report-interval=10  --max-requests=0 --time=300 --threads=4 --tables=3  --table-size=500000 --skip-trx=on --db-ps-mode=disable --mysql-ignore-errors=1062 prepare/run/cleanup       

這裡需要注意:因為DBProxy的限制,如不支援prepare,需要添加--skip-trx=on --db-ps-mode=disable--skip-trx=on --db-ps-mode=disable;由于不加事務出現的重複key的幾率比較大,是以需要跳過錯誤:--mysql-ignore-errors=1062。 

測試的線程:1、4、8、16、32、64、128

美團點評DBProxy讀寫分離使用說明

把上面資料以折線圖的形式表現:

TPS:

美團點評DBProxy讀寫分離使用說明

QPS: 

美團點評DBProxy讀寫分離使用說明

②:隻讀(oltp_read_only.lua)

./bin/sysbench --test=./share/sysbench/oltp_read_only.lua --mysql-host=192.168.200.202 --mysql-port=3306 --mysql-user=sbtest --mysql-password=sbtest --mysql-db=sbtest  --report-interval=10  --max-requests=0 --time=300 --threads=1 --tables=3  --table-size=500000 run      
./bin/sysbench --test=./share/sysbench/oltp_read_only.lua --mysql-host=192.168.200.24 --mysql-port=3308 --mysql-user=sbtest --mysql-password=sbtest --mysql-db=sbtest  --report-interval=10  --max-requests=0 --time=300 --threads=1 --tables=3  --table-size=500000 --skip-trx=on --db-ps-mode=disable --mysql-ignore-errors=1062 run      
美團點評DBProxy讀寫分離使用說明
美團點評DBProxy讀寫分離使用說明

QPS:

美團點評DBProxy讀寫分離使用說明

③:隻寫入(oltp_insert.lua)

./bin/sysbench --test=./share/sysbench/oltp_insert.lua --mysql-host=192.168.200.202 --mysql-port=3306 --mysql-user=sbtest --mysql-password=sbtest --mysql-db=sbtest  --report-interval=10  --max-requests=0 --time=300 --threads=1 --tables=3  --table-size=500000 run      
./bin/sysbench --test=./share/sysbench/oltp_insert.lua --mysql-host=192.168.200.24 --mysql-port=3308 --mysql-user=sbtest --mysql-password=sbtest --mysql-db=sbtest  --report-interval=10  --max-requests=0 --time=300 --threads=1 --tables=3  --table-size=500000 --skip-trx=on --db-ps-mode=disable --mysql-ignore-errors=1062 run      
美團點評DBProxy讀寫分離使用說明
美團點評DBProxy讀寫分離使用說明

④:隻更新(oltp_update_index.lua)

./bin/sysbench --test=./share/sysbench/oltp_update_index.lua --mysql-host=192.168.200.202 --mysql-port=3306 --mysql-user=sbtest --mysql-password=sbtest --mysql-db=sbtest  --report-interval=10  --max-requests=0 --time=300 --threads=1 --tables=3  --table-size=500000 run      
./bin/sysbench --test=./share/sysbench/oltp_update_index.lua --mysql-host=192.168.200.24 --mysql-port=3308 --mysql-user=sbtest --mysql-password=sbtest --mysql-db=sbtest  --report-interval=10  --max-requests=0 --time=300 --threads=1 --tables=3  --table-size=500000 --skip-trx=on --db-ps-mode=disable --mysql-ignore-errors=1062 run      
美團點評DBProxy讀寫分離使用說明
美團點評DBProxy讀寫分離使用說明

測試小結:

在讀寫混合的模式下:代理的TPS是直連的TPS的65%~80%,線程越少差距越大;代理的QPS是直連的QPS的60%~75%,線程越少差距越大。

在純讀模式下:和讀寫混合模式表現相近。

在寫和更新模式下:因為代理也隻通路主,它們的差距就是網絡開銷上,代理需要二次通路,不需要輪訓。代理的QPS是直連QPS的65%~90%。

當sysbench的并發測試線程較少時,代理和直連DB的QPS差距較大。這主要是因為當sysbench并發線程少時,DBProxy的性能沒有得到充分的發揮,sysbench隻有很少的線程向DBProxy發送請求,此時網絡延遲對QPS和TPS的影響是最主要的。 當sysbench的并發測試線程較大時,此時DBProxy的性能就得到了充分的發揮, 此時QPS和TPS的對比是代理與直連DB性能對比的真實的反應,網絡延遲對QPS的影響作用就顯得很小了。

由此看來利用DBProxy轉發SQL請求帶來的性能下降雖有下降,通過Open-Falcon對資料庫名額的監控,這個性能下降是完全可以接受的。另外DBProxy屬于CPU密集型任務,相對于磁盤IO和記憶體占用率而言,其對CPU消耗顯得最為明顯,是以建議在部署的時候需要優先考慮伺服器的CPU性能。

總結

通過上面的一些基本介紹,大緻了解了DBProxy讀寫分離功能的使用,和直連DB資料庫對比的性能情況。關于DBproxy的其他功能内容在手冊裡有了詳盡的介紹,需要的話可以去檢視。

這裡還有2個問題:一個問題是在讀寫分離上面,要是從庫延遲超過門檻值,導緻讀寫分離不可用,則需要自己編寫腳本去連接配接admin接口控制問題從庫的下線。另一個問題是即使資料庫有MHA保證,但是DBProxy是一個單點,是以需要保證DBProxy的高可用,這2個問題後面會繼續研究,以及會再看另一個中間件proxysql來和DBProxy進行對比選型。

補充:

補上檢測MySQL從庫延遲進行下線和不延遲進行上線操作的判斷,賬号密碼通過讀配置檔案,通過讀取admin接口進行操作,配置檔案(proxy_db.txt)的格式是:

DBProxy執行個體名,DBProxy IP,DBProxy Admin User,DBProxy Admin Password,從執行個體的使用者,從執行個體的使用者,從執行個體的密碼
如:
masterdata_proxy,192.168.200.24,3309,guest,guest,test,test      

DBProxy Admin接口進行下線和上線的python腳本(check_set_repl.py):具體的參數可以自行按照需要修改。 

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

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.Utils import COMMASPACE, formatdate

import MySQLdb
import fileinput
import smtplib
import mimetypes
import email.MIMEMultipart
import email.MIMEText
import email.MIMEBase

def send_mail(to, subject, text, from_mail, server="localhost"):
    message = MIMEMultipart()
    message['From'] = from_mail
    message['To'] = COMMASPACE.join(to)
    message['Date'] = formatdate(localtime=True)
    message['Subject'] = subject
    message.attach(MIMEText(text,_charset='utf-8'))
    smtp = smtplib.SMTP(server)
    smtp.sendmail(from_mail, to, message.as_string())
    smtp.close()

class DBProxyInfo():

    def __init__(self,host,port,user,password,slave_user,slave_password):
        self.host     = host
        self.port     = port
        self.user     = user
        self.password = password
        self.slave_user     = slave_user
        self.slave_password = slave_password

    def backends_info(self):
        try:
            m = MySQLdb.connect(host=self.host,user=self.user,passwd=self.password,port=self.port)
            query = "SELECT * FROM backends"
            cursor = m.cursor()
            cursor.execute(query)
            Str_string = cursor.fetchall()
            cursor.close()
            m.close()
            return Str_string

        except Exception, e:
            print e
            sys.exit()
    def repl_info(self,slave_host,slave_port):
        try:
            m = MySQLdb.connect(host=slave_host,user=self.slave_user,passwd=self.slave_password,port=slave_port)
            query = "SHOW SLAVE STATUS"
            cursor = m.cursor()
            cursor.execute(query)
            Str_string = cursor.fetchone()
            cursor.close()
            m.close()
            return Str_string

        except Exception, e:
            print e
            sys.exit()

    def set_offline(self,backend_ndx):
        try:
            m = MySQLdb.connect(host=self.host,user=self.user,passwd=self.password,port=self.port)
            query = "SET offline %s" %backend_ndx
            cursor = m.cursor()
            cursor.execute(query)
            Str_string = cursor.fetchone()
            cursor.close()
            m.close()
            return Str_string

        except Exception, e:
            print e
            sys.exit()

    def set_online(self,backend_ndx):
        try:
            m = MySQLdb.connect(host=self.host,user=self.user,passwd=self.password,port=self.port)
            query = "SET online %s" %backend_ndx
            cursor = m.cursor()
            cursor.execute(query)
            Str_string = cursor.fetchone()
            cursor.close()
            m.close()
            return Str_string

        except Exception, e:
            print e
            sys.exit()


if __name__ == '__main__':

    db_list= []
    for line in fileinput.input():
        db_list.append(line.strip())
    for db_info in db_list:
        instance_name,host,port,user,password,salve_user,slave_password = db_info.split(',')
        
        conn = DBProxyInfo(host,int(port),user,password,salve_user,slave_password)
        backends_info = conn.backends_info()
        for backend_ndx,address,hostname,state,type,weight,tag,threads_running in backends_info:
            if type == 'ro':
                salve_host,slave_port = address.split(':')
                repl_info = conn.repl_info(salve_host,int(slave_port))
                Slave_IO_Running  = repl_info[10]
                Slave_SQL_Running = repl_info[11]
                Seconds_Behind_Master = repl_info[32]
                if Slave_IO_Running != 'Yes' or Slave_SQL_Running != 'Yes' or Seconds_Behind_Master >= 60:
                    if state == 'up':
                        conn.set_offline(self,backend_ndx)
                        subject = "%s's slave is offline " %instance_name
                        message = " %s's slave Warning:\n Slave_IO_Running:%s \n Slave_SQL_Running:%s \n Seconds_Behind_Master:%s" %(address,Slave_IO_Running,Slave_SQL_Running,Seconds_Behind_Master)
                        mail_list = ['[email protected]']
                        send_mail(mail_list, subject.encode("utf8"), message, "[email protected]", server="192.168.200.xxx")
                    else:
                        pass
                elif Slave_IO_Running == 'Yes' and Slave_SQL_Running == 'Yes' and Seconds_Behind_Master < 60 and state != 'up':
                    conn.set_online(backend_ndx)
                    subject = "%s's slave is online " %instance_name
                    message = " %s's slave OK " %(address)
                    mail_list = ['[email protected]']
                    send_mail(mail_list, subject.encode("utf8"), message, "[email protected]", server="192.168.200.xxx")
                else:
                    pass      

 運作方式:可以放到系統的crontab裡定時檢測。

python check_set_repl.py proxy_db.txt      

參考文檔

DBProxy手冊

Atlas手冊

~~~~~~~~~~~~~~~

萬物之中,希望至美

~~~~~~~~~~~~~~~

./bin/sysbench --test=./share/sysbench/oltp_read_write.lua --mysql-host=192.168.200.202 --mysql-port=3306 --mysql-user=sbtest --mysql-password=sbtest --mysql-db=sbtest  --report-interval=10  --max-requests=0 --time=300 --threads=4 --tables=3  --table-size=500000 prepare/run/cleanup        
./bin/sysbench --test=./share/sysbench/oltp_read_write.lua --mysql-host=192.168.200.24 --mysql-port=3308 --mysql-user=sbtest --mysql-password=sbtest --mysql-db=sbtest  --report-interval=10  --max-requests=0 --time=300 --threads=4 --tables=3  --table-size=500000 --skip-trx=on --db-ps-mode=disable --mysql-ignore-errors=1062 prepare/run/cleanup       
美團點評DBProxy讀寫分離使用說明
美團點評DBProxy讀寫分離使用說明