mysql主从、基于GTID复制、mysqlproxy读写分离

MySQL集群实战

实验环境:

  • rhel6.5 server2(主):172.25.70.2
  • rhel6.5 server3(从):172.25.70.3

  • rpm包:mysql5.7

一、环境设置

为server2和server3都安装mysql5.7的rpm包,并进行初始化设置,这里使用server2做演示

[root@server2 mysql5.7]# yum install mysql-community-client-5.7.17-1.el6.x86_64.rpm mysql-community-common-5.7.17-1.el6.x86_64.rpm mysql-community-libs-5.7.17-1.el6.x86_64.rpm mysql-community-libs-compat-5.7.17-1.el6.x86_64.rpm mysql-community-server-5.7.17-1.el6.x86_64.rpm -y
[root@server2 mysql5.7]# /etc/init.d/mysqld start  #开启服务

#初始化,这里两个主机用两种不同的方法分别演示:
[root@server2 ~]# grep password /var/log/mysqld.log   #首先查看系统默认的mysql密码是多少
[root@server2 ~]# mysql_secure_installatio    #自己设置密码,密码有安全性要求,必须大小写字母、特殊符号、数字都有
[root@server2 ~]# mysql -p    ##修改之后,登录成功
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 5.7.17 MySQL Community Server (GPL)

Copyright (c) 2000, 2016, 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,然后用SQL语句更改密码
[root@server3 mysql5.7]# grep password /var/log/mysqld.log
[root@server3 mysql5.7]# mysql -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.7.17

Copyright (c) 2000, 2016, 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> ALTER USER root@localhost identified by 'Lcl@0514';  ##更改密码
Query OK, 0 rows affected (0.17 sec)

mysql> flush privileges;    ##手动刷新
Query OK, 0 rows affected (0.10 sec)

二、MySQL主从复制

随着访问量的不断增加,单台MySQL数据库服务器压力不断增加,需要对MySQL进行优化和架构改造,如果MySQL优化不能明显改善压力,可以使用高可用、主从复制、读写分离、拆分库、拆分表等方法来进行优化。
MySQL主从复制的目的是实现数据库冗余备份,将master数据库数据定时间同步至slave库中,一旦master数据库宕机,可以将web应用数据库配置快速切换至slave数据库,确保Web应用具有较高的高可用率

这里写图片描述

MySQL主从复制集群至少需要2台数据库服务器,其中一台为master库,另外一台为slave库,MySQL主从数据同步是一个异步复制的过程,要实现复制首先需要在master开启bin-log日志功能,bin-log日志用于记录在master库中执行的增、删、修改、更新等操作的SQL语句,整个过程需要开启3个进程,分别是master开启I/O线程,slave开启I/O线程和SQL线程,具体主从同步原理详解如下:

  • salve上执行slave start,slave I/O线程会通过在master创建的授权用户连接上至master,并请求master从指定的文件和位置之后发送bin-log日志内容;
  • master接收来自slave I/O线程的请求后,master I/O线程根据slave发送的指定bin-log日志position点之后的内容,然后返回给slave的I/O线程;
  • 返回的信息除了bin-log日志内容外,还有master最新的bin-log文件名以及在bin-log中的下一个指定更新position点;
  • slave I/O线程接收到信息后,将接收到的日志内容一次添加到slave端的relay-log文件的最末端,并将读取到的master端的bin-log的文件名和position点记录到master.info文件中,以便在下一次读取的时候能告知master从相应的bin-log文件名以及最后一个position点开始发起请求;
  • slave SQL线程检测到relay-log中内容有更新,会立刻解析relay-log日志中的内容,将解析后的SQL语句在slave中执行,执行成功后slave库与master库数据保持一致。

1、master配置

在/etc/my.cnf配置文件[mysqld]段中加入如下代码,然后重启MySQL服务器

server-id=1
log-bin=mysql-bin

在master数据库服务器命令行中创建tongbu用户及密码并且设置权限,并查看bin-log文件及position点

grant replication slave on *.* to 'tongbu'@'%' identified by 'Lcl@0514';
show master status;

这里写图片描述
这里写图片描述

2、slave配置

在/etc/my.cnf配置文件[mysqld]段中加入代码server-id=2,然后重启MySQL服务器即可。master与slave之间的server-id不能相同,slave端不需要开启bin-log功能

3、slave指定master

slave指定master IP、用户名、密码、bin-log文件名及position,代码如下

