什么是 MySQL 主从同步

当 master(主)库的数据发生变化的时候,变化会实时的同步到slave(从)库。

主从同步有什么好处

  1. 水平扩展数据库的负载能力
  2. 容错,高可用。Failover/High Availability
  3. 数据备份

主从同步的原理是什么

首先我们来了解 master-slave 的体系结构。

如下图:

binlog解析 mysql 开源工具 mysql binlog原理_mysql 查看binlog

不管是 delete、update、insert,还是创建函数、存储过程,所有的操作都在 master 上。

当 master 有操作的时候,slave 会快速的接收到这些操作,从而做同步。

但是,这个机制是怎么实现的呢?

  1. 在 master 机器上,主从同步事件会被写到特殊的 log 文件中(binary-log);
  2. 在 slave 机器上,slave 读取主从同步事件,并根据读取的事件变化,在 slave 库上做相应的更改。

如此,就实现了主从同步了!下面我们来详细的了解。

主从同步事件有哪些

上面说到,在 master 机器上,主从同步事件会被写到特殊的 log 文件中(binary-log);

主从同步事件有3种形式:statement、row、mixed。

  1. statement:会将对数据库操作的 sql 语句写入到 binlog 中。
  2. row:会将每一条数据的变化写入到 binlog 中。
  3. mixed:statement 与 row 的混合。MySQL 决定什么时候写 statement 格式的,什么时候写 row 格式的 binlog。

在 master 上的操作

当 master 上的数据发生改变的时候,该事件(insert、update、delete)变化会按照顺序写入到binlog中。

binlog dump线程

当 slave 连接到 master 的时候,master机器会为slave开启binlog dump线程。

当 master 的 binlog 发生变化的时候,binlog dump线程会通知slave,并将相应的binlog内容发送给slave。

在 slave 上的操作


当主从同步开启的时候,slave上会创建2个线程。 I/O线程:该线程连接到 master 机器,master 机器上的 binlog dump 线程会将 binlog的内容发送给该 I/O 线程。该 I/O 线程接收到 binlog 内容后,再将内容写入到本地的relay log。 SQL线程:该线程读取 I/O 线程写入的 relay log。并且根据 relay log 的内容对 slave 数据库做相应的操作。

查看上述线程

使用 SHOW PROCESSLIST 命令可以查看,如图,在 master 机器上查看 binlog dump线程。

binlog解析 mysql 开源工具 mysql binlog原理_mysql binlog查看工具_02

如图,在 slave 机器上查看I/O、SQL线程。

binlog解析 mysql 开源工具 mysql binlog原理_mysql 事件_03

一图以蔽之

讲了这么多,一图以蔽之

binlog解析 mysql 开源工具 mysql binlog原理_binlog解析 mysql 开源工具_04

下面的实战演练,都是基于上面的环境。当然,其他环境也大同小异。

os:ubuntu16.04mysql:5.7.17
os:ubuntu16.04
mysql:5.7.17




工具
2台机器:

master IP:192.168.33.22slave  IP:192.168.33.33
master IP:192.168.33.22
slave  IP:192.168.33.33




master 机器上的操作

1、更改配置文件

我们找到文件

/etc/mysql/mysql.conf.d/mysqld.cnf
/etc/mysql/mysql.conf.d/mysqld.cnf




配置如下:

#your master ipbind-address = 192.168.33.22#在master-slave架构中,每台机器节点都需要有唯一的server-idserver-id = 1#开启binlog log_bin = /var/log/mysql/mysql-bin.log
#your master ip
bind-address = 192.168.33.22
#在master-slave架构中,每台机器节点都需要有唯一的server-id
server-id = 1
#开启binlog 
log_bin = /var/log/mysql/mysql-bin.log




2、重启 MySQL,以使配置文件生效。

sudo systemctl restart mysql
sudo systemctl restart mysql




3、创建主从同步的 MySQL user

