专职DBA-MySQL主从异步复制

孤街浪徒 提交于 2020-01-01 01:49:26
专职DBA-MySQL主从异步复制


MySQL主从复制企业级应用场景
1.从服务器作为主服务器的实时数据备份。
2.主从服务器实现读写分离,从服务器实现负载均衡。
3.根据业务重要性对多个从服务器进行拆分访问。

MySQL主从读写分离实现方案
1.通过开发程序实现读写分离(需要程序支持)
2.通过开源的软件实现读写分离。
3.大型门户独立开发DAL层综合软件。


mysql主从复制原理重点小结:
1.主从复制是异步的逻辑的SQL语句级的复制。
2.复制时,主库有一个binlog dump线程,从库有两个线程,I/O线程和SQL线程。
3.从mysql 5.6起,slave从库的SQL线程可以是多个。
4.实现主从复制的必要条件是主库要开启记录binlog的功能。
5.用于复制的所有mysql节点配置中的server-id都不能相同。
6.binlog文件只记录对数据库有更改的SQL语句(来自主库内容的更改),不记录任何(select,show)查询以及未对数据库做出更改的语句。


链接克隆两台主机,模板机安装请参考install_linux_os.sh


VMware克隆Centos6.4虚拟机网卡无法启动问题
# cat /etc/sysconfig/network-scripts/ifcfg-eth0
# sed -i '/UUID/d' /etc/sysconfig/network-scripts/ifcfg-eth0
# sed -i '/HWADDR/d' /etc/sysconfig/network-scripts/ifcfg-eth0
# >/etc/udev/rules.d/70-persistent-net.rules
# reboot


如果是克隆安装好的mysql虚拟机,还要修改数据目录下auto.cnf文件的UUID
/data/mysql/3306/data/auto.cnf
MySQL数据目录中通常存在一个名为auto.cnf文件,存储了server-uuid的值,
MySQL启动时,会自动从data_dir/auto.cnf 文件中获取server-uuid值,并将这个值存储在全局变量server_uuid中。
如果这个值或者这个文件不存在,那么将会生成一个新的uuid值,并将这个值保存在auto.cnf文件中。
server-uuid与server-id一样,用于标识MySQL实例在集群中的唯一性,这两个参数在主从复制中具有重要作用,
默认情况下,如果主从库的server-uuid或者server-id的值一样,将会导致主从复制报错中断。
你可以把auto.cnf删除或者mv走,数据库启动会自动生成auto.cnf


主、从库server-uuid值一样,导致主从复制异常中断
主、从库server-id值一样,同样导致主从复制异常中断
参考文章https://www.jianshu.com/p/2347b1a9eacd
参考文章https://www.jianshu.com/p/2347b1a9eacd


主机规划
数据库角色  主机名  bond0(ssh连接ip)  bond1(内网通信ip)  数据库端口
主库master  db01    10.0.0.11        192.168.10.11     3306
从库slave   db02    10.0.0.12        192.168.10.12     3306


按照专职DBA数据库安装文档,先把数据库安装上。
[root@db01 ~]# vim /etc/my.cnf
[mysql]
#prompt                  ="\\u@\\h [\\d]> \"
#prompt                  ="mysql [\\d]> \"
prompt                   ="Master [\\d]> \"
#prompt                  ="Slave [\\d]> \"

[root@db02 ~]# vim /etc/my.cnf
[mysql]
#prompt                  ="\\u@\\h [\\d]> \"
#prompt                  ="mysql [\\d]> \"
#prompt                  ="Master [\\d]> \"
prompt                   ="Slave [\\d]> \"


数据库配置文件示例
[root@db01 ~]# cat /data/mysql/3306/my.cnf
[mysqld]
# for mysql global
user                     = mysql
basedir                  = /usr/local/mysql
datadir                  = /data/mysql/3306/data
tmpdir                   = /data/mysql/3306/tmp
pid_file                 = /data/mysql/3306/3306.pid
socket                   = /data/mysql/3306/mysql.sock
port                     = 3306
server_id                = 113306
character-set-server     = utf8

# for binlog
binlog_format            = row
log_bin                  = /data/mysql/3306/logs/mysql-bin

