Mysql Proxy 简介


 MySQL Proxy是一个处于你的client端和MySQL server端之间的简单程序,它可以监测、分析、或改变它们的通信。它使用灵活,没有限制,常见的用途包括:负载平衡,故障、查询分析,查询过滤或修改等等。

 MySQL Proxy就是这么一个中间层代理,简单的说,MySQL Proxy就是一个连接池,负责前台应用的连接请求转发给后台的数据库,并且通过使用lua脚本,可以实现复杂的连接控制和过滤,从而实现读写分离和负载平衡。对于应用来说,MySQL Proxy是完全透明的,应用则只需要连接到MySQL Proxy的监听端口即可。当然,这样proxy机器可能成为单点故障,但完全可以使用多个proxy机器做冗余,在应用服务器和连接池配置中配置多个proxy的连接参数即可。


 MySQL Proxy更强大的一项功能就是实现"读写分离",基本原理就是让主数据库处理事务性查询,让从服务器进行SELECT查询。数据库复制被用来把事务性查询导致的变更同步到集群的从库中。



MySQL Proxy安装方式


 一、源码安装

  1、源码安装时,MySQL proxy的依赖关系:

     libevent 1.x or higher

     lua 5.1x or higher

     glib2 2.6.0 or higher

     pkg-config.

     libtool 1.5 or higher

     MySQL 5.0.x or higher developer files

     

    2、安装

     # tar xf mysql-proxy-0.8.2.tar.gz

     # cd mysql-proxy-0.8.2

     # ./configure

     # make

     # make check

     如果管理员有密码,上面的步骤则需要使用如下格式进行:

     #MYSQL_PASSWORD=root_pwd make check

     

     # make install

     默认情况下,mysql-proxy安装在/usr/local/sbin/mysql-proxy,而Lua示例脚本安装在/usr/local/share目录中


  二 、通用二进制格式安装

   

     1、下载,当前系统架构为 Centos6.5 64位系统

http://mirrors.sohu.com/mysql/MySQL-Proxy/mysql-proxy-0.8.4-linux-el6-x86-64bit.tar.gz    

     2、解压

      #tar  xf mysql-proxy-0.8.4-linux-e16-x86-64bit.tar.gz

      #mv mysql-proxy-0.8.4-linux-e16-x86-64bit /usr/local/mysql-proxy

     3、添加代理用户

      # useradd mysql-proxy

     4、为mysql-proxy提供SysV服务脚本

     

     5、为mysql-proxy脚本提供配置文件




MySQL Proxy实现读写分离


    环境搭建

        wKioL1NzYoHhEAEjAAEOHQfKrzE087.jpg

       

 如上图所示

 

MySQL Master 主服务器172.16.13.13MariaDB-5.5.36
MySQL Slave  从服务器172.16.13.14MariaDB-5.5.36
MySQL  Proxy 代理服务器172.16.13.2mysql-proxy-0.8.4-linux-el6-x86-64bit.tar.gz

     


一、MySQL主从复制架构的实现


    关于MySQL主从复制的实现详情请参考我的博客:

   http://jungege.blog.51cto.com/4102814/1396276



二、MySQL Proxy服务器配置


   1、下载所需要的版本,这里的系统平台为CentOS6.5 64系统

   

#wget http://mirrors.sohu.com/mysql/MySQL-Proxy/mysql-proxy-0.8.4-linux-el6-x86-64bit.tar.gz
# tar xf mysql-proxy-0.8.4-linux-el6-x86-64bit.tar.gz
# mv mysql-proxy-0.8.4-linux-el6-x86-64bit /usr/local/mysql-proxy


   2、添加代理用户

   

# useradd mysql-proxy


   3、为mysql-proxy提供SysV服务脚本

   

# 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

   

#chmod +x /etc/rc.d/init.d/mysql-proxy  赋予执行权限
#chkconfig --add mysql-proxy           添加到系统服务列表中
#chkconfig mysql-proxy on          开机启动


   4、为mysql-proxy服务脚本提供配置文件

     #vim  /etc/sysconfig/mysql-proxy  内容如下

   

