MySQL5.5读写分离之mysql-proxy

通常一个网站在初期访问量都比较小,所以一般的小架构足以支撑。但是,当网站逐渐发展起来后,随之而来的是大量的访问,这时候最先出现的瓶颈就是数据库了。因为数据的写入读取操作(I/O)是集群中响应速度最慢的,所以在集群建设时就要规划好后端存储架构。

后端存储数据库架构普遍是主从复制,这样解决了数据备份问题。但是,由前端来的读写请求都要经过主库,量小没问题,当量大到超过主库的性能极限时,主库分分钟会宕机。

为了避免主库宕机这种灾难性事件的发生,读写分离的设计诞生了!把写的请求只交给主库,读的请求由主库和从库一起分摊,这样就大大减轻了主库的负担。

大部分公司会由开发部门在软件层面实现对数据库的读写分离,其次可以选择读写分离的中间件如:TDDL、amoeba、cobar、MySQL-proxy、Atlas、MyCat。

本次测试采用MySQL官方发布的MySQL-proxy。

官网下载地址(二进制包):https://downloads.mysql.com/archives/get/file/mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz

测试环境:

[[email protected] ~]# cat /etc/redhat-release

CentOS release 6.8 (Final)

[[email protected] ~]# uname -r

2.6.32-642.el6.x86_64

MySQL-proxy   IP:192.168.0.86

MySQL-master  IP:192.168.0.88

MySQL-slave   IP:192.168.0.90

前提:MySQL主库与从库已经实现主从复制。

实现主从复制请参考我的前一篇博文:http://yuyicong.blog.51cto.com/11274530/1919158

接下来的操作在proxy服务器上:

[[email protected] ~]# cd /usr/local/src/

[[email protected] src]# wget https://downloads.mysql.com/archives/get/file/mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz

[[email protected] src]# ll -h

total 12M

-rw-r--r-- 1 root root 12M Aug 19  2014 mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz

[[email protected] src]# tar zxf mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz -C /usr/local/

[[email protected] src]# cd ..

[[email protected] local]# mv mysql-proxy-0.8.5-linux-el6-x86-64bit/ mysql-proxy-0.8.5

[[email protected] local]# ll -d mysql-proxy-0.8.5

drwxr-xr-x  8 7161 wheel 4096 Aug 19  2014 mysql-proxy-0.8.5    # 看到所属用户和组有问题

[[email protected] local]# chown -R root:root mysql-proxy-0.8.5/  # 改为root

[[email protected] local]# ln -s mysql-proxy-0.8.5/ mysql-proxy    # 必备软连接

[[email protected] local]# cd mysql-proxy

[[email protected] mysql-proxy]# mkdir etc              # 创建 lua 脚本存放目录

[[email protected] mysql-proxy]# mkdir logs            # 创建日志目录

把实现读写分离的 lua 脚本复制到 etc 目录下

[[email protected] mysql-proxy]# cp share/doc/mysql-proxy/rw-splitting.lua etc/

[[email protected] mysql-proxy]# cp share/doc/mysql-proxy/admin-sql.lua etc/

创建启动参数文件,启动服务时命令行就不用老长老长的。

[[email protected] ~]# vim /etc/mysql-proxy.cnf

[mysql-proxy]
admin-username=proxy     # 连接主从mysql共有的用户
admin-password=123       # 连接用户的密码
proxy-address=192.168.0.86:3306   # mysql-proxy监听本地工作ip和端口,不加端口默认是4040,为了方便管理这里用3306
proxy-backend-addresses=192.168.0.87:3306    # 指定后端主库
proxy-read-only-backend-addresses=192.168.0.90:3306  # 指定后端只读从库
proxy-lua-script=/usr/local/mysql-proxy/etc/rw-splitting.lua  # 指定实现读写分离的lua脚本
admin-lua-script=/usr/local/mysql-proxy/etc/admin-sql.lua     # 指定管理脚本
pid-file=/var/run/mysql-proxy.pid   
log-file=/usr/local/mysql-proxy/logs/mysql-proxy.log  # 日志位置
log-level=info  # 定义log日志级别,由高到低分别有(error|warning|info|message|debug)
daemon=true     # 以守护进程方式运行
keepalive=true  # work进程崩溃时,尝试重启