# for error log
log_error                = /data/mysql/3306/error.log

# general log
general_log              = off
general_log_file         = /data/mysql/3306/general.log

# for slow query log
slow_query_log           = on
slow_query_log_file      = /data/mysql/3306/slow.log
long_query_time          = 1.000000

# for gtid
gtid_mode                = on
enforce_gtid_consistency = on

# for replication
# for innodb

[mysql]
character-set-client     = utf8
#prompt                  ="\\u@\\h [\\d]> \"
#prompt                  ="mysql [\\d]> \"
#prompt                  ="Master [\\d]> \"
#prompt                  ="Slave [\\d]> \"


检查数据库的当前状态
[root@db01 ~]# mysqld --defaults-file=/data/mysql/3306/my.cnf &
[1] 6735
[root@db01 ~]# ss -tunlp | grep mysql
tcp    LISTEN     0      80       :::3306                 :::*                   users:(("mysqld",pid=6735,fd=34))
[root@db01 ~]# netstat -tunlp | grep mysql
tcp6       0      0 :::3306                 :::*                    LISTEN      6735/mysqld         
[root@db01 ~]# lsof -i :3306
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
mysqld  6735 mysql   34u  IPv6  35637      0t0  TCP *:mysql (LISTEN)
[root@db01 ~]# lsof -i :mysql
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
mysqld  6735 mysql   34u  IPv6  35637      0t0  TCP *:mysql (LISTEN)
[root@db01 ~]# ps -aux | grep mysql
mysql     6735  2.0 35.0 1118452 171692 pts/0  Sl   06:02   0:01 mysqld --defaults-file=/data/mysql/3306/my.cnf
root      6787  0.0  0.1 112708   976 pts/0    R+   06:03   0:00 grep --color=auto mysql
[root@db01 ~]# ps -ef | grep mysql
mysql     6735  6697  1 06:02 pts/0    00:00:01 mysqld --defaults-file=/data/mysql/3306/my.cnf
root      6790  6697  0 06:03 pts/0    00:00:00 grep --color=auto mysql


[root@db02 ~]# mysqld --defaults-file=/data/mysql/3306/my.cnf &
[1] 6761
[root@db02 ~]# ps -ef | grep mysql
mysql     6761  6739 10 06:04 pts/0    00:00:01 mysqld --defaults-file=/data/mysql/3306/my.cnf
root      6790  6739  0 06:04 pts/0    00:00:00 grep --color=auto mysql


在主库master上执行操作配置
1.设置server_id的值,并开启binlog功能参数
(1).修改主库的配置文件/etc/my.cnf
[root@db01 ~]# egrep "server_id|log_bin" /data/mysql/3306/my.cnf 
server_id                = 113306
log_bin                  = /data/mysql/3306/logs/mysql-bin


(2).登录数据库检查参数的更改情况
[root@db01 ~]# mysql -S /data/mysql/3306/mysql.sock -p

Master [(none)]> show global variables like "server_id";
+---------------+--------+
| Variable_name | Value  |
+---------------+--------+
| server_id     | 113306 |
+---------------+--------+
1 row in set (0.00 sec)

Master [(none)]> show global variables like "log_bin";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+
1 row in set (0.01 sec)


2.在主库上创建用于主从复制的账号
从库要想与主库同步,必须要有一个可以连接主库的账号,并且这个账号是在主库上创建的,权限是允许从库连接主库并同步数据。
Master [(none)]> grant replication slave on *.* to 'rep'@'192.168.10.%' identified by '123';
Query OK, 0 rows affected, 1 warning (0.00 sec)

Master [(none)]> flush privileges;
Query OK, 0 rows affected (0.00 sec)

Master [(none)]> select user,host from mysql.user;
+---------------+--------------+
| user          | host         |
+---------------+--------------+
| rep           | 192.168.10.% |
| mysql.session | localhost    |
| mysql.sys     | localhost    |
| root          | localhost    |
+---------------+--------------+
4 rows in set (0.00 sec)

Master [(none)]> show grants for 'rep'@'192.168.10.%';
+--------------------------------------------------------+
| Grants for rep@192.168.10.%                            |
+--------------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO 'rep'@'192.168.10.%' |
+--------------------------------------------------------+
1 row in set (0.00 sec)


