结构图

                                | ---> master(rw) (172.18.14.70:3306)
client ---> mysqlrouter ---->   |--->  slave1(rw) (172.18.14.71:3306)
                                | ---> salve2(ro) (172.18.14.72:3306)
                                | ---> slave3(ro) (172.18.14.73:3306)


我们通过 mysqlrouter 定义一个监听端口,把 master 和 slave1 定义到一组,做成高可用(rw),平时将客户端对该端口的写请求发给 master,当 master 故障时,把请求转给 slave1;再通过 mysqlrouter 定义一个监听端口,把 salve2 和 slave3 定义到一组,做成负载均衡(ro),装客户端对端口的读请求轮流发送给后端。

注意:MySQL Router 不管 MySQL 服务器的主从关系以及数据是否一致,他只起到数据转发作用。

安装

下载二进制包后解压即可。
mkdir -p /var/log/mysqlrouter/ # 创建日志目录
mkdir -p /etc/mysqlrouter # 创建配置文件目录

MySQL Router的配置

配置文件为 /etc/mysqlrouter/mysqlrouter.ini

[DEFAULT]
logging_folder = /var/log/mysqlrouter
[logger]
level = INFO

# 一个高可用的标签
[routing:failover]
bind_address = 0.0.0.0
bind_port = 7001
max_connections = 1024
mode = read-write
# mode 目前就支持两种: read-write 和 read-only,前者用于高可用,后者用于负载均衡
destinations = 172.18.14.70:3306, 172.18.14.71:3306
# 实际转发的地址,第一个socket无法连接了,才会连接到第二个socket

# 一个负载均衡的标签
[routing:balancing]
bind_address = 0.0.0.0
bind_port = 7002
max_connections = 1024
mode = read-only
destinations = 172.18.14.72:3306, 172.18.14.73:3306
# 这里的两个socket是轮询用的

MySQL Router的启动

官方二进制安装包中的启动脚本示例是 debian 系的,可在 MySQL 官网下载 RedHat 对应的 mysql-router 的 RPM 包,解压后,将其中的 /etc/init.d/mysqlrouter 抽取出来,修改相应文件路径即可。

也可以直接使用如下示例:

# cat /etc/init.d/mysqlrouter

#! /bin/bash
#
# mysqlrouter This shell script takes care of starting and stopping
# the MySQL Router
#
# chkconfig: 2345 66 34
# description: MySQL Router
# processname: mysqlrouter
# config: /etc/mysqlrouter/mysqlrouter.ini
# pidfile: /var/run/mysqlrouter/mysqlrouter.pid
#
# Copyright (c) 2015, 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
#
# Maintainer: MySQL Release Engineering <mysql-build@oss.oracle.com>
#

# Source function library
. /etc/rc.d/init.d/functions

# Source networking configuration
. /etc/sysconfig/network

# add general install path
base_dir=/usr/local/mysql-router

# fix exec path
exec=${base_dir}/bin/mysqlrouter
prog=mysqlrouter
piddir=${base_dir}/run/mysqlrouter
pidfile=${piddir}/mysqlrouter.pid
logdir=/var/log/mysqlrouter
logfile=$logdir/mysqlrouter.log
lockfile=/var/lock/subsys/$prog

# add conf path
conf=/etc/mysqlrouter/mysqlrouter.ini

start () {
    [ -d $piddir ] || mkdir -p $piddir
    chown mysql:mysql $piddir
    [ -d $logdir ] || mkdir -p $logdir
    chown mysql:mysql $logdir
    [ -e $logfile ] || touch $logfile
    chown mysql:mysql $logfile
    export ROUTER_PID=$pidfile
    # add opt -c to resolv mysqlrouter.ini
    daemon --user mysql $exec -c $conf >/dev/null 2>&1 &
    ret=$?
    if [ $ret -eq "0" ]; then
    action $"Starting $prog: " /bin/true
    touch /var/lock/subsys/$prog
    else
    action $"Starting $prog: " /bin/false
    fi
    return $ret
}

stop () {
    [ -f /var/lock/subsys/$prog ] || return 0
    killproc mysqlrouter >/dev/null 2>&1
    ret=$?
    if [ $ret -eq "0" ]; then
    rm -f $pidfile
    rm -f /var/lock/subsys/$prog
    action $"Stopping $prog: " /bin/true
    else
    ation $"Stopping $prog: " /bin/false
    fi
}

restart () {
    stop
    start
}

condrestart () {
    [ -e /var/lock/subsys/$prog ] && restart || return 0
}

case "$1" in
    start)
    start
    ;;
    stop)
    stop
    ;;
    status)
    status -p "$pidfile" $prog
    ;;
    restart)
    restart
    ;;
    condrestart|try-restart)
    condrestart
    ;;
    reload)
    exit 3
    ;;
    force-reload)
    restart
    ;;
    *)
    echo $"Usage: $0 {start|stop|status|condrestart|try-restart|reload|force-reload}"
    exit 2
esac

exit $?

启动mysqlrouter:

# /etc/init.d/mysqlrouter start

启动后,可以通过 netstat 命令和 mysqlrouter 日志文件观察 mysqlrouter 的监听 IP 和端口。

MySQL Router 的测试

现在,就可以通过连接 mysqlrouter 主机的 IP 和端口来进行 mysql 的连接测试了。
可以发现,如果连接的是读端口,则每次连接都是轮询的,如果连接的是写端口,则只连接的是 master。

  • 通过这种方式,其实就实现了读写分离,但是需要依靠业务端进行代码修改才能完成。读的指向7002(RO),写的指向7001(RW)。
  • 如果一个事物中既有读,又有写的时候,针对 MySQL Router 这个中间件来说,应该指向 7001(RW)。
  • 针对其他中间件如 mycat,DDB(网易)、TDDL(淘宝)来说,对外只暴露一个端口,对业务层是透明的,但是实现起来较重,因为这类中间件需要对SQL语句进行解析(CPU 开销较重)。且在一个事务中有读有写的情况下,最保险的做法还是应该发送给 Master 节点,避免数据不一致。
-- By 许望(RHCA、OCM、VCP)
最后修改:2020 年 02 月 18 日 09 : 27 PM
如果觉得我的文章对你有用,请随意赞赏