启动服务

[[email protected] ~]# /usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/etc/mysql-proxy.cnf

2017-04-24 16:40:19: (critical) mysql-proxy-cli.c:326: loading config from ‘/etc/mysql-proxy.cnf‘ failed: permissions of /etc/mysql-proxy.cnf aren‘t secure (0660 or stricter required)

2017-04-24 16:40:19: (message) Initiating shutdown, requested from mysql-proxy-cli.c:328

2017-04-24 16:40:19: (message) shutting down normally, exit code is: 1

!!看到无法启动,文件权限要改,因为文件里面有账号密码。

[[email protected] ~]# chmod 660 /etc/mysql-proxy.cnf     # 改权限

[[email protected] ~]# ll /etc/mysql-proxy.cnf

-rw-rw---- 1 root root 432 Apr 24 16:31 /etc/mysql-proxy.cnf

[[email protected] ~]# /usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/etc/mysql-proxy.cnf                                              #  重新启动

[[email protected] ~]# netstat -lntup   # 查看服务

Active Internet connections (only servers)

Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name

tcp        0      0 192.168.0.86:3306           0.0.0.0:*                   LISTEN      3086/mysql-proxy

老是命令行敲一长串命令肯定不科学了,直接上服务管理脚本。

[[email protected] ~]# vim /etc/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

DEFAULT_FILE=/etc/mysql-proxy.cnf
PROXY_PID=/var/run/mysql-proxy.pid

RETVAL=0

start() {
    echo -n $"Starting MySQL-proxy...  : "
    daemon $prog --defaults-file=$DEFAULT_FILE
    RETVAL=$?
    echo
    if [ $RETVAL -eq 0 ]; then
        touch /var/lock/subsys/mysql-proxy.lock
    fi
}

