大纲
一、系统环境
二、准备工作
三、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实现读写分离的目的已然实现