$ mysql -u root -pPassword:##创建slave1用户,并指定该用户只能在主机192.168.33.33上登录。mysql> CREATE USER 'slave1'@'192.168.33.33' IDENTIFIED BY 'slavepass';Query OK, 0 rows affected (0.00 sec)##为slave1赋予REPLICATION SLAVE权限。mysql> GRANT REPLICATION SLAVE ON *.* TO 'slave1'@'192.168.33.33';Query OK, 0 rows affected (0.00 sec)
$ mysql -u root -p
Password:

##创建slave1用户,并指定该用户只能在主机192.168.33.33上登录。
mysql> CREATE USER 'slave1'@'192.168.33.33' IDENTIFIED BY 'slavepass';
Query OK, 0 rows affected (0.00 sec)

##为slave1赋予REPLICATION SLAVE权限。
mysql> GRANT REPLICATION SLAVE ON *.* TO 'slave1'@'192.168.33.33';
Query OK, 0 rows affected (0.00 sec)




4、为 MySQL 加读锁

为了主库与从库的数据保持一致,我们先为 MySQL 加入读锁,使其变为只读。

mysql> FLUSH TABLES WITH READ LOCK;Query OK, 0 rows affected (0.00 sec)

5、记录下来 MASTER REPLICATION LOG 的位置

mysql> SHOW MASTER STATUS;+------------------+----------+--------------+------------------+-------------------+| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |+------------------+----------+--------------+------------------+-------------------+| mysql-bin.000001 |      613 |              |                  |                   |+------------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)
mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      613 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)




6、将 master DB 中现有的数据信息导出

$ mysqldump -u root -p --all-databases --master-data > dbdump.sql
$ mysqldump -u root -p --all-databases --master-data > dbdump.sql




7、解除 master DB 的读锁

mysql> UNLOCK TABLES;
mysql> UNLOCK TABLES;




8、将步骤 6 中的 dbdump.sql 文件 copy 到 slave

scp dbdump.sql ubuntu@192.168.33.33:/home/ubuntu
scp dbdump.sql ubuntu@192.168.33.33:/home/ubuntu




slave 机器上的操作

1、更改配置文件

我们找到文件

/etc/mysql/mysql.conf.d/mysqld.cnf
/etc/mysql/mysql.conf.d/mysqld.cnf




更改配置如下:

#your slave ipbind-address = 192.168.33.33#master-slave结构中,唯一的server-idserver-id = 2 #开启binloglog_bin = /var/log/mysql/mysql-bin.log
#your slave ip
bind-address = 192.168.33.33
#master-slave结构中,唯一的server-id
server-id = 2 
#开启binlog
log_bin = /var/log/mysql/mysql-bin.log




2、重启 MySQL,以使配置文件生效

sudo systemctl restart mysql
sudo systemctl restart mysql




3、导入从 master DB。导出的 dbdump.sql 文件,以使 master-slave 数据一致

$ mysql -u root -p < /home/ubuntu/dbdump.sql
$ mysql -u root -p < /home/ubuntu/dbdump.sql




4、使 slave 与 master 建立连接,从而同步

$ mysql -u root -pPassword:mysql> STOP SLAVE;Query OK, 0 rows affected, 1 warning (0.00 sec)mysql> CHANGE MASTER TO    -> MASTER_HOST='192.168.33.22',    -> MASTER_USER='slave1',    -> MASTER_PASSWORD='slavepass',    -> MASTER_LOG_FILE='mysql-bin.000001',    -> MASTER_LOG_POS=613;Query OK, 0 rows affected, 2 warnings (0.01 sec)mysql> START SLAVE;Query OK, 0 rows affected (0.00 sec)
$ mysql -u root -p
Password:

mysql> STOP SLAVE;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> CHANGE MASTER TO
    -> MASTER_HOST='192.168.33.22',
    -> MASTER_USER='slave1',
    -> MASTER_PASSWORD='slavepass',
    -> MASTER_LOG_FILE='mysql-bin.000001',
    -> MASTER_LOG_POS=613;
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql> START SLAVE;
Query OK, 0 rows affected (0.00 sec)




经过如此设置之后,就可以进行 master-slave 同步了~