美团点评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 startedroot@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 dbproxy2:创建日志目录
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用户:

guest@127.0.0.1 : (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
backendsproxy用户名下绑定的bakcend(以tag名的形式标记)
type类型信息。proxy:proxy端口的用户 admin:admin 端口的用户

 

 

 

 

 

 

不能添加、删除admin用户,只能修改admin用户的用户名、密码和访问IP。

① 修改用户名和密码:alter admin user $user:$pwd

guest@127.0.0.1 : (none) 12:55:32>alter admin user zjy:zjy;
Empty set (0.00 sec)guest@127.0.0.1 : (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-adminCopyright (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.zjy@127.0.0.1 : (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

guest@192.168.200.24 : (none) 12:28:54>remove admin user hosts 192.168.200.64;
Empty set (0.00 sec)guest@192.168.200.24 : (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)guest@192.168.200.24 : (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是%,大致的验证流程如下:

 

大致的意思是设置了系统白名单则需要首先通过系统白名单验证,要是也设置了用户白名单则再通过用户白名单验证,若均没有设置白名单则直接访问不需要验证(默认)。所以我们这里系统白名单没有设置,只需要设置用户白名单即可。既然系统白名单有设置,为了安全还是设置一下,大致流程如下:

系统白名单设置:

添加: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 sbtest@192.168.200.64|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 sbtest@192.168.200.25|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... 
sbtest@192.168.200.24 : (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.%,sbtest@192.168.200.25|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

guest@127.0.0.1 : (none) 04:31:55>select * from backends;
Empty set (0.00 sec)guest@127.0.0.1 : (none) 04:31:57>add master 192.168.200.202:3306;
Empty set (0.00 sec)guest@127.0.0.1 : (none) 04:32:00>add slave 192.168.200.132:3306;
Empty set (0.00 sec)guest@127.0.0.1 : (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)guest@127.0.0.1 : (none) 04:32:18>

当已经存在一个主库,再添加一个主库会报错:

guest@127.0.0.1 : (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进行删除。

guest@127.0.0.1 : (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)guest@127.0.0.1 : (none) 04:36:02>remove backend 2;
Empty set (0.00 sec)guest@127.0.0.1 : (none) 04:36:42>remove backend 1 timeout 100;
Empty set (0.00 sec)guest@127.0.0.1 : (none) 04:36:48>select * from backends;
Empty set (0.00 sec)
字段名称含义
backend_ndx每个backend的索引值,该值是动态变化的,从1开始依次排序,主库序号靠前
addressbackend的主机ip和port
hostname显示ip地址对应的主机名称
state显示backend的状态。状态有:UP/DOWN/REMOVING/OFFLINE/OFFLING
type代表backend的类型。类型有:rw:主库,可进行读写操作 ro:从库,只可进行读取操作
weight代表从库的权重。主库权重为0,代表其没有权重属性;从库的权重最小值为1
tagbackend的标签名
threads_running当前backend上正在运行的并发线程数

 

 

 

 

 

 

 

 

 

这里说明一下state和weight的意义,tag的说明可以看文档,这里不做说明。

state:proxy根据其状态进行读写策略,当状态是down或则是offline的时候,表示已经不可用,读写都不会分配过来,会分流到其他的从库或则主库。即:当一主一从,从down了,之后的读写都会分到主上去。直到state正常之后就会自动分流回来。这个可以通过sql日志(日志目录下的sql目录中)看到。如:

这里有个不足是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-dev2:下载
git clone https://github.com/akopytov/sysbench.git3:安装
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

把上面数据以折线图的形式表现:

TPS:

QPS: 

 

②:只读(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

测试的线程:1、4、8、16、32、64、128

把上面数据以折线图的形式表现:

TPS:

QPS:

③:只写入(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

测试的线程:1、4、8、16、32、64、128

把上面数据以折线图的形式表现:

QPS:

④:只更新(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

测试的线程:1、4、8、16、32、64、128

把上面数据以折线图的形式表现:

QPS:

测试小结:

在读写混合的模式下:代理的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, formatdateimport MySQLdb
import fileinput
import smtplib
import mimetypes
import email.MIMEMultipart
import email.MIMEText
import email.MIMEBasedef send_mail(to, subject, text, from_mail, server="localhost"):message = MIMEMultipart()message['From'] = from_mailmessage['To'] = COMMASPACE.join(to)message['Date'] = formatdate(localtime=True)message['Subject'] = subjectmessage.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     = hostself.port     = portself.user     = userself.password = passwordself.slave_user     = slave_userself.slave_password = slave_passworddef 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_stringexcept Exception, e:print esys.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_stringexcept Exception, e:print esys.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_ndxcursor = m.cursor()cursor.execute(query)Str_string = cursor.fetchone()cursor.close()m.close()return Str_stringexcept Exception, e:print esys.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_ndxcursor = m.cursor()cursor.execute(query)Str_string = cursor.fetchone()cursor.close()m.close()return Str_stringexcept Exception, e:print esys.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_namemessage = " %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 = ['zjy@xxx.com']send_mail(mail_list, subject.encode("utf8"), message, "check_set_rep@ls.xxx.net", server="192.168.200.xxx")else:passelif 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_namemessage = " %s's slave OK " %(address)mail_list = ['zjy@dxyer.com']send_mail(mail_list, subject.encode("utf8"), message, "check_set_rep@ls.xxx.net", server="192.168.200.xxx")else:pass

 运行方式:可以放到系统的crontab里定时检测。

python check_set_repl.py proxy_db.txt

 

参考文档

DBProxy手册

Atlas手册

 

转载于:https://www.cnblogs.com/zhoujinyi/p/6697141.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/372406.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

apriori算法c++_关联分析——基于Apriori算法实现

电子商务推荐系统主要是通过统计和挖掘技术&#xff0c;根据用户在网站上的行为,主动为用户提供推荐服务&#xff0c;从而提高网站体验。而根据不同的业务场景&#xff0c;推荐系统需要满足不同的推荐粒度&#xff0c;包括搜索推荐,商品类目推荐,商品标签推荐&#xff0c;店铺推…

在Oracle Coherence中分发Spring Bean

本文展示了如何通过使用Oracle Coherence中的EntryProcessor和可移植对象格式&#xff08;POF&#xff09;功能来分发Spring Bean。 Coherence通过EntryProcessor API支持无锁编程模型。 此功能通过减少网络访问并在条目上执行隐式的低级锁定来提高系统性能。 此隐式低级锁定功…

Apache Commons SCXML:有限状态机实现

本文提到有限状态机&#xff08;FSM&#xff09;&#xff0c;SCXML&#xff08;状态图可扩展标记语言&#xff09;和Apache Common的SCXML库。 本文还提供了基本的ATM有限状态机示例代码。 有限状态机&#xff1a; 您可能还记得计算机科学课程中的有限状态机。 FSM用于设计计算…

pymol怎么做底物口袋表面_怎么从文献中发掘一篇新文章?

本文来自微信公众号&#xff1a;X-MOLNews可能你的导师也曾说过这样的话——盯着Nature、Science级别的文章做&#xff0c;可能最终会中十分的文章&#xff1b;如果盯着十分的文章做&#xff0c;可能最终发出来也就五六分&#xff1b;但如果就为了发个文章混毕业&#xff0c;很…

如何分析线程转储– IBM VM

本文是我们的线程转储分析系列的第4部分&#xff0c;它将为您概述什么是IBM VM的JVM线程转储以及您将找到的不同线程和数据点。 您将看到和学习​​到&#xff0c;IBM VM Thread Dump格式是不同的&#xff0c;但是提供了更多现成的故障排除数据。 在这一点上&#xff0c;您应该…

VMware vSphere克隆虚拟机

参考资料&#xff1a;http://blog.csdn.net/shen_jz2012/article/details/484167711. 首先将你所要克隆的虚拟机关掉2. 选择你的ESXI服务器选中"配置"&#xff0c;然后选中存储器右键你的存储介质&#xff0c;比如我的是datastore1&#xff0c;选择“浏览数据存储”。…

windows命令行无法启动redis_windows系统安装redis

1、下载最新redis https://github.com/MicrosoftArchive/redis/releases我选择下载msi版本的2.双击下载包安装3.设置redis环境变量&#xff0c;把redis路径配置到系统变量path值中4启动redis&#xff0c;cmd进入安装好redis文件夹 输入&#xff1a;如果redis启动出错Creating S…

OpenShift Express Web管理控制台:入门

本周&#xff0c; 最新版本的OpenShift为已经很棒的PaaS Cloud提供商带来了两个非常好的功能。 首先&#xff0c;JBoss AS已从7.0升级到7.1&#xff0c;并且所有新的Express Web Management Console已作为预览发布。 在本文中&#xff0c;我们将研究如何使用此新控制台&#xf…

女士细线毛衣起多少针_从起针到缝合,教你织毛衣的各种要点(详细教程)

新手学织毛衣看过来&#xff0c;7大编织要点帮你解决织好一件毛衣的基础问题&#xff0c;满满的干货&#xff0c;每点都值得学习!一、起针二、棒针符号三、如何织小样四、依据小样推算针数收挂肩的推算五、斜肩针数的推算开前、后领的位置与针数六、袖山的推算七、如何上袖子一…

Jelastic Java云端平台

谁在Jelastic背后&#xff1f; 那是我的第一个问题&#xff0c;因此我浏览了Jelastic网站。 回答此问题的最佳方法是查看“ Jelastic团队”部分。 创始人&#xff0c;顾问&#xff0c;特殊合作伙伴构成了一支真正的专业团队。 作为特殊的合作伙伴&#xff0c;您会发现MySQL&am…

请先设置tkk_搅拌站水泥罐仓顶除尘器设置及调整

搅拌站水泥罐仓顶除尘器采用脉冲喷吹清灰系统&#xff0c;除尘器本体结构&#xff0c;采用标准模板焊接&#xff0c;整体结构&#xff0c;强度牢靠&#xff0c;组装维修方便&#xff0c;脉冲清灰采用时序控制器MCY系列 控制阀门KEK系列&#xff0c;喷吹清灰频率及喷吹间隔可手…

并发–执行程序和Spring集成

基于线程池/执行器的实现 比原始线程版本更好的方法是基于线程池的线程池&#xff0c;其中基于运行任务的系统定义了适当的线程池大小– CPU数量/&#xff08;任务的1-Blocking Coefficient&#xff09;。 Venkat Subramaniams书中有更多详细信息&#xff1a; 首先&#xff0c…

后面的参数_英特尔I系列CPU大家都知道,后面的参数你有没有了解过

嗨&#xff01;大家好&#xff0c;我是伟仔&#xff0c;今天主要是和大家聊下CPU。大多数人买笔记本或台式电脑对CPU的要求就知道I5或者I7之类的。像是I7一定比I5要好&#xff0c;I3很LOU这样的&#xff0c;当然这样子的观点是不正确的&#xff0c;今天我会告诉大家&#xff0c…

移动端

http://www.w3cplus.com/mobile/lib-flexible-for-html5-layout.html 移动端手淘使用方案 移动端px自动转换rem插件 CSSREM Flexible 转载于:https://www.cnblogs.com/yuruiweb/p/6723580.html

OutOfMemoryError:Java堆空间–分析和解决方法

java.lang.OutOfMemoryError&#xff1a;Java堆问题是在支持或开发复杂的Java EE应用程序时可能会遇到的最复杂的问题之一。 这篇简短的文章将为您提供此JVM HotSpot OutOfMemoryError错误消息的描述&#xff0c;以及在解决该问题之前应如何解决此问题。 有关如何确定要处理的O…

Google AppEngine:任务队列API

任务队列 com.google.appengine.api.taskqueue 使用任务队列&#xff0c;用户可以发起一个请求&#xff0c;以使应用程序执行此请求之外的工作。 它们是进行后台工作的强大工具。 此外&#xff0c;您可以将工作组织成小的离散单元&#xff08;任务&#xff09;。 然后&#xf…

NetBeans 7.2 beta:更快,更有用

NetBeans 7.2的beta版本引起了极大的兴奋。 在本文中&#xff0c;我将简要介绍一下此版本令人兴奋的原因&#xff08;包括更好的性能&#xff0c;提供更多的提示以及集成FindBugs&#xff09;。 NetBeans 7.2 beta在典型的下载捆绑软件中可用&#xff0c;从较小的Java SE&#…

WPF DevExpress 设置雷达图Radar样式

DevExpress中定义的ChartControl很不错&#xff0c;很多项目直接使用这种控件。 本节讲述雷达图的样式设置 <Grid><Grid.Resources><DataTemplate x:Key"LabelItemDataTemplate" DataType"dxc:SeriesLabelItem"><Border CornerRadius…

mxnet系列教程之1-第一个例子

第一个例子当然是mnist的例子 假设已经成功安装了mxnet 例子的代码如下&#xff1a; cd mxnet/example/image-classification python train_mnist.py这样就会运行下去 train_mnist.py的代码为 """ Train mnist, see more explanation at http://mxnet.io/tutori…

mysql数据存在就更新_Mysql:如果数据存在则更新,不存在则插入

mysql语法支持如果数据存在则更新&#xff0c;不存在则插入&#xff0c;首先判断数据存在还是不存在的那个字段要设置成unique索引&#xff0c;例如表tb_addrbook如下&#xff1a;索引&#xff1a;语句1:不存在插入INSERT INTO tb_addrbook(num,name,mobile) VALUE(1001,小李,1…