zoukankan      html  css  js  c++  java
  • MySQL主从复制(Master-Slave)与读写分离(MySQL-Proxy)实践

    转载自: http://heylinux.com/archives/1004.html

    MySQL作为目前世界上使用最广泛的免费数据库,相信所有从事系统运维的工程师都一定接触过。但在实际的生产环境中,由单台Mysql作为独立的数据库是完全不能满足实际需求的,无论是在安全性,高可用性以及高并发等各个方面。

    因此,一般来说都是通过 主从复制(Master-Slave)的方式来同步数据,再通过读写分离(MySQL-Proxy)来提升数据库的并发负载能力 这样的方案来进行部署与实施的。但是他们有主从之分,数据写操作都发生在主服务器上,由主服务器将数据复制到集群其他从服务器;数据读操作及数据分析等离线操作在从服务器上进行。

    如下图所示:

    下面是我在实际工作过程中所整理的笔记,在此分享出来,以供大家参考。

    一、MySQL的安装与配置
    具体的安装过程,建议参考我的这一篇文章:http://heylinux.com/archives/993.html
    值得一提的是,我的安装过程都是源码包编译安装的,并且所有的配置与数据等都统一规划到了/opt/mysql目录中,因此在一台服务器上安装完成以后,可以将整个mysql目录打包,然后传到其它服务器上解包,便可立即使用。

    二、MySQL主从复制
    场景描述:
    主数据库服务器:192.168.10.130,MySQL已经安装,并且无应用数据。
    从数据库服务器:192.168.10.131,MySQL已经安装,并且无应用数据。

    2.1 主服务器上进行的操作
    启动mysql服务
    /opt/mysql/init.d/mysql start

    通过命令行登录管理MySQL服务器
    /opt/mysql/bin/mysql -uroot -p'new-password'

    授权给从数据库服务器192.168.10.131
    mysql> GRANT REPLICATION SLAVE ON *.* to 'rep1'@'192.168.10.131' identified by ‘password’;

    查询主数据库状态
    Mysql> show master status;
    +------------------+----------+--------------+------------------+
    | File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
    +------------------+----------+--------------+------------------+
    | mysql-bin.000005 | 261 | | |
    +------------------+----------+--------------+------------------+

    记录下 FILE 及 Position 的值,在后面进行从服务器操作的时候需要用到。

    2.2 配置从服务器
    修改从服务器的配置文件/opt/mysql/etc/my.cnf
    将 server-id = 1修改为 server-id = 10,并确保这个ID没有被别的MySQL服务所使用。

    启动mysql服务
    /opt/mysql/init.d/mysql start

    通过命令行登录管理MySQL服务器
    /opt/mysql/bin/mysql -uroot -p'new-password'

    执行同步SQL语句
    mysql> change master to
    master_host=’192.168.10.130’,
    master_user=’rep1’,
    master_password=’password’,
    master_log_file=’mysql-bin.000005’,
    master_log_pos=261;

    正确执行后启动Slave同步进程
    mysql> start slave;

    主从同步检查
    mysql> show slave statusG
    ==============================================
    **************** 1. row *******************
    Slave_IO_State:
    Master_Host: 192.168.10.130
    Master_User: rep1
    Master_Port: 3306
    Connect_Retry: 60
    Master_Log_File: mysql-bin.000005
    Read_Master_Log_Pos: 415
    Relay_Log_File: localhost-relay-bin.000008
    Relay_Log_Pos: 561
    Relay_Master_Log_File: mysql-bin.000005
    Slave_IO_Running: YES
    Slave_SQL_Running: YES
    Replicate_Do_DB:
    ……………省略若干……………
    Master_Server_Id: 1
    1 row in set (0.01 sec)
    ==============================================

    其中Slave_IO_Running 与 Slave_SQL_Running 的值都必须为YES,才表明状态正常。

    如果主服务器已经存在应用数据,则在进行主从复制时,需要做以下处理:
    (1)主数据库进行锁表操作,不让数据再进行写入动作
    mysql> FLUSH TABLES WITH READ LOCK;

    (2)查看主数据库状态
    mysql> show master status;

    (3)记录下 FILE 及 Position 的值。
    将主服务器的数据文件(整个/opt/mysql/data目录)复制到从服务器,建议通过tar归档压缩后再传到从服务器解压。

    (4)取消主数据库锁定
    mysql> UNLOCK TABLES;

    2.3 验证主从复制效果

    主服务器上的操作
    在主服务器上创建数据库first_db
    mysql> create database first_db;
    Query Ok, 1 row affected (0.01 sec)

    在主服务器上创建表first_tb
    mysql> create table first_tb(id int(3),name char(10));
    Query Ok, 1 row affected (0.00 sec)

    在主服务器上的表first_tb中插入记录
    mysql> insert into first_tb values (001,’myself’);
    Query Ok, 1 row affected (0.00 sec)

    在从服务器上查看
    mysql> show databases;
    =============================
    +--------------------+
    | Database |
    +--------------------+
    | information_schema |
    | first_db |
    | mysql |
    | performance_schema |
    | test |
    +--------------------+
    5 rows in set (0.01 sec)
    =============================
    数据库first_db已经自动生成

    mysql> use first_db
    Database chaged

    mysql> show tables;
    =============================
    +--------------------+
    | Tables_in_first_db |
    +--------------------+
    | first_tb |
    +--------------------+
    1 row in set (0.02 sec)
    =============================
    数据库表first_tb也已经自动创建

    mysql> select * from first_tb;
    =============================
    +------+------+
    | id | name |
    +------+------+
    | 1 | myself |
    +------+------+
    1 rows in set (0.00 sec)
    =============================
    记录也已经存在

    由此,整个MySQL主从复制的过程就完成了,接下来,我们进行MySQL读写分离的安装与配置。

    三、MySQL读写分离
    场景描述:
    数据库Master主服务器:192.168.10.130
    数据库Slave从服务器:192.168.10.131
    MySQL-Proxy调度服务器:192.168.10.132

    以下操作,均是在192.168.10.132即MySQL-Proxy调度服务器 上进行的。

    3.1 MySQL的安装与配置
    具体的安装过程与上文相同。

    3.2 检查系统所需软件包
    通过 rpm -qa | grep name 的方式验证以下软件包是否已全部安装。
    gcc* gcc-c++* autoconf* automake* zlib* libxml* ncurses-devel* libmcrypt* libtool* flex* pkgconfig*
    libevent* glib*

    若缺少相关的软件包,可通过yum -y install方式在线安装,或直接从系统安装光盘中找到并通过rpm -ivh方式安装。

    3.3 编译安装lua
    MySQL-Proxy的读写分离主要是通过rw-splitting.lua脚本实现的,因此需要安装lua。

    lua可通过以下方式获得
    从http://www.lua.org/download.html下载源码包

    从rpm.pbone.net搜索相关的rpm包
    download.fedora.redhat.com/pub/fedora/epel/5/i386/lua-5.1.4-4.el5.i386.rpm
    download.fedora.redhat.com/pub/fedora/epel/5/x86_64/lua-5.1.4-4.el5.x86_64.rpm

    这里我们建议采用源码包进行安装
    cd /opt/install
    wget http://www.lua.org/ftp/lua-5.1.4.tar.gz
    tar zvfx lua-5.1.4.tar.gz
    cd lua-5.1.4

    vi src/Makefile
    在 CFLAGS= -O2 -Wall $(MYCFLAGS) 这一行记录里加上-fPIC,更改为 CFLAGS= -O2 -Wall -fPIC $(MYCFLAGS) 来避免编译过程中出现错误。

    make linux
    make install

    cp etc/lua.pc /usr/lib/pkgconfig/
    export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib/pkgconfig

    3.4 安装配置MySQL-Proxy
    MySQL-Proxy可通过以下网址获得:
    http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/

    推荐采用已经编译好的二进制版本,因为采用源码包进行编译时,最新版的MySQL-Proxy对automake,glib以及libevent的版本都有很高的要求,而这些软件包都是系统的基础套件,不建议强行进行更新。
    并且这些已经编译好的二进制版本在解压后都在统一的目录内,因此建议选择以下版本:
    32位RHEL5平台:
    http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz
    64位RHEL5平台:
    http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1-linux-rhel5-x86-64bit.tar.gz

    测试平台为RHEL5 32位,因此选择32位的软件包
    wget http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz

    tar xzvf mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz
    mv mysql-proxy-0.8.1-linux-rhel5-x86-32bit /opt/mysql-proxy

    创建mysql-proxy服务管理脚本
    mkdir /opt/mysql-proxy/init.d/

    vim mysql-proxy

    01 #!/bin/sh
    02 #
    03 # mysql-proxy This script starts and stops the mysql-proxy daemon
    04 #
    05 # chkconfig: - 78 30
    06 # processname: mysql-proxy
    07 # description: mysql-proxy is a proxy daemon to mysql
    08  
    09 # Source function library.
    10 . /etc/rc.d/init.d/functions
    11  
    12 #PROXY_PATH=/usr/local/bin
    13 PROXY_PATH=/opt/mysql-proxy/bin
    14  
    15 prog="mysql-proxy"
    16  
    17 # Source networking configuration.
    18 . /etc/sysconfig/network
    19  
    20 # Check that networking is up.
    21 [ ${NETWORKING} = "no" ] && exit 0
    22  
    23 # Set default mysql-proxy configuration.
    24 #PROXY_OPTIONS="--daemon"
    25 PROXY_OPTIONS="--admin-username=root --admin-password=password --proxy-read-only-backend-addresses=192.168.10.131:3306 --proxy-backend-addresses=192.168.10.130:3306  --admin-lua-script=/opt/mysql-proxy/lib/mysql-proxy/lua/admin.lua --proxy-lua-script=/opt/mysql-proxy/scripts/rw-splitting.lua"
    26 PROXY_PID=/opt/mysql-proxy/run/mysql-proxy.pid
    27  
    28 # Source mysql-proxy configuration.
    29 if [ -f /etc/sysconfig/mysql-proxy ]; then
    30         . /etc/sysconfig/mysql-proxy
    31 fi
    32  
    33 PATH=$PATH:/usr/bin:/usr/local/bin:$PROXY_PATH
    34  
    35 # By default it's all good
    36 RETVAL=0
    37  
    38 # See how we were called.
    39 case "$1" in
    40   start)
    41         # Start daemon.
    42         echo -n $"Starting $prog: "
    43         $NICELEVEL $PROXY_PATH/mysql-proxy $PROXY_OPTIONS --daemon --pid-file=$PROXY_PID --user=mysql --log-level=warning --log-file=/opt/mysql-proxy/log/mysql-proxy.log
    44         RETVAL=$?
    45         echo
    46         if [ $RETVAL = 0 ]; then
    47                 touch /var/lock/subsys/mysql-proxy
    48         fi
    49        ;;
    50   stop)
    51         # Stop daemons.
    52         echo -n $"Stopping $prog: "
    53         killproc $prog
    54         RETVAL=$?
    55         echo
    56         if [ $RETVAL = 0 ]; then
    57                 rm -f /var/lock/subsys/mysql-proxy
    58                 rm -f $PROXY_PID
    59         fi
    60        ;;
    61   restart)
    62         $0 stop
    63         sleep 3
    64         $0 start
    65        ;;
    66   condrestart)
    67        [ -e /var/lock/subsys/mysql-proxy ] && $0 restart
    68       ;;
    69   status)
    70         status mysql-proxy
    71         RETVAL=$?
    72        ;;
    73   *)
    74         echo "Usage: $0 {start|stop|restart|status|condrestart}"
    75         RETVAL=1
    76        ;;
    77 esac
    78  
    79 exit $RETVAL

    脚本参数详解:
    ==============================================
    PROXY_PATH=/opt/mysql-proxy/bin //定义mysql-proxy服务二进制文件路径

    PROXY_OPTIONS="--admin-username=root //定义内部管理服务器账号
    --admin-password=password //定义内部管理服务器密码
    --proxy-read-only-backend-addresses=192.168.10.131:3306 //定义后端只读从服务器地址
    --proxy-backend-addresses=192.168.10.130:3306 //定义后端主服务器地址
    --admin-lua-script=/opt/mysql-proxy/lib/mysql-proxy/lua/admin.lua //定义lua管理脚本路径
    --proxy-lua-script=/opt/mysql-proxy/scripts/rw-splitting.lua" //定义lua读写分离脚本路径

    PROXY_PID=/opt/mysql-proxy/run/mysql-proxy.pid //定义mysql-proxy PID文件路径

    $NICELEVEL $PROXY_PATH/mysql-proxy $PROXY_OPTIONS
    --daemon //定义以守护进程模式启动
    --keepalive //使进程在异常关闭后能够自动恢复
    --pid-file=$PROXY_PID //定义mysql-proxy PID文件路径
    --user=mysql //以mysql用户身份启动服务
    --log-level=warning //定义log日志级别,由高到低分别有(error|warning|info|message|debug)
    --log-file=/opt/mysql-proxy/log/mysql-proxy.log //定义log日志文件路径
    ==============================================

    cp mysql-proxy /opt/mysql-proxy/init.d/
    chmod +x /opt/mysql-proxy/init.d/mysql-proxy

    mkdir /opt/mysql-proxy/run
    mkdir /opt/mysql-proxy/log

    mkdir /opt/mysql-proxy/scripts

    配置并使用rw-splitting.lua读写分离脚本
    最新的脚本我们可以从最新的mysql-proxy源码包中获取
    cd /opt/install

    wget http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1.tar.gz

    tar xzvf mysql-proxy-0.8.1.tar.gz
    cd mysql-proxy-0.8.1
    cp lib/rw-splitting.lua /opt/mysql-proxy/scripts

    修改读写分离脚本rw-splitting.lua
    修改默认连接,进行快速测试,不修改的话要达到连接数为4时才启用读写分离
    vim /opt/mysql-proxy/scripts/rw-splitting.lua
    =============================
    -- connection pool
    if not proxy.global.config.rwsplit then
    proxy.global.config.rwsplit = {
    min_idle_connections = 1, //默认为4
    max_idle_connections = 1, //默认为8
    is_debug = false
    }
    end
    =============================

    修改完成后,启动mysql-proxy
    /opt/mysql-proxy/init.d/mysql-proxy start

    3.5 测试读写分离效果
    创建用于读写分离的数据库连接用户
    登陆主数据库服务器192.168.10.130,通过命令行登录管理MySQL服务器
    /opt/mysql/bin/mysql -uroot -p'new-password'
    mysql> GRANT ALL ON *.* TO 'proxy1'@'192.168.10.132' IDENTIFIED BY 'password';
    由于我们配置了主从复制功能,因此从数据库服务器192.168.10.131上已经同步了此操作。

    为了清晰的看到读写分离的效果,需要暂时关闭MySQL主从复制功能
    登陆从数据库服务器192.168.10.131,通过命令行登录管理MySQL服务器
    /opt/mysql/bin/mysql -uroot -p'new-password'

    关闭Slave同步进程
    mysql> stop slave;
    Query OK, 0 rows affected (0.00 sec)

    连接MySQL-Proxy
    /opt/mysql/bin/mysql -uproxy1 -p'password' -P4040 -h192.168.10.132

    登陆成功后,在first_db数据的first_tb表中插入两条记录
    mysql> use first_db;
    Database changed
    mysql> insert into first_tb values (007,’first’);
    Query Ok, 1 row affected (0.00 sec)
    mysql> insert into first_tb values (110,’second’);
    Query Ok, 1 row affected (0.00 sec)

    查询记录
    mysql> select * from first_tb;
    =============================
    +------+------+
    | id | name |
    +------+------+
    | 1 | myself |
    +------+------+
    1 rows in set (0.00 sec)
    =============================
    通过读操作并没有看到新记录

    mysql> quit
    退出MySQL-Proxy

    下面,分别登陆到主从数据库服务器,对比记录信息
    首先,检查主数据库服务器
    mysql> select * from first_tb;
    =============================
    +------+------+
    | id | name |
    +------+------+
    | 1 | myself |
    +------+------+
    | 007 | first |
    +------+------+
    | 110 | second |
    +------+------+
    3 rows in set (0.00 sec)
    =============================
    两条新记录都已经存在

    然后,检查从数据库服务器
    mysql> select * from first_tb;
    =============================
    +------+------+
    | id | name |
    +------+------+
    | 1 | myself |
    +------+------+
    1 rows in set (0.00 sec)
    =============================
    没有新记录存在

    由此验证,我们已经实现了MySQL读写分离,目前所有的写操作都全部在Master主服务器上,用来避免数据的不同步;
    另外,所有的读操作都分摊给了其它各个Slave从服务器上,用来分担数据库压力。

    经验分享:
    1.当MySQL主从复制在 show slave statusG 时出现Slave_IO_Running或Slave_SQL_Running 的值不为YES时,需要首先通过 stop slave 来停止从服务器,然后再执行一次本文 2.1与2.2 章节中的步骤即可恢复,但如果想尽可能的同步更多的数据,可以在Slave上将master_log_pos节点的值在之前同步失效的值的基础上增大一些,然后反复测试,直到同步OK。因为MySQL主从复制的原理其实就是从服务器读取主服务器的binlog,然后根据binlog的记录来更新数据库。

    2.MySQL-Proxy的rw-splitting.lua脚本在网上有很多版本,但是最准确无误的版本仍然是源码包中所附带的lib/rw-splitting.lua脚本,如果有lua脚本编程基础的话,可以在这个脚本的基础上再进行优化;

    3.MySQL-Proxy实际上非常不稳定,在高并发或有错误连接的情况下,进程很容易自动关闭,因此打开--keepalive参数让进程自动恢复是个比较好的办法,但还是不能从根本上解决问题,因此通常最稳妥的做法是在每个从服务器上安装一个MySQL-Proxy供自身使用,虽然比较低效但却能保证稳定性;

    4.一主多从的架构并不是最好的架构,通常比较优的做法是通过程序代码和中间件等方面,来规划,比如设置对表数据的自增id值差异增长等方式来实现两个或多个主服务器,但一定要注意保证好这些主服务器数据的完整性,否则效果会比多个一主多从的架构还要差;

    5.MySQL-Cluster 的稳定性也不是太好;

    6.Amoeba for MySQL 是一款优秀的中间件软件,同样可以实现读写分离,负载均衡等功能,并且稳定性要大大超过MySQL-Proxy,建议大家用来替代MySQL-Proxy,甚至MySQL-Cluster。

    补充: 

    1.彻底解除主从复制关系
    1). stop slave;
    2). reset slave; 或直接删除master.info和relay-log.info这两个文件;
    3). 修改my.cnf删除主从相关配置参数。

    2.让slave不随MySQL自动启动
    修改my.cnf 在[mysqld]中增加 skip-slave-start 选项。

    做了MySQL主从复制以后,使用mysqldump对数据备份时,一定要注意按照如下方式:
    mysqldump --master-data --single-transaction --user=username --password=password dbname> dumpfilename
    这样就可以保留 file 和 position 的信息,在新搭建一个slave的时候,还原完数据库, file 和 position 的信息也随之更新,接着再start slave 就可以很迅速的完成增量同步!

    需要限定同步哪些数据库,有3个思路:
    1.在执行grant授权的时候就限定数据库;
    2.在主服务器上限定binlog_do_db = 数据库名;
    3.主服务器上不限定数据库,在从服务器上限定replicate-do-db = 数据库名;

    如果想实现 主-从(主)-从 这样的链条式结构,需要设置:
    log-slave-updates #只有加上它,从前一台机器上同步过来的数据才能同步到下一台机器。
    当然,二进制日志也是必须开启的:
    log-bin=/opt/mysql/binlogs/bin-log
    log-bin-index=/opt/mysql/binlogs/bin-log.index

    还可以设置一个log保存周期:
    expire_logs_days=14

  • 相关阅读:
    svn command line tag
    MDbg.exe(.NET Framework 命令行调试程序)
    Microsoft Web Deployment Tool
    sql server CI
    VS 2010 One Click Deployment Issue “Application Validation did not succeed. Unable to continue”
    mshtml
    大厂程序员站错队被架空,只拿着五折工资!苟活和离职,如何选择?
    揭秘!Windows 为什么会蓝屏?微软程序员竟说是这个原因...
    喂!千万别忘了这个C语言知识!(~0 == -1 问题)
    Linux 比 Windows 更好,谁反对?我有13个赞成理由
  • 原文地址:https://www.cnblogs.com/Evil-Rebe/p/5867322.html
Copyright © 2011-2022 走看看