大纲

一、系统环境

二、准备工作

三、mysql-proxy安装与配置








一、系统环境

系统环境

CentOS5.8 x86_64

master.network.com    master    172.16.1.101

slave.network.com     slave     172.16.1.105

CentOS6.5 x86_64

myproxy.network.com   proxy    172.16.1.102


软件包

  • mysql-5.6.26-linux-glibc2.5-x86_64.tar.gz(二进制通用安装包)

  • mysql-proxy-0.8.5-1.el6.x86_64.rpm 

拓扑图



二、MySQL初始化安装过程

1、时间同步

[root@master ~]# ntpdate s2c.time.edu.cn
[root@slave ~]# ntpdate s2c.time.edu.cn
[root@proxy ~]# ntpdate s2c.time.edu.cn

可根据需要在每个节点上定义crontab任务
[root@master ~]# which ntpdate
/sbin/ntpdate
[root@master ~]# echo "*/5 * * * * /sbin/ntpdate s2c.time.edu.cn &> /dev/null" >> /var/spool/cron/root 
[root@master ~]# crontab -l
*/5 * * * * /sbin/ntpdate s2c.time.edu.cn &> /dev/null

2、主机名称要与uname -n保持一致,并通过/etc/hosts解析

master
[root@master ~]# hostname master.network.com
[root@master ~]# uname -n
master.network.com
[root@master ~]# sed -i 's@\(HOSTNAME=\).*@\1master.network.com@g'  /etc/sysconfig/network

slave
[root@slave ~]# hostname slave.network.com
[root@slave ~]# uname -n
slave.network.com
[root@slave ~]# sed -i 's@\(HOSTNAME=\).*@\1slave.network.com@g'  /etc/sysconfig/network

proxy
[root@myproxy ~]# hostname myproxy.network.com
[root@myproxy ~]# uname -n
myproxy.network.com
[root@myproxy ~]# sed -i 's@\(HOSTNAME=\).*@\1myproxy.network.com@g'  /etc/sysconfig/network

master添加hosts解析
[root@master ~]# vim /etc/hosts
[root@master ~]# cat /etc/hosts
# Do not remove the following line, or various programs
# that require network functionality will fail.
127.0.0.1		CentOS5.8 CentOS5 localhost.localdomain localhost
::1		localhost6.localdomain6 localhost6
172.16.1.101	master.network.com 	master
172.16.1.105	slave.network.com 	slave
172.16.1.102    myproxy.network.com     myproxy

拷贝此hosts文件至slave
[root@master ~]# scp /etc/hosts slave:/etc/
root@slave's password: 
hosts                  100%  233     0.2KB/s   00:00

拷贝此hosts文件至myproxy
[root@master ~]# scp /etc/hosts myproxy:/etc/
root@slave's password: 
hosts                  100%  233     0.2KB/s   00:00

3、关闭iptables和selinux

master
[root@master ~]# service iptables stop
[root@master ~]# vim /etc/sysconfig/selinux 
[root@master ~]# cat /etc/sysconfig/selinux
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#	enforcing - SELinux security policy is enforced.
#	permissive - SELinux prints warnings instead of enforcing.
#	disabled - SELinux is fully disabled.
#SELINUX=permissive
SELINUX=disabled
# SELINUXTYPE= type of policy in use. Possible values are:
#	targeted - Only targeted network daemons are protected.
#	strict - Full SELinux protection.
SELINUXTYPE=targeted

slave
[root@slave ~]# service iptables stop
[root@slave ~]# vim /etc/sysconfig/selinux 
[root@slave ~]# cat /etc/sysconfig/selinux
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#	enforcing - SELinux security policy is enforced.
#	permissive - SELinux prints warnings instead of enforcing.
#	disabled - SELinux is fully disabled.
#SELINUX=permissive
SELINUX=disabled
# SELINUXTYPE= type of policy in use. Possible values are:
#	targeted - Only targeted network daemons are protected.
#	strict - Full SELinux protection.
SELINUXTYPE=targeted