3、对主库锁表只读后进行备份(当前窗口不要关闭)
(1).对主库锁表只读
Master [(none)]> reset master;
Query OK, 0 rows affected (0.01 sec)

Master [(none)]> flush table with read lock;
Query OK, 0 rows affected (0.01 sec)


a.窗口关闭后锁表会失效。
b.超时参数设置的时间到了,锁表也会失效。
对于不同引擎,这个锁表命令的时间会受到下面参数的控制。锁表时,如果超过了设置的时间则会自动解锁。
Master [(none)]> show variables like '%timeout%';            
+-----------------------------+----------+
| Variable_name               | Value    |
+-----------------------------+----------+
| connect_timeout             | 10       |
| delayed_insert_timeout      | 300      |
| have_statement_timeout      | YES      |
| innodb_flush_log_at_timeout | 1        |
| innodb_lock_wait_timeout    | 50       |
| innodb_rollback_on_timeout  | OFF      |
| interactive_timeout         | 28800    |
| lock_wait_timeout           | 31536000 |
| net_read_timeout            | 30       |
| net_write_timeout           | 60       |
| rpl_stop_slave_timeout      | 31536000 |
| slave_net_timeout           | 60       |
| wait_timeout                | 28800    |
+-----------------------------+----------+
13 rows in set (0.00 sec)


(2).锁表后查看主库的状态
Master [(none)]> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      154 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)


(3).导出主库数据
锁表后,一定要再打开一个CRT窗口去操作
[root@db01 ~]# mysqldump -S /data/mysql/3306/mysql.sock -p -A -B |gzip > /backup/bak_$(date +%F).sql.gz
也可以加上-x --master-data=1就可以在从库配置复制参数的时候省去以下两个参数:
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=407;

[root@db01 ~]# ls -l /backup/
total 200
-rw-r--r-- 1 root root 196911 Jul 15 06:25 bak_2019-07-15.sql.gz
drwxr-xr-x 2 root root     29 Jul 12 03:50 conf
-rw-r--r-- 1 root root   2243 Jul 15 05:28 eth0123.zip
drwxr-xr-x 2 root root     54 Jul 12 05:39 sh
drwxr-xr-x 2 root root     49 Jul 12 03:52 sql


为了确保导出数据期间,数据库没有数据插入操作,导库完毕后再检查一下主库的状态信息。
Master [(none)]> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      154 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)


(4).导出数据完毕后,解锁主库,恢复可写,因为主库还要对外提供服务,因此不能一直锁定不让用户访问吧。
Master [(none)]> unlock tables;
Query OK, 0 rows affected (0.00 sec)


4.把主库导出的mysql数据迁移到从库
[root@db01 ~]# ping -c 3 192.168.10.12
PING 192.168.10.12 (192.168.10.12) 56(84) bytes of data.
64 bytes from 192.168.10.12: icmp_seq=1 ttl=64 time=0.633 ms
64 bytes from 192.168.10.12: icmp_seq=2 ttl=64 time=0.718 ms
64 bytes from 192.168.10.12: icmp_seq=3 ttl=64 time=0.543 ms

--- 192.168.10.12 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 0.543/0.631/0.718/0.074 ms


[root@db01 ~]# scp -rp /backup/bak_$(date +%F).sql.gz root@192.168.10.12:/backup/
The authenticity of host '192.168.10.12 (192.168.10.12)' can't be established.
ECDSA key fingerprint is SHA256:auBeaQTHqMvqa5fgR9w9UDEho26UWpxRqc0bHUwCv/Y.
ECDSA key fingerprint is MD5:fc:ad:3a:4d:d7:83:20:a5:a1:49:c6:59:39:0b:1c:e5.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.10.12' (ECDSA) to the list of known hosts.
root@192.168.10.12's password: 
bak_2019-07-15.sql.gz                                                  100%  192KB  16.0MB/s   00:00


