设为首页 收藏本站
查看: 1166|回复: 0

[经验分享] mysql-poxy 实现mysql主从架构读写分离

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2015-5-4 08:36:41 | 显示全部楼层 |阅读模式
在高并发系统设计中,后端数据库的性能往往会成为系统的瓶颈,这时候就需要进行合理的设计,以分摊后端数据库的压力,比如在数据层前面构建缓存层、数据文件存放在RAID这样的设备、对数据进行分库分表分区存放、合理利用索引、进行数据的读写分离等。mysql-proxy提供了mysql数据库的读写分离能力,mysql-proxy通过Lua脚本能分析得出用户的sql请求,如果发现在是read请求,则会转化到master-slave模型的slave中,如果是write请求,则会转发到master中,以达到读写分离的目的,在一定程度上能大大增加系统的性能。下面来一步步通过mysql-proxy搭建mysql的读写分离。

一、环境准备
    os:centos6.4

    mysql-slave:version:5.6.13    ip:192.168.1.111

    mysql-master:version:5.6.13    ip:192.168.1.110

    mysql-proxy:version:0.85    ip:192.168.1.112


二、环境搭建
    1、mysql主从复制搭建

        mysql安装
        tips:mysql从5.6起,主从复制中采用了GTID,GTID为每个数据库事务编码一个number,并为

        每个server赋予一个global uuid,通过uuid和事务编号来进行数据的复制和恢复,这种方案更有利
        于在高可用的环境中数据的恢复。在5.6后,mysql主从架构中还支持多线程复制,即可以启动多个

        sql thread对relay log进行处理,默认的线程数建议为要同步的数据库的个数。


        由于是搭建5.6.13的mysql主从架构,因上安装好mysql后。在/etc/my.cnf中主要配置如下:
        master:

        [mysqld]
        port = 3306
        datadir = /data/mysql
        server_id = 1
        socket = /tmp/mysql.sock
        innodb_file_per_table = 1
        log-bin = master-bin
        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
        report-host=master.lee.com

            vim /etc/hosts添加一条条目

            192.168.1.110 master.lee.com master


        slave:

        [mysqld]
        datadir = /data/mysql    #存放数据目录
        port = 3306    #启动端口
        server_id = 100    #server_id
        socket = /tmp/mysql.sock
        innodb_file_per_table = 1    #每表一个表空间
        binlog-format=ROW   
        log-slave-updates=true
        gtid-mode=on     #启动gtid
        enforce-gtid-consistency=true
        master-info-repository=TABLE    #master记录bin-log的位置(myql.slave_master_info)
        relay-log-info-repository=TABLE    #slave记录relay-log的地方,默认为file
        sync-master-info=1    #启用后可确保无信息丢失
        slave-parallel-workers=2    #启动的sql thread线程数
        binlog-checksum=CRC32    #二进制校验算法crc32
        master-verify-checksum=1    #启用复制有关的校验功能
        slave-sql-verify-checksum=1    #启用复制有关的校验功能
        binlog-rows-query-log_events=1    #记录相关事件信息,降低排错复杂度
        report-port=3306    #通知给master的端口号
        log-bin=mysql-bin.log    #开启二进制日志功能,可以拥有自己的从服务器
        report-host=slave.lee.com    #通知给master的主机名

        在master中创建主从复制用户

        mysql> grant replication slave on *.* to 'repluser'@'192.168.1.%' identified by 'replpass';
        在slave中连接master:

        mysql> change master to master_host='192.168.1.110',master_user='repluser',master_password

        ='replpass',master_auto_position=1;

        启动myql slave

        mysql> start slave


    2、安装mysql-proxy

        tar xf mysql-proxy-0.8.5-linux-glibc2.3-x86-64bit.tar.gz -C /usr/local
        cd /usr/local

        ln -sv mysql-proxy-0.8.5-linux-glibc2.3-x86-64bit/ mysql-proxy
        创建mysql-proxy用户

        useradd -r -s /sbin/nologin mysql-proxy



      为mysql-proxy提供SysV脚本,将下面代码复制到/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

    # 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/init.d/mysql-proxy

        chkconfig --add mysql-proxy

        chkconfig mysql-proxy on



        为mysql-prox提供服务脚本

        vim /etc/sysconfig/mysql-proxy


       DMIN_USER="admin"    #管理员用户名
        ADMIN_PASSWORD="admin"    #管理员用户密码
        ADMIN_ADDRESS="192.168.1.112:4041"    #管理mysql-proxy监听的套接字
           #admin lua脚本

        ADMIN_LUA_SCRIPT="/usr/local/mysql-proxy/share/doc/mysql-proxy/admin.lua"
        PROXY_ADDRESS="192.168.1.112:3306"    #mysql-proxy监听的套接字
        PROXY_USER="mysql-proxy"    #启动mysql-proxy服务的用户
          #mysql-proxy启动的选项

        PROXY_OPTIONS="--daemon --log-level=debug --log-use-syslog --plugins=proxy --plugins=admin --proxy-backend-addresses=192.168.1.110:3306 --proxy-read-only-backend-addresses=192.168.1.111:3306 --proxy-lua-script=/usr/local/mysql-proxy/share/doc/mysql-proxy/rw-splitting.lua


        #--daemon:以守护进程方式启动

        #--log-level=debug,日志级别,此处为了调试而用

        #--log-use-syslog : 通过系统的syslog记录日志

        #--plugins:插件

        #--proxy-backend-addresses:后台读写数据库服务器(rw),可添加多个
        #--proxy-read-only-backend-addresses:后台只读数据库服务器(ro),可添加多个
        #--proxy-lua-script:mysql读写分离lua脚本


        复制下面代码,到/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

    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
   
     启动mysql-proxy

        service mysql-proxy start

        查看是否启动成功

        netstat -tlnp可查看到mysql-proxy监听在3306和4041(管理)端口上。



    3、读写分离测试

        在master中创建一个测试管理用户mproxyadmin

        mysql> grant all on *.* to 'mproxyadmin'@'192.168.1.112' identified by 'mproxypass';

        mysql> flush priviledges;
        选择从slave中登录mysql-proxy
        mysql -umproxyadmin -h192.168.1.112 -p;
        登录进去

        创建一个aa数据库

        mysql> create database aa;

        可以看到主从数据库都有已经创建了aa数据库。


        在slave中登录mysql-proxy所的admin管理后台

        mysql -uadmin -padmin -h192.168.1.112 --port=4041

        管理后台只有一条sql语句有用,查看backends的状态信息:

        mysql> select * from backends;

         wKioL1VGEjLwP-vpAAEQi9xOLGI394.jpg

        可看到此时的backends有两个,但状态为unknown.,且master为读写模式,slave为主从模式

        当在主中进行相关非查询操作时,master的state会变成up。当进行查询时,slave的状态也会变

        成up,当二者都激活后,mysql-proxy就能进行读写分离了。

         wKiom1VGE0LTIM9fAAEGtUTEl5w046.jpg

        由于mysql-proxy启动时日志级别设计为debug,所以在mysql-proxy所在机子可以轻易地看到日志

        信息,首先在slave上连接上mysq_proxy,在刚才创建的aa数据库中创建一张test表,

         wKiom1VGFtGz8M8-AABI45qny3c864.jpg
        这时在mysql-proxy中看到的日志是:

         wKiom1VGFyajEPSuAAEkZ_ADf7Y242.jpg
        由is_slave为false可知道,这个创表语句是在master中执行的。

        下面我们为这个表插入一条数据,然后再select出来

        mysql> insert into test values(1,"test");

        mysql> select * from test;

         wKiom1VGGATz0V4tAANJVWksvSk059.jpg
    这时发现select语句,is_slave为true,也就是查询是在slave中执行的。

    以后每执行查询操作都会在slave中执行,其它的操作都会在master中执行,这就实现了mysql的读写

    分离。




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-63326-1-1.html 上篇帖子: mysql 主从同步 下篇帖子: mysql+drbd+corosync实现高可用mysql version master 数据库 mysql write
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表