proxy
[root@myproxy ~]# service iptables stop
[root@myproxy ~]# vim /etc/sysconfig/selinux 
[root@myproxy ~]# cat /etc/sysconfig/selinux
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#	enforcing - SELinux security policy is enforced.
#	permissive - SELinux prints warnings instead of enforcing.
#	disabled - SELinux is fully disabled.
#SELINUX=permissive
SELINUX=disabled
# SELINUXTYPE= type of policy in use. Possible values are:
#	targeted - Only targeted network daemons are protected.
#	strict - Full SELinux protection.
SELINUXTYPE=targeted


三、mysql-proxy安装与配置

1、安装mysql-proxy

我这里使用的是epel源,请自行配置epel源或下载rpm包,源码包编译安装也行
[root@myproxy ~]# yum install -y mysql-proxy

查看安装生成的文件
[root@myproxy ~]# rpm -ql mysql-proxy
/etc/mysql-proxy.cnf
/etc/rc.d/init.d/mysql-proxy
/etc/sysconfig/mysql-proxy
/usr/bin/mysql-binlog-dump
/usr/bin/mysql-myisam-dump
/usr/bin/mysql-proxy
/usr/lib64/libmysql-chassis-glibext.so.0
/usr/lib64/libmysql-chassis-glibext.so.0.0.0
/usr/lib64/libmysql-chassis-timing.so.0
/usr/lib64/libmysql-chassis-timing.so.0.0.0
/usr/lib64/libmysql-chassis.so.0
/usr/lib64/libmysql-chassis.so.0.0.0
/usr/lib64/libmysql-proxy.so.0
/usr/lib64/libmysql-proxy.so.0.0.0
/usr/lib64/mysql-proxy
/usr/lib64/mysql-proxy/lua
/usr/lib64/mysql-proxy/lua/admin.lua
/usr/lib64/mysql-proxy/lua/chassis.so
/usr/lib64/mysql-proxy/lua/glib2.so
/usr/lib64/mysql-proxy/lua/lfs.so
/usr/lib64/mysql-proxy/lua/lpeg.so
/usr/lib64/mysql-proxy/lua/mysql.so
/usr/lib64/mysql-proxy/lua/posix.so
/usr/lib64/mysql-proxy/lua/proxy
/usr/lib64/mysql-proxy/lua/proxy/auto-config.lua
/usr/lib64/mysql-proxy/lua/proxy/balance.lua
/usr/lib64/mysql-proxy/lua/proxy/commands.lua
/usr/lib64/mysql-proxy/lua/proxy/parser.lua
/usr/lib64/mysql-proxy/lua/proxy/test.lua
/usr/lib64/mysql-proxy/lua/proxy/tokenizer.lua
/usr/lib64/mysql-proxy/plugins
/usr/lib64/mysql-proxy/plugins/libadmin.so
/usr/lib64/mysql-proxy/plugins/libdebug.so
/usr/lib64/mysql-proxy/plugins/libproxy.so
/usr/lib64/mysql-proxy/plugins/libreplicant.so
/usr/share/doc/mysql-proxy-0.8.5
/usr/share/doc/mysql-proxy-0.8.5/AUTHORS
/usr/share/doc/mysql-proxy-0.8.5/COPYING
/usr/share/doc/mysql-proxy-0.8.5/NEWS
/usr/share/doc/mysql-proxy-0.8.5/README
/usr/share/doc/mysql-proxy-0.8.5/examples
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-basic.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-constants.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-inject.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-keepalive.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-monitor.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-packets.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-prep-stmts.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-query-time.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-resultset.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-rewrite.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-routing.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-scramble.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-states.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-tokenize.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-union.lua
/usr/share/doc/mysql-proxy-0.8.5/examples/tutorial-warnings.lua

2、启动mysql-proxy