在slave从库上执行的操作过程
1.设置server_id的值,并关闭binlog功能参数
从库的server_id不能与主库以及其他从库一样,并且需要注释掉从库binlog参数配置。
这里开启binlog反而会增加从库磁盘I/O的压力。
以下两种情况需要开启从库的binlog参数配置,记录数据库更新的sql语句:
    •级联同步复制A--->B--->C,中间的B数据库服务需要开启binlog记录功能。
    •在从库中做数据库备份时需要开启binlog记录功能。因为数据库备份必须要有全备和binlog日志,才是完整的备份。

(1).修改配置文件
[root@db02 ~]# egrep "server_id|log_bin" /data/mysql/3306/my.cnf 
server_id                = 123306
#log_bin                  = /data/mysql/3306/logs/mysql-bin


(3).重启从库
[root@db02 ~]# mysqladmin -S /data/mysql/3306/mysql.sock -p shutdown
[root@db02 ~]# mysqld --defaults-file=/data/mysql/3306/my.cnf &


(4).登录数据库检查参数的改变情况
[root@db02 ~]# mysql -S /data/mysql/3306/mysql.sock -p
Enter password:

Slave [(none)]> show global variables like "server_id";
+---------------+--------+
| Variable_name | Value  |
+---------------+--------+
| server_id     | 123306 |
+---------------+--------+
1 row in set (0.03 sec)

Slave [(none)]> show global variables like "log_bin";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | OFF   |
+---------------+-------+
1 row in set (0.01 sec)


2.将刚才主库mysqldump导出的数据恢复到从库
[root@db02 ~]# zcat /backup/bak_2019-07-15.sql.gz | mysql -S /data/mysql/3306/mysql.sock -p
Enter password:


3.登录从库配置复制参数
CHANGE MASTER TO
MASTER_HOST='192.168.10.11',
MASTER_PORT=3306,
MASTER_USER='rep',
MASTER_PASSWORD='123',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=154;

参数的值不能有空格!!!
Slave [(none)]> CHANGE MASTER TO
    -> MASTER_HOST='192.168.10.11',
    -> MASTER_PORT=3306,
    -> MASTER_USER='rep',
    -> MASTER_PASSWORD='123',
    -> MASTER_LOG_FILE='mysql-bin.000001',
    -> MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.02 sec)


以上操作原理是把用户密码等信息写入从库新的master.info文件中
[root@db02 ~]# ls -l /data/mysql/3306/data/master.info 
-rw-r----- 1 mysql mysql 86 Jul 15 06:37 /data/mysql/3306/data/master.info


[root@db02 ~]# cat /data/mysql/3306/data/master.info      
25
mysql-bin.000001
154
192.168.10.11
rep
123
3306
60
0





0
30.000

0

86400


0


4.启动从库同步开关并测试主从复制
(1).启动从库主从复制开关,并查看复制状态。
Slave [(none)]> start slave;
Query OK, 0 rows affected (0.01 sec)

Slave [(none)]> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.10.11
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 154
               Relay_Log_File: db02-relay-bin.000002
                Relay_Log_Pos: 320
        Relay_Master_Log_File: mysql-bin.000001
             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: 154
              Relay_Log_Space: 526
              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: 113306
                  Master_UUID: 7c145945-a680-11e9-baea-000c29a14cf7
             Master_Info_File: /data/mysql/3306/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: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

[root@db02 ~]# mysql -S /data/mysql/3306/mysql.sock -p -e "show slave status\G;"|egrep "IO_Running|SQL_Running:|_Behind_Master"   
Enter password: 
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
        Seconds_Behind_Master: 0 #0表示状态已经同步