stop() {
    echo -n $"Stopping MySQL-proxy...  : "
    killproc -p $PROXY_PID -d 3 $prog
    RETVAL=$?
    echo
    if [ $RETVAL -eq 0 ]; then
        rm -f /var/lock/subsys/mysql-proxy.lock
        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

[[email protected] ~]# chmod +x /etc/init.d/mysql-proxy   #  给执行权限

[[email protected] ~]# chkconfig mysql-proxy on           # 可以加入开机启动

测试一下脚本:

[[email protected] ~]# /etc/init.d/mysql-proxy status
mysql-proxy (pid  3086) is running...
[[email protected] ~]# 
[[email protected] ~]# /etc/init.d/mysql-proxy stop
Stopping MySQL-proxy...  :                                 [  OK  ]
[[email protected] ~]# 
[[email protected] ~]# /etc/init.d/mysql-proxy status
mysql-proxy is stopped
[[email protected] ~]# netstat -lntup
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      1079/sshd           
tcp        0      0 :::22                       :::*                        LISTEN      1079/sshd           
[[email protected] ~]# /etc/init.d/mysql-proxy start
Starting MySQL-proxy...  :                                 [  OK  ]
[[email protected] ~]# /etc/init.d/mysql-proxy restart
Stopping MySQL-proxy...  :                                 [  OK  ]
Starting MySQL-proxy...  :                                 [  OK  ]
[[email protected] ~]# 
[[email protected] ~]# netstat -lntup               
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name   
tcp        0      0 192.168.0.86:3306           0.0.0.0:*                   LISTEN      3143/mysql-proxy

以上MySQL-proxy服务器搭建完成,但是用于连接后端数据库的用户:proxy还需要在数据库端创建

数据库Master端:创建proxy用户,给增删改查权限

[[email protected] ~]# mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.5.55-log MySQL Community Server (GPL)

Copyright (c) 2000, 2017, 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.

Master> 
Master> grant insert,delete,update,select on *.* to [email protected]‘192.168.0.86‘ identified by ‘123‘;
Query OK, 0 rows affected (0.00 sec)

Master> select user,host from mysql.user;                                       +-------+--------------+
| user  | host         |
+-------+--------------+
| root  | 127.0.0.1    |
| rep   | 192.168.0.%  |
| proxy | 192.168.0.86 |
| root  | localhost    |
+-------+--------------+
4 rows in set (0.00 sec)

Master> show grants for [email protected]‘192.168.0.86‘;
+------------------------------------------------------------------------------------------------------------------------------------------+
| Grants for [email protected]                                                                                                            |
+------------------------------------------------------------------------------------------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO ‘proxy‘@‘192.168.0.86‘ IDENTIFIED BY PASSWORD ‘*23AE809DDACAF96AF0FD78ED04B6A265E05AA257‘ |
+------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Slave端:此时已经与主库一致拥有了proxy用户,但是从库只能读(select),所以要对proxy回收权限。

Slave> show grants for [email protected]‘192.168.0.86‘;
+------------------------------------------------------------------------------------------------------------------------------------------+
| Grants for [email protected]                                                                                                            |
+------------------------------------------------------------------------------------------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO ‘proxy‘@‘192.168.0.86‘ IDENTIFIED BY PASSWORD ‘*23AE809DDACAF96AF0FD78ED04B6A265E05AA257‘ |
+------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Slave> revoke insert,update,delete on *.* from [email protected]‘192.168.0.86‘; # 只留查询权限
Query OK, 0 rows affected (0.00 sec)

Slave> show grants for [email protected]‘192.168.0.86‘;                        
+------------------------------------------------------------------------------------------------------------------+
| Grants for [email protected]                                                                                    |
+------------------------------------------------------------------------------------------------------------------+
| GRANT SELECT ON *.* TO ‘proxy‘@‘192.168.0.86‘ IDENTIFIED BY PASSWORD ‘*23AE809DDACAF96AF0FD78ED04B6A265E05AA257‘ |
+------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

测试读写分离

为了方便测试,修改 rw-splitting.lua 脚本里触发读写分离参数

[[email protected] ~]# vim /usr/local/mysql-proxy/etc/rw-splitting.lua 
-- connection pool
if not proxy.global.config.rwsplit then
        proxy.global.config.rwsplit = {
                min_idle_connections = 1,  # 默认超过4个连接数时,才开始读写分离,改为1
                max_idle_connections = 8,  # 默认最大连接数8,不动它

                is_debug = false
        }
end

[[email protected] ~]# /etc/init.d/mysql-proxy restart       # 重启一下
Stopping MySQL-proxy...  :                                 [  OK  ]
Starting MySQL-proxy...  :                                 [  OK  ]

数据库Master端

Master> create database proxy;         # 建个库
Query OK, 1 row affected (0.00 sec)
 
Master> create table master(id int(2),name char(10));  # 停掉从库 IO线程后再建个表
Query OK, 0 rows affected (0.18 sec)

Master> desc master;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(2)   | YES  |     | NULL    |       |
| name  | char(10) | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)

Slave端

Slave> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| proxy              |     # 新建的库已经有了
| school             |
| test               |
+--------------------+
6 rows in set (0.00 sec)
 
Slave> stop slave io_thread;      # 停掉 IO 线程
Query OK, 0 rows affected (0.00 sec)

Slave> show slave status\G  
*************************** 1. row ***************************
               Slave_IO_State: 
                  Master_Host: 192.168.0.88
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000019
          Read_Master_Log_Pos: 351
               Relay_Log_File: relay-bin.000011
                Relay_Log_Pos: 497
        Relay_Master_Log_File: mysql-bin.000019
             Slave_IO_Running: No
            Slave_SQL_Running: Yes
            
Slave> use proxy;
Database changed

Slave> create table slave(id int(2),name char(10));  # 建个表
Query OK, 0 rows affected (0.00 sec)

Slave> desc slave;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(2)   | YES  |     | NULL    |       |
| name  | char(10) | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)

Slave> insert into slave values(90,‘slave‘);    # 插入一条数据
Query OK, 1 row affected (0.00 sec)