mysql> CHANGE MASTER TO master_host = '172.25.70.2',master_user='tongbu',master_password='Lcl@0514',master_log_file='mysql-bin.000001',master_log_pos=154;
Query OK, 0 rows affected, 2 warnings (1.36 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> start slave;
Query OK, 0 rows affected (0.26 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event   ##slave连接到master的状态
                  Master_Host: 172.25.70.2    ##master主机
                  Master_User: tongbu   ##负责主从复制的用户
                  Master_Port: 3306  
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001   ##I/O线程当前正在读取的主服务器二进制日志文件的名称
          Read_Master_Log_Pos: 154    ##在当前的主服务器二进制日志中,I/O线程已读取的位置
               Relay_Log_File: server3-relay-bin.000002   ##salve的SQL线程当前正在读取和执行的中继日志文件名称
                Relay_Log_Pos: 320
        Relay_Master_Log_File: mysql-bin.000001   ##由SQL线程执行的包含多数近期事件的主服务器二进制日志文件的名称
             Slave_IO_Running: Yes    ##I/O线程是否启动成功并连接到master上
            Slave_SQL_Running: Yes  ##SQL线程是否被成功启动
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error:    ##slave的SQL线程读取日志参数的错误量和错误消息
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 154    ##来自主服务器的二进制日志的由SQL线程执行的上一个时间的位置
              Relay_Log_Space: 529  ##所有的原有中继日志结合起来的总大小
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0  ##表示主从之间的时间差,是数字的时候表示相差多少秒,null表示未知数,一般主从出现问题就会出现null
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 5c570315-9953-11e8-a680-525400757e9f
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.01 sec)

4、主从复制测试

在master端创建mysql_db_test数据库和t1表,命令如下

mysql> create database mysql_db_test charset=utf8;
Query OK, 1 row affected (0.25 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| mysql_db_test      |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.32 sec)

mysql> use mysql_db_test;
Database changed
mysql> create table t1 (id varchar(20),name varchar(20));
Query OK, 0 rows affected (1.53 sec)

mysql> show tables;
+-------------------------+
| Tables_in_mysql_db_test |
+-------------------------+
| t1                      |
+-------------------------+
1 row in set (0.00 sec)

在slave服务器查看那是否有mysql_db_test服务器和t1表,存在则表示slave复制master成功

这里写图片描述


在master服务器的t1表上插入两条数据,并在slave查看是否已经同步,master执行命令为

insert into t1 values ("1","alice");
insert into t1 values ("2","bob");
select * from t1;

这里写图片描述

slave端执行查询命令
这里写图片描述

5、主从同步排错思路

MySQL主从同步集群在生产环境使用时,如果主从服务器之间网络通信条件差或者数据库数据量非常大,容易导致MySQL主从同步延迟
MySQL主从同步延迟之后,一旦主库宕机,会导致部分数据没有即使同步至主库,重新启动主库,会导致从库与主库同步错误,快速恢复主从同步关系有两种方法:


(1) 忽略错误后,继续同步
此方法适用于主从库数据内容相差不大的情况。
master端执行命令flush tables with read lock;,将数据库设置为全局读锁,不允许写入新数据
slave端停止slave I/O线程和SQL线程,同时将同步错误的SQL跳过一次,跳过错误会导致数据不一致,启动start slave;,同步状态恢复,命令为:

stop slave;
set global sql_slave_skip_counter = 1;
start slave;

(2) 重新做主从同步,使数据完全同步
此方法适用于主从库数据内容相差很大的情况。
master执行flush tables with read lock;,将数据库设置全局读锁,不允许写入新数据。
master基于mysqldump、xtrabackup工具对数据库进行完整备份,也可用shell脚本或python脚本实现定时备份,备份成功后,将完整的数据导入到从库,重新配置主从关系,当slave的I/O线程、SQL线程均为Yes后,将master端的读锁解开即可,命令为unlock tables;

三、基于GTID的复制

1、GTID概念

GTID即全局事务ID(global transaction identifier),GTID实际上是由UUID+TID组成的。其中UUID是一个MySQL实例的唯一标识。TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增,所以GTID能够保证每个MySQL实例事务的执行(不会重复执行同一个事务,并且会补全没有执行的事务)。
可以在集群全局范围标识事务,用于取代过去通过binlog文件偏移量定位复制位置的传统方式。借助GTID,在发生主备切换的情况下,MySQL的其它Slave可以自动在新主上找到正确的复制位置,这大大简化了复杂复制拓扑下集群的维护,也减少了人为设置复制位置发生误操作的风险。另外,基于GTID的复制可以忽略已经执行过的事务,减少了数据发生不一致的风险。
原理:
从服务器连接到主服务器之后,把自己执行过的GTID(Executed_Gtid_Set) < SQL线程> 、获取到的GTID(Retrieved_Gtid_Set)< IO线程>发给主服务器,主服务器把从服务器缺少的GTID及对应的transactions发过去补全即可。当主服务器挂掉的时候,找出同步最成功的那台从服务器,直接把它提升为主即可。如果硬要指定某一台不是最新的从服务器提升为主, 先change到同步最成功的那台从服务器, 等把GTID全部补全了,就可以把它提升为主了。

2、配置

在master和server的my.cnf中添加:并重启服务
gtid_mode = ON
enforce-gtid-consistency=true 

然后在slave上重新指定master,重启服务
mysql> stop slave;
Query OK, 0 rows affected (0.05 sec)

mysql> change master to master_host='172.25.70.2',master_user='tongbu',master_password='Lcl@0514',master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.21 sec)