测试主从同步,在主库写入数据。
Master [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

Master [(none)]> create database shenzhen;
Query OK, 1 row affected (0.00 sec)

Master [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| shenzhen           |
| sys                |
+--------------------+
5 rows in set (0.00 sec)


Slave [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| shenzhen           |
| sys                |
+--------------------+
5 rows in set (0.01 sec)


Master [shenzhen]> create table t1(id int);
Query OK, 0 rows affected (0.03 sec)

Master [shenzhen]> insert into t1(id) values(1);
Query OK, 1 row affected (0.04 sec)

Slave [(none)]> select * from shenzhen.t1;
+------+
| id   |
+------+
|    1 |
+------+
1 row in set (0.00 sec)


Master [(none)]> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|    123306 |      | 3306 |    113306 | ab0bfc5a-a681-11e9-bf5d-000c296165a9 |
+-----------+------+------+-----------+--------------------------------------+
1 row in set (0.00 sec)


Master [(none)]> show processlist;
+----+------+---------------------+------+-------------+------+---------------------------------------------------------------+------------------+
| Id | User | Host                | db   | Command     | Time | State                                                         | Info             |
+----+------+---------------------+------+-------------+------+---------------------------------------------------------------+------------------+
|  6 | root | localhost           | NULL | Query       |    0 | starting                                                      | show processlist |
|  8 | rep  | 192.168.10.12:55924 | NULL | Binlog Dump |  270 | Master has sent all binlog to slave; waiting for more updates | NULL             |
+----+------+---------------------+------+-------------+------+---------------------------------------------------------------+------------------+
2 rows in set (0.00 sec)


[root@db01 ~]# cat /data/mysql/3306/data/auto.cnf 
[auto]
server-uuid=7c145945-a680-11e9-baea-000c29a14cf7


[root@db02 ~]# mysql -S /data/mysql/3306/mysql.sock -p -e "show slave status\G;"|egrep "Master_UUID"     
Enter password: 
                  Master_UUID: 7c145945-a680-11e9-baea-000c29a14cf7


5.MySQL主从复制线程状态说明及用途
(1).登录主库查看mysql主从复制线程状态说明
Master [(none)]> show full processlist;
+----+------+---------------------+------+-------------+------+---------------------------------------------------------------+-----------------------+
| Id | User | Host                | db   | Command     | Time | State                                                         | Info                  |
+----+------+---------------------+------+-------------+------+---------------------------------------------------------------+-----------------------+
|  6 | root | localhost           | NULL | Query       |    0 | starting                                                      | show full processlist |
|  8 | rep  | 192.168.10.12:55924 | NULL | Binlog Dump |  386 | Master has sent all binlog to slave; waiting for more updates | NULL                  |
+----+------+---------------------+------+-------------+------+---------------------------------------------------------------+-----------------------+
2 rows in set (0.00 sec)


Master [(none)]> show full processlist\G
*************************** 1. row ***************************
     Id: 6
   User: root
   Host: localhost
     db: NULL
Command: Query
   Time: 0
  State: starting
   Info: show full processlist
*************************** 2. row ***************************
     Id: 8
   User: rep
   Host: 192.168.10.12:55924
     db: NULL
Command: Binlog Dump #用于复制的主库线程
   Time: 401
  State: Master has sent all binlog to slave; waiting for more updates #当前状态
   Info: NULL
2 rows in set (0.00 sec)


(2).登录从库查看mysql主从复制线程状态说明
Slave [(none)]> show processlist\G
*************************** 1. row ***************************
     Id: 2
   User: root
   Host: localhost
     db: NULL
Command: Query
   Time: 0
  State: starting
   Info: show processlist
*************************** 2. row ***************************
     Id: 4
   User: system user
   Host: 
     db: NULL
Command: Connect
   Time: 510
  State: Waiting for master to send event #线程已经连接上主服务器,正在等待二进制binlog日志事件的到达。
   Info: NULL
*************************** 3. row ***************************
     Id: 5
   User: system user
   Host: 
     db: NULL
Command: Connect
   Time: 319
  State: Slave has read all relay log; waiting for more updates
   Info: NULL
3 rows in set (0.00 sec)


6.主从复制存在的问题
(1).主库show master status;没有返回状态结果
    原因是binlog功能没打开或者没生效。
(2).change master to的时候参数不能有空格。
(3).mysql服务无法启动
    数据库目录权限和用户属主问题,数据库目录使用mysql用户。
    my.cnf文件参数出错。
    数据库初始化有问题,需要重新初始化。
(4).先在从库创建一个库,然后在主库创建同名的库,导致主从数据冲突。
    stop slave;
    set global sql_slave_skip_counter=1;
    start slave;
(5).mysql自身的原因,以及人为重复插入数据。
(6).不同的数据库版本会引起不同步,主从数据库版本不一致。
(7).mysql运行错误,或者程序有bug.
(8).binlog记录模式,例如row level模式就比默认的语句模式要好。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!