mysql主从

1 主从作用

  • 实时灾备,用于故障切换
  • 读写分离,提供查询服务
  • 备份,避免影响业务

1.1主从形式

  • 一主一从
  • 主主复制
  • 一主多从—扩展系统读取的性能,因为读是在从库读取的
  • 多主一从—5.7开始支持
  • 联级复制

2. 主从复制原理

主从复制步骤:

主库将所有的写操作记录到binlog日志中并生成一个log dump线程,将binlog日志传给从库的I/O线程
从库生成两个线程,一个I/O线程,一个SQL线程

  • I/O线程去请求主库的binlog,并将得到的binlog日志写到relay log(中继日志) 文件中
  • SQL线程,会读取relay log文件中的日志,并解析成具体操作,来实现主从的操作一致,达到最终数据一致的目的

3. 主从复制配置

主从复制配置步骤:

  • 确保从数据库与主数据库里的数据一样
  • 在主数据库里创建一个同步账号授权给从数据库使用
  • 配置主数据库(修改配置文件)
  • 配置从数据库(修改配置文件)

需求:
搭建两台MySQL服务器,一台作为主服务器,一台作为从服务器,主服务器进行写操作,从服务器进行读操作

环境说明:

数据库角色 IP 应用与系统版本 有无数据
主数据库(xxx) 196.168.125.129 centos7/redhat7
mysql-5.7
有数据
从数据库(xj) 192.168.125.128 centos7/redhat
mysql-5.7
无数据

3.1 mysql安装

查看mysql安装

3.2 mysql主从配置

3.2.1 确保从数据库与主数据库里的数据一样

为确保从数据库与主数据库里的数据一样,先全备主数据库并还原到从数据库中

  • 查看主库有哪些库
[[email protected] ~]# mysql -uroot -p123456 -e 'show databases;'
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| xiaojian           |
| zabbix             |
+--------------------+
  • 查看从库有哪些库
[[email protected] ~]# mysql -uroot -pxj123456 -e 'show databases;'
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+


全备主库

  • 全备主库时需要另开一个终端,给数据库加上读锁,避免在备份期间有其他人在写入导致数据不一致
mysql> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

锁表的终端必须在备份完成以后才能退出,退出既解锁
  • 备份主库并将备份文件传送到从库
[[email protected] ~]# mysqldump -uroot -p123456 --all-databases > /root/all.sql  --全备
mysqldump: [Warning] Using a password on the command line interface can be insecure.
[[email protected] ~]# scp all.sql [email protected]:/root
[email protected]'s password: 
all.sql                                                    100% 4994KB   4.9MB/s   00:00    
[[email protected] ~]# ls
all.sql  anaconda-ks.cfg
  • 解除主库的锁表状态,直接退出交互式界面即可
mysql> quit
Bye
  • 在从库上恢复主库的备份并查看从库,确保与主库一致
[[email protected] ~]# mysql -uroot -pxj123456 < all.sql 
mysql: [Warning] Using a password on the command line interface can be insecure.
[[email protected] ~]# mysql -uroot -pxj123456 -e 'show databases;'
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| xiaojian           |
| zabbix             |
+--------------------+
与主库的数据一样

3.2.2 在主数据库里创建一个同步账号授权给从数据库使用

mysql> grant replication slave on *.* to 'xj'@'192.168.125.128' identified by 'xj123456';
Query OK, 0 rows affected, 1 warning (14.02 sec) 

mysql> flush privileges; --刷新权限
Query OK, 0 rows affected (0.00 sec)

3.2.3 配置主数据库

[[email protected] ~]#  vim /etc/my.cnf
//在[mysqld]这段的后面加上如下内容
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-bin=mysql-bin   //启用binlog日志
server-id=3    //数据库服务器唯一标识符,主库的server-id值必须比从库的小

symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid 

The server quit without updating PID file

  • 重启mysql服务
[[email protected] ~]# service mysqld stop
[[email protected] ~]# service mysqld start
Starting MySQL. SUCCESS! 
[[email protected] ~]# 
[[email protected] ~]# ss -anlt
State       Recv-Q Send-Q              Local Address:Port                Peer Address:Port 
LISTEN      0      128                     127.0.0.1:9000                           *:*     
LISTEN      0      5                               *:873                            *:*     
LISTEN      0      128                             *:22                             *:*     
LISTEN      0      5                              :::873                           :::*     
LISTEN      0      80                             :::3306                          :::*     
LISTEN      0      128                            :::80                            :::*     
LISTEN      0      128                            :::22                            :::*     
  • 查看主库的状态
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000004 |     1610 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

3.2.4 配置从数据库

[[email protected] ~]# vim /etc/my.cnf
添加如下内容
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
server-id=2     //设置从库的唯一标识符,从库的server-id值必须大于主库的该值
relay-log=mysql-relay-bin       //启用中继日志relay-log

symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
  • 重启从库的mysql服务