[root@myproxy ~]# mysql-proxy --daemon --log-level=debug --log-file="/var/log/mysql-proxy.log" \
> --plugins="proxy" --proxy-backend-addresses="172.16.1.101:3306" \
> --proxy-read-only-backend-addresses="172.16.1.105:3306"

--proxy-backend-addresses后面跟的是主服务器,能读能写的
--proxy-read-only-backend-addresses后面跟的是从服务器,只能读的


查看日志信息
[root@myproxy ~]# tail /var/log/mysql-proxy.log 
2016-01-03 16:13:47: (critical) plugin proxy 0.8.5 started
2016-01-03 16:13:47: (debug) max open file-descriptors = 1024
2016-01-03 16:13:47: (message) proxy listening on port :4040
2016-01-03 16:13:47: (message) added read/write backend: 172.16.1.101:3306
2016-01-03 16:13:47: (message) added read-only backend: 172.16.1.105:3306

查看监听端口为4040
[root@myproxy ~]# netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address       Foreign Address     State       PID/Program name   
tcp        0      0 0.0.0.0:22          0.0.0.0:*           LISTEN      1106/sshd           
tcp        0      0 0.0.0.0:49401       0.0.0.0:*           LISTEN      1056/rpc.statd      
tcp        0      0 0.0.0.0:4040        0.0.0.0:*           LISTEN      3483/mysql-proxy    
tcp        0      0 :::22               :::*                LISTEN      1106/sshd           
tcp        0      0 :::52904            :::*                LISTEN      1056/rpc.stat

3、远程连接mysql-proxy

在从服务器上尝试连接一下proxy服务器
[root@slave ~]# mysql -uroot -h172.16.1.102 --port=4040 -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'root'@'172.16.1.102' (using password: YES)

在主服务器上允许远程访问
[root@master ~]# mysql 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.6.26-log MySQL Community Server (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'172.16.%.%' IDENTIFIED BY 'redhat';
Query OK, 0 rows affected (0.77 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.22 sec)

mysql> \q
Bye