# Options for mysql-proxy
ADMIN_USER="admin"
ADMIN_PASSWORD="admin"
ADMIN_ADDRESS=""
ADMIN_LUA_SCRIPT="/usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua"
PROXY_ADDRESS=""
PROXY_USER="mysql-proxy"
PROXY_OPTIONS="--daemon --log-level=info --log-use-syslog"
PROXY_OPTIONS="--daemon --log-level=info --log-use-syslog --plugins=proxy --plugins=admin --proxy-backend-addresses=172.16.13.13:3306 --proxy-read-only-backend-addresses=172.16.13.14:3306 --proxy-lua-script=/usr/local/mysql-proxy/share/doc/mysql-proxy/rw-splitting.lua"
其中的proxy-backend-addresses选项和proxy-read-only-backend-addresses选项均可重复使用多次,以实现指定多个读写服务器或只读服务器。

   

      mysql-proxy的配置选项

      mysql-proxy的配置选项大致可分为帮助选项、管理选项、代理选项及应用程序选项几类,下面一起去介绍他们

     --help

     --help-admin

     --help-proxy

     --help-all ——以上四个选项均用于获取帮助信息;


     --proxy-address=host:port   ——代理服务监听的地址和端口

     --admin-address=host:port   ——管理模块监听的地址和端口

     --proxy-backend-address=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/confi_file_name ——默认使用的配置文件路径;其配置段使用[mysql-proxy]标识

     --proxy-skip-profiling ——禁用profile

     --pid-file=/path/to/pid_file_name  ——进程文件名


    5、复制一下内容建立admin.lua文件,将其保存至/user/local/mysql-proxy/share/doc/mysql-proxy

     

#vim  /usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua
内容如下
--[[ $%BEGINLICENSE%$
 Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as
 published by the Free Software Foundation; version 2 of the
 License.
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 02110-1301  USA
 $%ENDLICENSE%$ --]]
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

 

    6、测试

      6.1 管理功能测试

     #service mysql-proxy start

     #ss  -ntl

     管理端口:4041

     读写分离端口:3306

       

[root@www ~]# mysql -uadmin -padmin -h172.16.13.2 --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
Copyright (c) 2000, 2013, 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>


     

     6.2 读写分离测试

       

     

在MySQL 主服务器上授权一个用户
MariaDB [(none)]> grant all on *.* to 'root'@'172.16.13.2' identified by '123';


     6.2.1接下来我们在MySQL Proxy服务器(172.16.13.2)上测试

          ###########多次读写操作,这样效果才能明显如下所示:

   

[root@www mysql-proxy]# mysql -uroot -h172.16.13.2 -p123 --port=3306 -e "select user from mysql.user"
[root@www mysql-proxy]# mysql -uroot -h172.16.13.2 -p123 --port=3306 -e "select user from mysql.user"
[root@www mysql-proxy]# mysql -uroot -h172.16.13.2 -p123 --port=3306 -e "create database testdb"
注意:--port=3306不需要带,默认侦听的读写分离连接端口就是3306.
如果将mysql-proxy安装在了一台mysql服务器上,那么MySQL侦听的端口要改为其他端口,否则会冲突(直接在my.cnf配置文件改就行)

   

     6.2.2 多次读写操作后,我们去管理端口查看读写分离情况

   

[root@www ~]# mysql -uadmin -h172.16.13.2 -padmin --port=4041
mysql> select * from backends;
+-------------+-------------------+-------+------+------+-------------------+
| backend_ndx | address           | state | type | uuid | connected_clients |
+-------------+-------------------+-------+------+------+-------------------+
|           1 | 172.16.13.13:3306 | up    | rw   | NULL |                 0 |
|           2 | 172.16.13.14:3306 | up    | ro   | NULL |                 0 |
+-------------+-------------------+-------+------+------+-------------------+
2 rows in set (0.00 sec)


   基于mysql-proxy实现了MariaDB主从复制架构中读写分离!




  总结:整个实例中不难发现,如果架构为LAMP的架构,那么PHP程序代码直接与MySQL Proxy地址相连即可,MySQL Proxy会将读写代理至后端的MySQL主从复制架构中,MySQL主服务器负责读写,从服务器只负责读,从而实现读写分离架构,如果担心Mysql proxy单点故障,可以建立冗余,多建立几个

     



PS:水平有限,如有不妥请指出,MariaDB的MMM架构即将推出,敬请期待!!!