Slave> select * from slave;
+------+-------+
| id   | name  |
+------+-------+
|   90 | slave |
+------+-------+
1 row in set (0.00 sec)

模拟远程连接MySQL-proxy服务器进行读写操作

[[email protected] ~]# mysql -h192.168.0.86 -uproxy -P3306 -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.5.55-log MySQL Community Server (GPL)

Copyright (c) 2000, 2017, 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.

mysql> 
mysql> use proxy;
Database changed
mysql> 
mysql> show tables;   # show 出来的只有master这个表
+-----------------+
| Tables_in_proxy |
+-----------------+
| master          |
+-----------------+
1 row in set (0.01 sec)

mysql> desc master;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(2)   | YES  |     | NULL    |       |
| name  | char(10) | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> insert into master values(88,‘master‘);  # 往master表里插入数据
Query OK, 1 row affected (0.00 sec)        <<--- 写入是 OK 的

mysql> select * from master;
ERROR 1146 (42S02): Table ‘proxy.master‘ doesn‘t exist  # 明显查不到的,因为去找从库了,从库上没有这表。

mysql> show tables;   # 我们show时只能看到 master 表,好像show只能找主库。
+-----------------+
| Tables_in_proxy |
+-----------------+
| master          |
+-----------------+
1 row in set (0.00 sec)

mysql> select * from slave;  # 我们直接查 slave 表
+------+-------+
| id   | name  |
+------+-------+
|   90 | slave |         <<--- 查到了,读操作成功
+------+-------+
1 row in set (0.00 sec)

mysql>

恢复 slave IO 线程

Slave> start slave io_thread;
Query OK, 0 rows affected (0.00 sec)

Slave> show slave status\G   
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.0.88
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000019
          Read_Master_Log_Pos: 1566
               Relay_Log_File: relay-bin.000012
                Relay_Log_Pos: 1468
        Relay_Master_Log_File: mysql-bin.000019
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

再次模拟远程连接MySQL-proxy服务器查 master 表

[[email protected] ~]# mysql -h192.168.0.86 -uproxy -P3306 -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.5.55-log MySQL Community Server (GPL)

Copyright (c) 2000, 2017, 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.

mysql> 
mysql> use proxy;
Database changed
mysql> 
mysql> select * from master;
+------+--------+
| id   | name   |
+------+--------+
|   88 | master |        <<----由于从库恢复后开始复制主库数据,所以可以查到了。
+------+--------+
1 row in set (0.00 sec)

以上MySQL-proxy读写分离完成。


存在的问题:

当模拟前端连接MySQL-proxy服务器并进行数据库操作时,MySQL-proxy服务器端屏幕有信息输出,不知道为什么?

信息如下:

[[email protected] ~]#     server default db: proxy

client default db: school

syncronizing

server default db: proxy

client default db: school

syncronizing

server default db: school

client default db: proxy

syncronizing

时间: 2024-10-21 18:06:23

MySQL5.5读写分离之mysql-proxy的相关文章

mysql5.5 读写分离 半同步

读写分离 一般我们从服务器端是只负责客户的读请求的,主服务端负责写请求的.那么配置下吧!    首先查看下从服务器端的只读方式是否打开.    mysql> show global variables like 'read%';    +----------------------+---------+    | Variable_name        | Value   |    +----------------------+---------+    | read_buffer_size

实现MySQL读写分离,MySQL性能调优

实现MySQL读写分离 1.1 问题 本案例要求配置2台MySQL服务器+1台代理服务器,实现MySQL代理的读写分离: 用户只需要访问MySQL代理服务器,而实际的SQL查询.写入操作交给后台的2台MySQL服务器来完成 其中Master服务器允许SQL查询.写入,Slave服务器只允许SQL查询 1.2 方案 使用4台RHEL 7.2虚拟机,如图-1所示.其中192.168.4.10.192.168.4.20分别作为MySQL主.从服务器,是整个服务的后端:另一台 192.168.4.100

Database基础(六):实现MySQL读写分离、MySQL性能调优