然后再尝试连接
[root@slave ~]# mysql -uroot -h172.16.1.102 --port=4040 -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 13
Server version: 5.6.26-log MySQL Community Server (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> CREATE DATABASE proxydb;
Query OK, 1 row affected (0.10 sec)

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema | 
| mysql              | 
| performance_schema | 
| proxydb            | 
| test               | 
+--------------------+
5 rows in set (0.06 sec)

再在从服务器上查看是否有此库,有的话可以说明我们的写操作是被定向至主服务器上的
[root@slave ~]# mysql -S /tmp/mysql.sock 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 14
Server version: 5.6.26-log MySQL Community Server (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema | 
| mysql              | 
| performance_schema | 
| proxydb            |        
| test               | 
+--------------------+
5 rows in set (0.02 sec)

我们的写请求凑巧被定向至主服务器了,因为mysql-proxy自身是没有读写分离功能,得借助于lua脚本才能实现

4、使用管理lua脚本

系统默认也没有提供,所以我们需要自行创建
[root@myproxy ~]# vim /usr/share/doc/mysql-proxy-0.8.5/examples/admin.lua
[root@myproxy ~]# cat /usr/share/doc/mysql-proxy-0.8.5/examples/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[i]

			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

5、使用读写分离脚本

因为rpm包里没有提供读写分离lua脚本,所以我们自行从同版本二进制包中拷贝了一个
[root@myproxy ~]# wget http://ftp.ntu.edu.tw/pub/MySQL/Downloads/MySQL-Proxy/mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz

[root@myproxy ~]# tar xf mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz 
[root@myproxy ~]# cp mysql-proxy-0.8.5-linux-el6-x86-64bit/share/doc/mysql-proxy/rw-splitting.lua /usr/share/doc/mysql-proxy-0.8.5/examples/

先强行停止mysql-proxy
[root@myproxy ~]# pkill mysql-proxy
[root@myproxy ~]# ps aux | grep "mysql-proxy"
root      3657  0.0  0.3 103244   836 pts/3    S+   18:36   0:00 grep mysql-proxy

启动mysql-proxy
[root@myproxy ~]# mysql-proxy --daemon --log-level=debug --log-file=/var/log/mysql-proxy.log --plugins="proxy" --proxy-backend-addresses="172.16.1.101:3306" --proxy-read-only-backend-addresses="172.16.1.105:3306" --proxy-lua-script="/usr/share/doc/mysql-proxy-0.8.5/examples/rw-splitting.lua" --plugins=admin --admin-username="admin" --admin-password="admin" --admin-lua-script="/usr/share/doc/mysql-proxy-0.8.5/examples/admin.lua"

查看监听端口
[root@myproxy ~]# netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address         Foreign Address     State       PID/Program name   
tcp        0      0 0.0.0.0:22            0.0.0.0:*           LISTEN      1106/sshd           
tcp        0      0 0.0.0.0:49401         0.0.0.0:*           LISTEN      1056/rpc.statd      
tcp        0      0 0.0.0.0:4040          0.0.0.0:*           LISTEN      3675/mysql-proxy    
tcp        0      0 0.0.0.0:4041          0.0.0.0:*           LISTEN      3675/mysql-proxy    
tcp        0      0 :::22                 :::*                LISTEN      1106/sshd           
tcp        0      0 :::52904              :::*                LISTEN      1056/rpc.statd 

查看日志
[root@myproxy ~]# tail /var/log/mysql-proxy.log 
2016-01-03 18:37:34: (critical) plugin proxy 0.8.5 started
2016-01-03 18:37:34: (debug) max open file-descriptors = 1024
2016-01-03 18:37:34: (message) proxy listening on port :4040
2016-01-03 18:37:34: (message) added read/write backend: 172.16.1.101:3306
2016-01-03 18:37:34: (message) added read-only backend: 172.16.1.105:3306

6、测试读写分离效果

首先连接管理端口查看下状态
[root@slave mysql]# mysql -uadmin -h 172.16.1.102 -padmin --port=4041
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.0.99-agent-admin

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> SELECT * FROM backends;
+-------------+-------------------+---------+------+------+-------------------+
| backend_ndx | address           | state   | type | uuid | connected_clients |
+-------------+-------------------+---------+------+------+-------------------+
|           1 | 172.16.1.101:3306 | unknown | rw   | NULL |                 0 | 
|           2 | 172.16.1.105:3306 | unknown | ro   | NULL |                 0 | 
+-------------+-------------------+---------+------+------+-------------------+
2 rows in set (0.01 sec)
可以看到主节点和从节点都为unknown,因为我们没有发起任何读或者写操作

在另一个节点上向mysql-proxy发起一个写操作
[root@node3 ~]# mysql -uroot -h 172.16.1.102 -p --port=4040 -e 'CREATE DATABASE hellodb;'
Enter password: 

再来通过管理接口查看状态信息,可以看到主节点状态已经为up
mysql> SELECT * FROM backends;
+-------------+-------------------+---------+------+------+-------------------+
| backend_ndx | address           | state   | type | uuid | connected_clients |
+-------------+-------------------+---------+------+------+-------------------+
|           1 | 172.16.1.101:3306 | up      | rw   | NULL |                 0 | 
|           2 | 172.16.1.105:3306 | unknown | ro   | NULL |                 0 | 
+-------------+-------------------+---------+------+------+-------------------+
2 rows in set (0.00 sec)

接下来我们再发起一个读请求
[root@node3 ~]# mysql -uroot -h 172.16.1.102 -p --port=4040 -e 'SELECT user,host,password FROM mysql.user;'
Enter password: 
+---------+-------------------+-------------------------------------------+
| user    | host              | password                                  |
+---------+-------------------+-------------------------------------------+
| root    | localhost         |                                           | 
| root    | slave.network.com |                                           | 
| root    | 127.0.0.1         |                                           | 
| root    | ::1               |                                           | 
|         | localhost         |                                           | 
|         | slave.network.com |                                           | 
| repuser | 172.16.%.%        | *304A91F0E46BBB1E641D3D95E225E9AAA27077CE | 
| root    | 172.16.%.%        | *84BB5DF4823DA319BBF86C99624479A198E6EEE9 | 
+---------+-------------------+-------------------------------------------+

再来通过管理接口查看状态信息,可以看到从节点状态已经为up
mysql> SELECT * FROM backends;
+-------------+-------------------+-------+------+------+-------------------+
| backend_ndx | address           | state | type | uuid | connected_clients |
+-------------+-------------------+-------+------+------+-------------------+
|           1 | 172.16.1.101:3306 | up    | rw   | NULL |                 0 | 
|           2 | 172.16.1.105:3306 | up    | ro   | NULL |                 0 | 
+-------------+-------------------+-------+------+------+-------------------+
2 rows in set (0.00 sec)

7、将配置信息保存至配置文件中

[root@myproxy ~]# vim /etc/mysql-proxy.cnf
[mysql-proxy]
daemon = true
pid-file = /var/run/mysql-proxy.pid
log-file = /var/log/mysql-proxy.log
log-level = debug
max-open-files = 1024
plugins = admin,proxy
#user = mysql-proxy
#
#Proxy Configuration
proxy-address = 0.0.0.0:3306
proxy-backend-addresses = 172.16.1.101:3306
proxy-read-only-backend-addresses = 172.16.1.105:3306
proxy-lua-script = /usr/share/doc/mysql-proxy-0.8.5/examples/rw-splitting.lua
#proxy-skip-profiling = true
#
# Admin Configuration
#admin-address = 0.0.0.0:4041
admin-lua-script = /usr/share/doc/mysql-proxy-0.8.5/examples/admin.lua
admin-username = admin
admin-password = admin

然后重启mysql-proxy服务
[root@myproxy ~]# service mysql-proxy restart
Stopping mysql-proxy:                                      [  OK  ]
Starting mysql-proxy:                                      [  OK  ]

查看监听端口,可以看到已经监听在3306端口了
[root@myproxy ~]# netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address        Foreign Address      State       PID/Program name   
tcp        0      0 0.0.0.0:22           0.0.0.0:*            LISTEN      1106/sshd           
tcp        0      0 0.0.0.0:49401        0.0.0.0:*            LISTEN      1056/rpc.statd      
tcp        0      0 0.0.0.0:4041         0.0.0.0:*            LISTEN      4040/mysql-proxy    
tcp        0      0 0.0.0.0:3306         0.0.0.0:*            LISTEN      4040/mysql-proxy    
tcp        0      0 :::22                :::*                 LISTEN      1106/sshd           
tcp        0      0 :::52904             :::*                 LISTEN      1056/rpc.statd 

客户端尝试连接访问
[root@node3 ~]# mysql -uroot -h 172.16.1.102 -p 
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 26
Server version: 5.6.26-log MySQL Community Server (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> CREATE DATABASE mydb;
Query OK, 1 row affected (0.05 sec)

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema | 
| hellodb            | 
| mydb               | 
| mysql              | 
| performance_schema | 
| proxydb            | 
| test               | 
+--------------------+
7 rows in set (0.03 sec)

mysql> SHOW TABLES FROM mydb;
Empty set (0.01 sec) 

再从管理接口查看后端服务器状态
mysql> SELECT * FROM backends;
+-------------+-------------------+-------+------+------+-------------------+
| backend_ndx | address           | state | type | uuid | connected_clients |
+-------------+-------------------+-------+------+------+-------------------+
|           1 | 172.16.1.101:3306 | up    | rw   | NULL |                 0 | 
|           2 | 172.16.1.105:3306 | up    | ro   | NULL |                 0 | 
+-------------+-------------------+-------+------+------+-------------------+
2 rows in set (0.00 sec)
到此,mysql借助于mysql-proxy实现读写分离的目的已然实现