[[email protected] ~]# service mysqld restart
Starting MySQL. SUCCESS! 
[[email protected] ~]# ss -anlt
State       Recv-Q Send-Q              Local Address:Port                Peer Address:Port 
LISTEN      0      100                     127.0.0.1:25                             *:*     
LISTEN      0      128                             *:22                             *:*     
LISTEN      0      100                           ::1:25                            :::*     
LISTEN      0      80                             :::3306                          :::*     
LISTEN      0      128                            :::22                            :::*     
  • 配置并启动主从复制
mysql> change master to
    -> master_host='192.168.125.129',  --主库ip
    -> master_usr='xj',  --同步账号
    -> master_password='xj123456',  --同步密码
    -> master_log_file='mysql-bin.000004',  --主库的binlog日志文件名
    -> master_log_pos=1610;   --binlog日志最后的pos值
Query OK, 0 rows affected (0.00 sec)

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

查看从服务器状态

mysql> show slave status \G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.125.129
                  Master_User: xj
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000005
          Read_Master_Log_Pos: 5250
               Relay_Log_File: mysql-relay-bin.000006
                Relay_Log_Pos: 5463
        Relay_Master_Log_File: mysql-bin.000005
             Slave_IO_Running: Yes  --必须为yes
            Slave_SQL_Running: Yes  --必须为yes
              Replicate_Do_DB: 

3.2.5 测试验证

在主服务器的student库的bj2表中插入数据:

mysql> use xiaojian;

Database changed
mysql> select * from xj;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | tom       |   20 |
|  2 | jerry     |   23 |
|  3 | wangqing  |   25 |
|  4 | sean      |   28 |
|  5 | zhangshan |   18 |
|  6 | zhangshan |   20 |
|  7 | xxx       |   21 |
|  8 | jjj       |   22 |
|  9 | hhhh      |   44 |
+----+-----------+------+
9 rows in set (0.00 sec)

mysql> insert into xj values(1,'zz',45);
Query OK, 1 row affected (0.00 sec)
mysql> select * from xj;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | tom       |   20 |
|  2 | jerry     |   23 |
|  3 | wangqing  |   25 |
|  4 | sean      |   28 |
|  5 | zhangshan |   18 |
|  6 | zhangshan |   20 |
|  7 | xxx       |   21 |
|  8 | jjj       |   22 |
|  9 | hhhh      |   44 |
|  1 | zz        |   45 |
+----+-----------+------+
10 rows in set (0.00 sec)

mysql> 

在从数据库中查看数据是否同步:

mysql> use xiaojian;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from xj;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | tom       |   20 |
|  2 | jerry     |   23 |
|  3 | wangqing  |   25 |
|  4 | sean      |   28 |
|  5 | zhangshan |   18 |
|  6 | zhangshan |   20 |
|  7 | xxx       |   21 |
|  8 | jjj       |   22 |
|  9 | hhhh      |   44 |
|  1 | zz        |   45 |
+----+-----------+------+
10 rows in set (0.00 sec)

zabbix监控主从


[[email protected] ~]# vim /usr/local/etc/zabbix_agentd.conf
...
UserParameter=cong_mysqld,/scripts/cong.sh
[[email protected] ~]# mkdir /scripts
[[email protected] ~]# vim /scripts/cong.sh 
[[email protected] ~]# cat /scripts/cong.sh  --监控从库的两个线程是否正常
#!/bin/bash
a=$(mysql  -e "show slave status \G" 2>/dev/null|egrep Slave_SQL_Running:|awk -F: '{print $2}')
b=$(mysql  -e "show slave status \G" 2>/dev/null|egrep Slave_IO_Running:|awk -F: '{print $2}')
if [ $a == Yes -a $b == Yes ];then
	echo 0    0为正常
else
	echo 1   1为不正常
fi
重启服务
[[email protected] ~]# pkill zabbix
[[email protected] ~]# zabbix_agentd

配置监控项和触发器
mysql主从
mysql主从
测试:把slave停止(stop slave)
mysql主从
收到报警邮件
mysql主从
恢复正常,问题已解决 (start slave;)
mysql主从
收到恢复邮箱
mysql主从

监控主从pos值

[[email protected] ~]# vim /usr/local/etc/zabbix_agentd.conf
...
UserParameter=pos_mysqld,/scripts/pos.sh
[[email protected] ~]# vim /scripts/pos.sh 
[[email protected] ~]# cat /scripts/pos.sh   --检查pos是否相等
#!/bin/bash
a=$(mysql -e "show slave status\G"|grep Read_Master_Log_Pos:|awk -F: '{print $2}')
b=$(mysql -e "show slave status\G"|grep  Exec_Master_Log_Pos:|awk -F: '{print $2}')
c=$[$a-$b]
	case $c in
		0)
			echo 0 --正常
			    ;;
		*)
			echo 1  --非正常
			    ;; 
esac
创建相关监控项和触发器

mysql主从
mysql主从

GTID主从配置

GTID 分成两部分

  • 一部分是服务的UUid,UUID保存在mysql数据目录的auto.cnf文件中,这是一个非常重要的文件,不能删除,这一部分是不会改变的
  • 另外一部分是事务ID,随着事务的增加,值依次递增