一.实现MySQL读写分离 目标: 本案例要求配置2台MySQL服务器+1台代理服务器,实现MySQL代理的读写分离: 用户只需要访问MySQL代理服务器,而实际的SQL查询.写入操作交给后台的2台MySQL服务器来完成 其中Master服务器允许SQL查询.写入,Slave服务器只允许SQL查询 方案: 使用4台RHEL 7.2虚拟机,如下图所示.其中192.168.4.10.192.168.4.20分别作为MySQL主.从服务器,是整个服务的后端:另一台 192.168.4.100作为MyS

Spring002--实现读写分离(Mysql实现主从复制)

Spring AOP实现读写分离(Mysql实现主从复制) 本文来自于博客:http://www.cnblogs.com/bjlhx/p/8297460.html 一.背景 一般应用对数据库而言都是"读多写少",也就说对数据库读取数据的压力比较大主库,负责写入数据,我们称之为:写库:从库,负责读取数据,我们称之为:读库: 1. 读库和写库的数据一致:2. 写数据必须写到写库:3. 读数据必须到读库: 二.方案 解决读写分离的方案有两种:应用层解决和中间件解决. 2.1.应用层解决 优点

GTID及mysql-proxy实现mysql5.6读写分离

GTID说明: MySQL 5.6引入的GTID(Global Transaction IDs)使得其复制功能的配置.监控及管理变得更加易于实现,且更加健壮. 要在MySQL 5.6中使用复制功能,其服务配置段[mysqld]中于少应该定义如下选项: binlog-format:二进制日志的格式,有row.statement和mixed几种类型: 用于启动GTID及满足附属的其它需求: log-slave-updates:当从服务器复制时是否启用二进制日志 gtid-mode:是否启用gtid功

超详细搭建Mysql5.5读写分离

Amoeba简介 Amoeba(变形虫)项目,该开源框架于2008年 开始发布一款 Amoeba for Mysql软件.这个软件致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的 时候充当SQL路由功能,专注于分布式数据库代理层(Database Proxy)开发.座落与 Client.DB Server(s)之间,对客户端透明.具有负载均衡.高可用性.SQL 过滤.读写分离.可路由相关的到目标数据库.可并发请求多台数据库合并结果. 通过Amoeba你能够完成多数据源的高

MySQL5.6 读写分离

一:读写分离架构图 二:安装配置MySQL-Proxy 三:测试读写分离 四:添加MySQL-Proxy 为系统服务 1.1读写分离架构图 1.Slave-1不接收写,也不接收读 2.Slave-1有中继日志,也有二进制日志,因为它需要接收Slave-1发送过来的数据,又要把数据发送给其它从服务器,但是它不需要存储数据. 3.因为Slave-1不需要存储数据,所以使用black hole存储引擎 2.1下载MySQL-Proxy http://dev.mysql.com/downloads/my

Yii2实现读写分离(MySQL主从数据库)

读写分离(Read/Write Splitting). 1.原理: 让主数据库(master)处理事务性增.改.删操作(INSERT.UPDATE.DELETE),而从数据库(slave)处理SELECT查询操作. 2.优点: 备份数据库,分担数据库压力,承受更大的访问量. yii实现读写分离非常简单,只需要在配置文件中写几个配置参数即可实现. 2.1.配置db.php文件 2.2.创建两个数据库为了演示ip都指向本地的MySQL数据库,但是数据库名称不同,同时在数据库分别插入一条数据,将sla

002-使用Spring实现读写分离(MySQL实现主从复制)

一. 背景 一般应用对数据库而言都是“读多写少”,也就说对数据库读取数据的压力比较大主库,负责写入数据,我们称之为:写库:从库,负责读取数据,我们称之为:读库: 1. 读库和写库的数据一致:2. 写数据必须写到写库:3. 读数据必须到读库: 二. 方案 解决读写分离的方案有两种:应用层解决和中间件解决. 2.1.应用层解决 优点: 1. 多数据源切换方便,由程序自动完成:2. 不需要引入中间件:3. 理论上支持任何数据库:缺点:1. 由程序员完成,运维参与不到:2. 不能做到动态增加数据源: 2