基于GTID的MySQL主从复制 和 mysql-proxy 读写分离
kevin.Zhu 发布于:2013-1-16 12:37 分类:Mysql 有 14 人浏览,获得评论 0 条
http://www.newasp.net/tech/67663.html
MySQL 5.6引入的GTID(Global Transaction IDs)使得其复制功能的配置、监控及管理变得更加易于实现,且更加健壮。
gtid是一个 unique 唯一的表示符,他是由服务器的uuid 全局唯一标示,是由128位的随机符组成,mysql-5.6是依靠server-id和uuid 来标示复制架构中的每一个主机,因为是128位的随机字符串在全局都不会重复,server-id 和uuid以及每一个mysql事物的事物序号组成了唯一的gtid ,自从引进mysql-5.6之后每一个二进制日志当中在每一个事物的首部都会写上gtid 标记,因此gtid使得追踪和比较复制事物变得非常简单而且能够实现从崩溃中快速恢复。尤其是innodb 引擎要想实现高可用功能必须要借助于gtid来实现。
要在MySQL 5.6中使用复制功能,其服务配置段[mysqld]中于少应该定义如下选项:
binlog-format:二进制日志的格式,有row、statement和mixed几种类型;
需要注意的是:当设置隔离级别为READ-COMMITED必须设置二进制日志格式为ROW,现在MySQL官方认为STATEMENT这个已经不再适合继续使用;但mixed类型在默认的事务隔离级别下,可能会导致主从数据不一致;
log-slave-updates、gtid-mode、enforce-gtid-consistency、report-port和report-host:用于启动GTID及满足附属的其它需求;
master-info-repository和relay-log-info-repository:启用此两项,可用于实现在崩溃时保证二进制及从服务器安全的功能;
sync-master-info:启用之可确保无信息丢失;
slave-paralles-workers:设定从服务器的SQL线程数;0表示关闭多线程复制功能;
binlog-checksum、master-verify-checksum和slave-sql-verify-checksum:启用复制有关的所有校验功能;
binlog-rows-query-log-events:启用之可用于在二进制日志记录事件相关的信息,可降低故障排除的复杂度;
log-bin:启用二进制日志,这是保证复制功能的基本前提;
server-id:同一个复制拓扑中的所有服务器的id号必须惟一.
主从复制的IP地址分配和主从关系:
配置主从复制注意事项:
1,两台服务器时间需要同步
2,相互都能通信ping的通
3,关闭SElinux
mysql版本:mysql-proxy-0.8.3-linux-glibc2.3-x86-32bit.tar.gz
系统版本:redhat 6.4 32位
配置步骤:
mysql 安装配置
1
2
3
4
5
6
7
8
9
10
11
|
# mkdir /mydata/data -pv
# useradd -r mysql
# chown -R mysql.mysql /mydata/data/
# tar xvf mysql-5.6.10-linux-glibc2.5-i686.tar.gz -C /usr/local
# cd /usr/local/
# ln -sv mysql-5.6.10-linux-glibc2.5-i686 mysql
# cd mysql
# chown -R root.mysql ./*
# scripts/mysql_install_db --user=mysql --datadir=/mydata/data
# cp support-files/mysql.server /etc/init.d/mysqld
# chkconfig --add mysqld
|
下面是配置文件部分 ,值得注意的是在下面配置文件中server-id 此项的值 不能重复。主从不能一样。
1
2
3
4
5
6
7
8
9
10
11
12
|
# vim /etc/local/mysql/my.cnf
添加以下几项
datadir = /mydata/data
innodb_file_per_table = ON
server- id = 1 从服务器不能跟此 id 重复
socket= /tmp/mysql .sock
log-bin = master-bin
# service mysqld start
# vim /etc/profile.d/mysqld
添加
export PATH=$PATH: /usr/local/mysql/bin
# . /etc/profile.d/mysqld 重读配置文件
|
下一步开始配置从mysql。配置从服务器,步骤如上,尤其注意的事 /etc/local/mysql/my.cnf 中server-id 值 不能重复!!!
配置主从mysql
编辑配置文件 添加主从复制中 主 的一些配置参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
master
# vim /usr/local/mysql/my.cnf
贴入以下信息
binlog-format=ROW
log-slave-updates= true
gtid-mode=on
enforce-gtid-consistency= true
master-info-repository=TABLE
relay-log-info-repository=TABLE
sync-master-info= 1
slave-parallel-workers= 2
binlog-checksum=CRC32
master-verify-checksum= 1
slave-sql-verify-checksum= 1
binlog-rows-query-log_events= 1
report-port= 3306
port= 3306
report-host= 172.16 . 66.1
|
启动mysql服务:
1
|
# service mysqld restart
|
进入mysql 数据库 查看gtid 等相关信息
1
2
|
# mysql
# mysql> show global var iables like '%gtid%' ;
|
创建复制用户并赋予权限
1
2
3
|
mysql> GRANT REPLICATION SLAVE ON *.* TO 'backup' @ '172.16.%.%' IDENTIFIED BY 'bak123' ;
mysql> flush privileges;
mysql> SELECT @@autocommit
|
下面是编mysql 从的 服务配置信息!!!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
slave
编辑从mysql 配置文件
# vim /usr/local/mysql/my.cnf
添加以下内容
binlog-format=ROW
log-slave-updates= true
gtid-mode=on
enforce-gtid-consistency= true
master-info-repository=TABLE
relay-log-info-repository=TABLE
sync-master-info= 1
slave-parallel-workers= 2
binlog-checksum=CRC32
master-verify-checksum= 1
slave-sql-verify-checksum= 1
binlog-rows-query-log_events= 1
report-port= 3306
port= 3306
report-host= 172.16 . 66.2
|
启动mysql服务
1
|
# service mysql restart
|
使用主mysql上创建的账号密码登陆复制。
1
2
3
|
# msyql>change master to master_host= '172.16.66.1' , master_user= 'backup' ,master_password= 'bak123' ,master_auto_position= 1 ;
# mysql>start slave;
# mysql>SHOW SLAVE STATUS\G 查看复制状态信息
|
接下来进入调试和验证步骤。
在主mysql 上创建数据库 监测 从是否能复制
登陆进主mysql数据库里 并 创建数据库从是否能同步成功。
1
|
# mysql> CREATE DATABASE LAOGEN;
|
登陆从mysql 验证数据库
1
|
# mysql> SHOW DATABASES;
|
检查二进制文件同步位置是否一致,两者对比一下!!!!
在主mysql数据库里面执行
1
|
mysql>show master status\G
|
在从mysql数据库里面执行,同样也是这条命令。
1
|
mysql>show master status\G
|
到此为止 基于Gtid的mysql主从复制 配置成功!!!
mysql-proxy主从分离
下面我们就在上面mysql主从复制基础上配置mysql-proxy 读写分离,需要在主从之外另外加一台服务器,注意此mysql-proxy 尽量和 主从一个网段,保证能ping通,时间同步。
IP配置信息如下:
先简单的介绍一下mysql-proxy:
MySQL-Proxy
MySQL-Proxy是一个处于你的client端和MySQL server端之间的简单程序,它可以监测、分析或改变它们的通信。它使用灵活,没有限制,常见的用途包括:负载平衡,故障、查询分析,查询过滤和修改等等。
MySQL-Proxy就是这么一个中间层代理,简单的说,MySQL-Proxy就是一个连接池,负责将前台应用的连接请求转发给后台的数据库,并且通过使用lua脚本,可以实现复杂的连接控制和过滤,从而实现读写分离和负载平衡。对于应用来说,MySQL-Proxy是完全透明的,应用则只需要连接到MySQL-Proxy的监听端口即可。当然,这样proxy机器可能成为单点失效,但完全可以使用多个proxy机器做为冗余,在应用服务器的连接池配置中配置到多个proxy的连接参数即可。
MySQL-Proxy更强大的一项功能是实现“读写分离”,基本原理是让主数据库处理事务性查询,让从库处理SELECT查询。数据库复制被用来把事务性查询导致的变更同步到集群中的从库。
mysql-proxy的配置选项
mysql-proxy的配置选项大致可分为帮助选项、管理选项、代理选项及应用程序选项几类,下面一起去介绍它们。
--help
--help-admin
--help-proxy
--help-all ———— 以上四个选项均用于获取帮助信息;
--proxy-address=host:port ———— 代理服务监听的地址和端口;
--admin-address=host:port ———— 管理模块监听的地址和端口;
--proxy-backend-addresses=host:port ———— 后端mysql服务器的地址和端口;
--proxy-read-only-backend-addresses=host:port ———— 后端只读mysql服务器的地址和端口;
--proxy-lua-script=file_name ———— 完成mysql代理功能的Lua脚本;
--daemon ———— 以守护进程模式启动mysql-proxy;
--keepalive ———— 在mysql-proxy崩溃时尝试重启之;
--log-file=/path/to/log_file_name ———— 日志文件名称;
--log-level=level ———— 日志级别;
--log-use-syslog ———— 基于syslog记录日志;
--plugins=plugin,.. ———— 在mysql-proxy启动时加载的插件;
--user=user_name ———— 运行mysql-proxy进程的用户;
--defaults-file=/path/to/conf_file_name ———— 默认使用的配置文件路径;其配置段使用[mysql-proxy]标识;
--proxy-skip-profiling ———— 禁用profile;
--pid-file=/path/to/pid_file_name ———— 进程文件名;
安装配置mysql-proxy:
下载所需要的版本,这里的系统平台为rhel6.4 32位系统,因此就以mysql-proxy-0.8.3-linux-glibc2.3-x86-32bit.tar.gz为例。
1,添加代理用户
1
|
# useradd -r mysql-proxy
|
2,安装 mysql-proxy
1
2
3
4
|
# tar xvf mysql-proxy-0.8.3-linux-glibc2.3-x86-32bit.tar.gz -C /usr/local/
# cd /usr/local/
# ln -sv mysql-proxy-0.8.3-linux-glibc2.3-x86-32bit mysql-proxy
# cd mysql-proxy
|
修改PATH环境变量,让系统可以直接使用mysql的相关命令。
1
2
3
|
# vim /etc/profile.d/mysql-proxy.sh
export PATH=$PATH:/usr/local/mysql-proxy/bin
# . /etc/profile.d/mysql-proxy.sh
|
此时一个简单的服务就可以启动了,但暂时还不具备读写分离公共,且向下看。
3,启动mysql-proxy
1
2
3
|
# mysql-proxy --daemon --log-level=debug --log-file=/ var /log/mysql-proxy.log \
--plugins= "proxy" --proxy-backend-addresses= "172.16.66.1:3306" \
--proxy-read-only-backend-addresses= "172.16.66.2:3306"
|
4,在主服务器上创建用来测试的账号密码:
1
2
|
# mysql>GRANT ALL ON *.* TO root@ '172.16.%.%' IDENTIFIED BY 'redhat' ;
# mysql> flush privileges;
|
5,随便找一台能链接mysql 数据库的服务器 ,验证是否能通过代理端口4040 端口连接到 mysql-proxy,此时我们就暂且从主mysql上连接测试。
1
|
# mysql -uroot -p -h172. 16.163 . 1 --port= 4040
|
注意:这里可以使用绝对路径和相对路径, 绝对路径如下:
1
|
# /usr/local/mysql/bin/mysql -uroot -p -h172. 16.163 . 1 --port= 4040
|
验证图:
6, MYSQL-PROXY 本身不会实现读写分离,主要是依靠 Lua 脚本实现的
在 mysql-proxy 主机上 杀死mysql-proxy 进程 并添加 添加读写分离脚本
1
|
# killall mysql-proxy
|
7,在 mysql-proxy 的安装目录中有一个rw-splitting.lua 脚本,专门用来实现 读写分离,路径是/usr/local/mysql-proxy/share/doc/mysql-proxy/rw-splitting.lua
,重新启动时把此脚本加入到启动选项里面 实现读写分离。
1
2
3
4
|
# mysql-proxy --daemon --log-level=debug --log-file=/ var /log/mysql-proxy.log
--plugins= "proxy" --proxy-backend-addresses= "172.16.66.1:3306"
--proxy-read-only-backend-addresses= "172.16.66.2:3306"
--proxy-lua-script= " /usr/local/mysql-proxy/share/doc/mysql-proxy/rw-splitting.lua"
|
8,查看添加LUA读写分离脚本后是否能够正常启动。
1
2
|
# tail / var /log/mysql-proxy.log
# netstat -tunlp | grep 4040
|
9,为mysql-proxy 提供一个管理接口,方便以后随时查看后端mysql 服务器的状态和访问类型,实现管理功能
下面为大家提供一个管理接口的脚本,同样也是一个LUA 脚本,建议跟 读写分离脚本放在同一目录。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
# vim /usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua
function set_error(errmsg)
proxy.response = {
type = proxy.MYSQLD_PACKET_ERR,
errmsg = errmsg or "error"
}
end
function read_query(packet)
if packet:byte() ~= proxy.COM_QUERY then
set_error( "[admin] we only handle text-based queries (COM_QUERY)" )
return proxy.PROXY_SEND_RESULT
end
local query = packet:sub( 2 )
local rows = { }
local fields = { }
if query:lower() == "select * from backends" then
fields = {
{ name = "backend_ndx" ,
type = proxy.MYSQL_TYPE_LONG },
{ name = "address" ,
type = proxy.MYSQL_TYPE_STRING },
{ name = "state" ,
type = proxy.MYSQL_TYPE_STRING },
{ name = "type" ,
type = proxy.MYSQL_TYPE_STRING },
{ name = "uuid" ,
type = proxy.MYSQL_TYPE_STRING },
{ name = "connected_clients" ,
type = proxy.MYSQL_TYPE_LONG },
}
for i = 1 , #proxy.global.backends do
local states = {
"unknown" ,
"up" ,
"down"
}
local types = {
"unknown" ,
"rw" ,
"ro"
}
local b = proxy.global.backends
rows[#rows + 1 ] = {
i,
b.dst.name, -- configured backend address
states[b.state + 1 ], -- the C-id is pushed down starting at 0
types[b.type + 1 ], -- the C-id is pushed down starting at 0
b.uuid, -- the MySQL Server's UUID if it is managed
b.connected_clients -- currently connected clients
}
end
elseif query:lower() == "select * from help" then
fields = {
{ name = "command" ,
type = proxy.MYSQL_TYPE_STRING },
{ name = "description" ,
type = proxy.MYSQL_TYPE_STRING },
}
rows[#rows + 1 ] = { "SELECT * FROM help" , "shows this help" }
rows[#rows + 1 ] = { "SELECT * FROM backends" , "lists the backends and their state" }
else
set_error( "use 'SELECT * FROM help' to see the supported commands" )
return proxy.PROXY_SEND_RESULT
end
proxy.response = {
type = proxy.MYSQLD_PACKET_OK,
resultset = {
fields = fields,
rows = rows
}
}
return proxy.PROXY_SEND_RESULT
end
|
10,关闭进程 提供管理接口 的启动选项参数。
1
|
# killall mysql-proxy
|
11,重新启动 mysql-proxy
这次启动要添加以下启动选项 ,因为我们添加了额外的插件,把新加功能添加进来,选项如下.
--plugins=admin ———— 在mysql-proxy启动时加载的插件;
--admin-username="admin" 运行mysql-proxy进程管理的用户;
--admin-password="admin" 密码
--admin-lua-script="/usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua" 插件使用的配置文件路径;
1
2
3
4
5
6
|
# mysql-proxy --daemon --log-level=debug --log-file=/ var /log/mysql-proxy.log
--plugins= "proxy" --proxy-backend-addresses= "172.16.66.1:3306"
--proxy-read-only-backend-addresses= "172.16.66.2:3306"
--proxy-lua-script= " /usr/local/mysql-proxy/share/doc/mysql-proxy/rw-splitting.lua"
--plugins=admin --admin-username= "admin" --admin-password= "admin"
--admin-lua-script= "/usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua"
|
此时查看日志和端口发现多了一个端口4041 此端口就是刚添加的用于管理。
12,找个客户端验证管理接口功能,客户端除了mysql-proxy之外任何一个客户端都可以。记得使用管理端口4041 登陆,密码是admin
1
|
# mysql -uadmin -p -h172. 16.163 . 1 --port= 4041
|
13, 登陆接口之后执行以下命令,此接口也仅能执行这一条命令,查看读写分离状态。
此时因为没有读写操作所以状态都是unknown。
1
|
# mysql> select * from backends;
|
14,测试读写分离状态
找任意一台提供mysql客户端连接的服务器测试。我们就暂且使用主mysql 测试。
在正常情况下不管你在哪台服务器上操作都会先通过mysql-proxy 然后在分发到各个读写mysql上。
1
2
|
# mysql>mysql -uroot -p -h172. 16.163 . 1 --port= 4040 -e ‘select user from mysql.user;’
# mysql>mysql -uroot -p -h172. 16.163 . 1 --port= 4040 -e 'create database abc;'
|
15,再次通过管理模式查看读写分离状态和访问类型,此时你会看到 状态从unknown 变为 up。
1
2
|
# mysql -uadmin -p -h172. 16.163 . 1 --port= 4041
# mysql> select * from backends;
|
注意: 在测试读写分离的时候,我们可以分布测试,比如先测试读的语句,查看读写状态是否UP ,然后在测试写的语句,反反复复多测试几次才能看出效果,本人在测试的时候也出现过读的状态不能up 解决办法是 多测试即便就出来了。
16,添加配置文件优化管理接口启动步骤。大家看到每次启动的时候 启动选项非常多,一不小心都会写错 所以我们创建一个脚本或者配置文件把选项都写进去,每次启动的时候都调用此脚本。
1
2
3
4
5
6
7
8
9
10
11
12
|
# vim /etc/sysconfig/mysql-proxy
[mysql-proxy]
log-level=debug
log-file=/ var /log/mysql-proxy.log
plugins= "proxy"
proxy-backend-addresses= "172.16.66.1:3306"
proxy-read-only-backend-addresses= "172.16.66.2:3306"
proxy-lua-script= "/usr/local/mysql-proxy/share/doc/mysql-proxy/rw-splitting.lua"
plugins=admin
admin-username= "admin"
admin-password= "admin"
admin-lua-script= "/usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua"
|
17,给MYSQL-PORXY 添加启动脚本,以后就可以使用service mysql-proxy start|stop 等启动项。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
# vim /etc/rc.d/init.d/mysql-proxy
#!/bin/bash
#
# mysql-proxy This script starts and stops the mysql-proxy daemon
#
# chkconfig: - 78 30
# processname: mysql-proxy
# description: mysql-proxy is a proxy daemon for mysql
# Source function library.
. /etc/rc .d /init .d /functions
prog= "/usr/local/mysql-proxy/bin/mysql-proxy"
# Source networking configuration.
if [ -f /etc/sysconfig/network ]; then
. /etc/sysconfig/network
fi
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0
# Set default mysql-proxy configuration.
ADMIN_USER= "admin"
ADMIN_PASSWD= "admin"
ADMIN_LUA_SCRIPT= "/usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua"
PROXY_OPTIONS= "--daemon"
PROXY_PID= /var/run/mysql-proxy .pid
PROXY_USER= "mysql-proxy"
# Source mysql-proxy configuration.
if [ -f /etc/sysconfig/mysql-proxy ]; then
. /etc/sysconfig/mysql-proxy
fi
RETVAL=0
start() {
echo -n $ "Starting $prog: "
daemon $prog $PROXY_OPTIONS --pid- file =$PROXY_PID --proxy-address= "$PROXY_ADDRESS" --user=$PROXY_USER --admin-username= "$ADMIN_USER" --admin-lua-script= "$ADMIN_LUA_SCRIPT" --admin-password= "$ADMIN_PASSWORD"
RETVAL=$?
echo
if [ $RETVAL - eq 0 ]; then
touch /var/lock/subsys/mysql-proxy
fi
}
stop() {
echo -n $ "Stopping $prog: "
killproc -p $PROXY_PID -d 3 $prog
RETVAL=$?
echo
if [ $RETVAL - eq 0 ]; then
rm -f /var/lock/subsys/mysql-proxy
rm -f $PROXY_PID
fi
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
condrestart|try-restart)
if status -p $PROXY_PIDFILE $prog >& /dev/null ; then
stop
start
fi
;;
status)
status -p $PROXY_PID $prog
;;
*)
echo "Usage: $0 {start|stop|restart|reload|status|condrestart|try-restart}"
RETVAL=1
;;
esac
exit $RETVAL
|
18,给予脚本执行权限。
1
2
|
# chmod +x /etc/rc.d/init.d/mysql-proxy
# chkconfig --add mysql-proxy
|
到此 mysql-proxy 读写分离配置完成!!!