在整个复制架构中GTID 是不变化的,即使在多个连环主从中也不会变
例如:ServerA —>ServerB ---->ServerC
GTID从在ServerA ,ServerB,ServerC 中都是一样的

GTID的工作原理

  • 1、master更新数据时,会在事务前产生GTID,一同记录到binlog日志中。
  • 2、slave端的i/o 线程将变更的binlog,写入到本地的relay log中。
  • 3、sql线程从relay log中获取GTID,然后对比slave端的binlog是否有记录。
  • 4、如果有记录,说明该GTID的事务已经执行,slave会忽略。
  • 5、如果没有记录,slave就会从relay log中执行该GTID的事务,并记录到binlog。
  • 6、在解析过程中会判断是否有主键,如果没有就用二级索引,如果没有就用全部扫描
    GTID的优点
  • 1.一个事务对应一个唯一ID,一个GTID在一个服务器上只会执行一次
  • 2.GTID是用来代替传统复制的方法,GTID复制与普通复制模式的最大不同就是不需要指定二进制文件名和位置
  • 3.减少手工干预和降低服务故障时间,当主机挂了之后通过软件从众多的备机中提升一台备机为主机

MySQL主从复制存在的问题

主从复制存在的问题

  • 主库宕机后,数据可能丢失

mysql主从复制是异步的,不需要等待从库复制成功后再返回。

  • 从库只有一个SQL线程,主库写压力大,复制很可能延时

从库应用日志的线程只有SQL线程一个,而主库同时接受很多线程进行读写。当主库压力大时,从库很可能落后主库

  • 解决方法:

半同步复制(可有效解决数据丢失的问题)
并行复制 (可以让从库同时启动更多的线程去应用binlog

在mysql主从的基础上配置GTID主从,参考上面文档
主库配置GTID参数(/etc/my.cnf)

主库
[[email protected] ~]# vim /etc/my.cnf
[mysqld]
basedir = /usr/local/mysql
datadir = /opt/data
socket = /tmp/mysql.sock
port = 3306
pid-file = /opt/data/mysql.pid
user = mysql
skip-name-resolve
server-id = 3  --比从库小
log-bin = mysql-bin
gtid-mode = on  --添加-开启gtid模式
enforce-gtid-consistency = true  --强制gtid一致性,开启后对于特定create table不被支持
binlog_format = row
从库
[mysqld]
basedir = /usr/local/mysql
datadir = /opt/data
socket = /tmp/mysql.sock
port = 3306
pid-file = /opt/data/mysql.pid
user = mysql
skip-name-resolve
relay-log=mysql-relay-bin
gtid-mode = on --开启gtid模式
enforce-gtid-consistency = true  --强制gtid一致性,开启后对于特定create table不被支持
server-id = 5  --比主库大
binlog_format = row
重启服务
 [[email protected] ~]# service mysqld stop
Shutting down MySQL.... SUCCESS! 
[[email protected] ~]# service mysqld start
Starting MySQL. SUCCESS! 
从库
[[email protected] ~]# service mysqld stop
Shutting down MySQL.. SUCCESS! 
[[email protected] ~]# service mysqld start
Starting MySQL. SUCCESS! 
  • 配置同步账号
  • 备份主数据库
  • 导入主数据库数据 上文已配置过
  • 配置同步

mysql> change master to master_host='192.168.125.129',master_user='xj',master_password='xj123456',master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.04 sec)

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

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.125.129
                  Master_User: xj
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 15579
               Relay_Log_File: mysql-relay-bin1.000002
                Relay_Log_Pos: 15792
        Relay_Master_Log_File: mysql-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              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: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 15579
              Relay_Log_Space: 16000
              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
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: 3
                  Master_UUID: 27bd7d9e-3640-11e9-bf5d-000c29610d2e
             Master_Info_File: /opt/data/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: 27bd7d9e-3640-11e9-bf5d-000c29610d2e:1-46
            Executed_Gtid_Set: 27bd7d9e-3640-11e9-bf5d-000c29610d2e:1-46
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

验证插入数据

主库
mysql> insert into xj values(10,'xxzz',22);
Query OK, 1 row affected (0.00 sec)

mysql> select * from xj;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | tom       |   20 |
|  2 | jerry     |   23 |
|  3 | wangqing  |   25 |
|  4 | sean      |   28 |
|  5 | zhangshan |   18 |
|  6 | zhangshan |   20 |
|  7 | xxx       |   21 |
|  8 | jjj       |   22 |
|  9 | hhhh      |   44 |
| 10 | xxzz      |   22 |
+----+-----------+------+
10 rows in set (0.00 sec)

mysql> 

从库

mysql> use xiaojian;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from xj;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | tom       |   20 |
|  2 | jerry     |   23 |
|  3 | wangqing  |   25 |
|  4 | sean      |   28 |
|  5 | zhangshan |   18 |
|  6 | zhangshan |   20 |
|  7 | xxx       |   21 |
|  8 | jjj       |   22 |
|  9 | hhhh      |   44 |
| 10 | xxzz      |   22 |
+----+-----------+------+
10 rows in set (0.00 sec)

mysql>