3、测试GTID主从复制

mysql> show slave status\G;
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 1

在master中插入一条数据,查看slave
mysql> insert into t1 values('3','eve');
Query OK, 1 row affected (0.09 sec)

slave:
mysql> select * from mysql_db_test.t1;
+------+-------+
| id   | name  |
+------+-------+
| 1    | alice |
| 2    | bob   |
| 3    | eve   |
+------+-------+
3 rows in set (0.00 sec)
mysql> show slave status\G;
           Retrieved_Gtid_Set: 5c570315-9953-11e8-a680-525400757e9f:1
            Executed_Gtid_Set: 5c570315-9953-11e8-a680-525400757e9f:1
                Auto_Position: 1

四、mysqlproxy实现读写分离

1、简介

mysql-proxy是mysql官方提供的mysql中间件服务,上游可接入若干个mysql-client,后端可连接若干个mysql-server。

它使用mysql协议,任何使用mysql-client的上游无需修改任何代码,即可迁移至mysql-proxy上。
根本上,mysql-proxy是一个官方提供的框架,具备良好的扩展性,可以用来完成:

  • sql拦截与修改
  • 性能分析与监控
  • 读写分离
  • 请求路由

这里只用来做读写分离

2、安装配置

tar zxf mysql-proxy-0.8.5-linux-el6-x86-64bit.tar.gz -C /usr/local/mysql-proxy
[root@mysqlproxy ~]# cd /usr/local/mysql-proxy/
[root@mysqlproxy mysql-proxy]# mkdir lua    #创建脚本存放目录
[root@mysqlproxy mysql-proxy]# mkdir logs   #创建日志目录
[root@mysqlproxy mysql-proxy]# cp share/doc/mysql-proxy/rw-splitting.lua ./lua/   #复制读写分离配置文件
[root@mysqlproxy mysql-proxy]# cp share/doc/mysql-proxy/admin-sql.lua ./lua/    ##复制管理脚本
[root@mysqlproxy mysql-proxy]# vim /etc/mysql-proxy.cnf #创建配置文件
[mysql-proxy]
user=root       #运行mysql-proxy用户
admin-username='admin'
admin-password='admin'
proxy-address=172.25.70.4     #mysql-proxy运行ip和端口,不加端口,默认4040
proxy-read-only-backend-addresses=172.25.70.3   #指定后端从slave读取数据
proxy-backend-addresses=172.25.70.2   #指定后端主master写入数据
proxy-lua-script=/usr/local/mysql-proxy/lua/rw-splitting.lua  #指定读写分离配置文件位置
admin-lua-script=/usr/local/mysql-proxy/lua/admin-sql.lua   #指定管理脚本
log-file=/usr/local/mysql-proxy/logs/mysql-proxy.log    #日志位置
log-level=info     #定义log日志级别,由高到低分别有(error|warning|info|message|debug)
daemon=true      #以守护进程方式运行
#keepalive=true      #mysql-proxy崩溃时,尝试重启
plugins=admin

chmod 660 /etc/mysql-porxy.cnf

vim /usr/local/mysql-proxy/lua/rw-splitting.lua
if not proxy.global.config.rwsplit then
 proxy.global.config.rwsplit = {
  min_idle_connections = 1, #默认超过4个连接数时,才开始读写分离,改为1
  max_idle_connections = 1, #默认8,改为1
  is_debug = false
 }
end

/usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/etc/mysql-proxy.cnf   ##启动mysql-proxy
##此时可以查看到3306和4041端口已经开放

关闭mysql-proxy使用:killall -9 mysql-proxy

在server2上,主服务器上

mysql> grant select,update,insert on *.* to proxy@'172.25.70.%' identified by 'Lcl@0514';
Query OK, 0 rows affected, 1 warning (0.31 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.13 sec)

##这个时候,主从服务器上都有proxy用户

读写分离测试可以参考这个链接:
测试

猜你喜欢

转载自blog.csdn.net/lcl_xiaowugui/article/details/81461554