MySQL复制介绍

默认情况 下复制是异步进行的,从库也不需要一直连接到主库来同步数据
MySQL复制的数据粒度可以是主实例上所有的数据库,也可以是指定的一个或多个数据库 ,也可以是一个数据库里的指定的表

MySQL复制所带来的优势在于:

  • 1.扩展能力:
    通过复制功能可以将MySQL的性能压力分担到一个或多个slave上。这要求所有的写操作和修改操作都必须在Master上完成,而读操作可以被分配到一个或多个slave上。将读写分离到不同服务器执行之后,MySQL的读写性能得到提升

  • 2.数据库备份:
    由于从实例是同步主实例的数据,所以可以将备份作业部署到从库

  • 3.数据分析和报表:
    同样,一些数据分析和报表的实现可以在从实例执行,以减少对主库的 性能影响

  • 4.容灾能力:
    可以在物理距离较远的另一个数据中心建立一个slave,保证在主实例所在地区 遭遇灾难时,在另一个数据中心能快速恢复

MySQL复制有两种方法:

  • 1.传统方式:
    基于主库的bin-log将日志事件和事件位置复制到从库,从库再加以应用来达到主从同步的目的
  • 2.Gtid方式:
    global transaction identifiers是基于事务来复制数据,因此也就不依赖日志文件,同时又能更好的保证主从库数据一致性

MySQL复制有多种类型:

  • 1.异步复制:一个主库,一个或多个从库,数据异步同步到从库
  • 2.同步复制:在MySQL Cluster中特有的复制方式
  • 3.半同步复制:在异步复制的基础上,确保任何一个主库上的事务在提交之前至少有一个从库已经收到该事务并日志记录下来
  • 4.延迟复制:在异步复制的基础上,人为设定主库和从库的数据同步延迟时间,即保证数据延迟至少是这个参数

复制的工作原理

数据库修改事件记录到bin log中并传递到slave,然后slave在 本地还原的过程。而事件记录到bin log的格式会有所不同。

MySQL复制有三种核心格式

  • 1.基于语句的复制(statement based replication):基于主库将SQL语句写入到bin log中完成复制
  • 2.基于行数据的复制(row based replication):基于主库将每一个行数据变化的信息作为事件写入到bin log中完成日志
  • 3.混合复制(mixed based replication):上述两者的结合。默认情况下优先使用基于语句的复制,只有当部分语句如果基于语句复制不安全的情况下才会自动切换为基于行数据的复制

基于binlog的复制

基于binary log的复制是指主库将修改操作写入到bin log中,从库负责读取主库的bin log,并在本地复制一份,然 后将里面的操作在从库执行一遍
每个从库会保存目前读取主库日志的文件名和日志位置 主库和每个从库都必须有一个唯一ID,叫server-id配置在配置文件中

配置方法:
1.主库需要开启bin-log,并且指定一个唯一的server-id,重启数据库

[mysqld]
log-bin=mysql-bin
server-id=1    #在同一个复制组下的所有实例的server_id都必须是唯一的,而且取值必须是正整数,取值范围是1~(232)−1 确保主库的my.cnf中skip-networking参数为非开启状态,否则会导致主从库不能通信而复制失败
mysql> show variables like '%log_bin%'; 

2.在主库创建一个专门用来做复制的数据库用户,这样所有从库都可以用这个用户来连接主库,也可以确保这个用户只有复制的权限虽然可以用任何拥有复制权限的MySQL用户来建立复制关系,但由于被使用的用户名和密码 会明文保存在备库的master.info文件中,所以为安全起见,最好是使用仅有复制权限的独立用户

mysql> CREATE USER 'repl'@'192.168.237.%' IDENTIFIED BY 'mysql';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.237.%';

3.从slave库验证远程连接主库是否正常
4.获取主库的日志信息
为了确保建立的备库能从正确的bin log位置开启复制,要首先获取主库的bin log信息, 包括当前的日志文件名和日志文件内的位置

mysql> FLUSH TABLES WITH READ LOCK;             --主库上所有表加锁,停止修改
mysql > SHOW MASTER STATUS;                           -- 获取主库的日志信息,file表示当前日志, position表示当前日志里的位置 

5.备份数据到slave

  • a.主库数据生成镜像并上传到从库 两种方式生成镜像,一种是用mysqldump,是innodb存储引擎推荐的方式;
  • b.另一种是将数据文件从主库拷贝到从库,这种方式效率更高(省去了dump/import过程中insert语句执行导致的更新index的行为),但 innodb不推荐使用
shell> bin/mysqldump --all-databases --master-data -u root -p -P 3308 > dbdump.db 
#mysqldump方式导出所有数据库数据到dbdump.db文件,--master-data表示导出数据直接加上change master to参数以便备库使用
#如果使用文件拷贝的办法: 将主库临时关闭,并将相关文件拷贝到从库上 
shell> tar cf /tmp/db.tar ./data

6.主库释放锁

mysql> UNLOCK TABLES;
#从库配置唯一server-id,并重启mysql实例 从库的bin log属性可以打开也可以不打开 
[mysqld]
server-id=2

7.从库应用主库的数据镜像 Mysqldump的镜像,通过source命令执行 原始文件拷贝的镜像,将文件复制到和主库相同的目录下 从库指定主库的日志信息和链接信息

mysql> CHANGE MASTER TO
MASTER_HOST='master_host_name',
MASTER_PORT=port_number,
MASTER_USER='replication_user_name',
MASTER_PASSWORD='replication_password',
MASTER_LOG_FILE='recorded_log_file_name',
MASTER_LOG_POS='recorded_log_position';
CHANGE MASTER TO 
MASTER_HOST='192.168.237.128', 
MASTER_PORT=3308, MASTER_USER='repl', 
MASTER_PASSWORD='mysql', 
MASTER_LOG_FILE='mysql-bin.000001', 
MASTER_LOG_POS=801;

8.从库启动复制进程

mysql> START SLAVE;

9.查看主备库复制是否正常:

mysql> show slave status\G;

10.验证复制工作正常:
在主库添加任意数据,查看从库是否能查询到在Master上执行:

mysql> create table temp(id int,name varchar(10));
mysql> insert into temp values(1,'a'),(2,'b');  Query OK, 2 rows affected (0.01 sec)
 
-- slave:
mysql> select * from temp; 

排错:

Last_IO_Errno: 1593
Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work.

解决办法:
删除备库的auto.cnf文件,重启mysql,生成新的UUID

复制过程中由于备份之前没有lock全表而导致的数据复制异常主库上执行:

Delimiter //
Create procedure proc1()
        Begin
                Declare n int default 1;
                while n<=20000 do
                Insert into temp values(n, 'mike');
                Set n=n+1;
                End while;
        End;
//
delimiter ;
mysql> show master status;
mysql> call proc1();

存储过程执行过程中开始mysqldump,并建立从库

MySQL基于binlog的多slave环境

当第一个slave创建好之后,如果还想创建其他的slave,则可以直接使用先前使用的备份文件,分别执行:

  • 1.在slave的my.cnf上分配新的server_id
  • 2.从库应用主库的数据镜像
  • 3.利用相同的change master命令将从库指定主库的日志信息和链接信息
    4 4.Slave start
    这样第二个slave也就创建起来了
    主库上执行:
show processlist; 

如果想在事后再增加一个slave,但之前的备份文件已经不存在,或者主库的日志文件已经被清除了的情况下,考虑使用如下办法:
在已经建立好的复制环境中新增一个从库,则不需要关闭主库复制数据,而是用已有的 从库复制数据即可

1.关闭现有的从库
shell> mysqladmin shutdown
2.拷贝从库的文件到新的从库,包括log文件和relay log文件,其中如果relay log使用了 从库的主机名,则需要调relay-log-index参数

[root@vmware1 mysql]# tar -zcvf data.tar.gz data
[root@vmware1 mysql]# scp data.tar.gz db:/usr/local/mysql/data/
cd /usr/local/mysql/data/
tar –zxvf data.tar.gz
rm -rf /usr/local/mysql/data/auto.cnf

3.拷贝master info和relay log info文件到新的从库
4.为新的从库分配一个唯一的server-id
5.新的从库启动slave进程

主库操作

配置 文件
cat /etc/my.cnf
[mysqld]
datadir=/data/mysql/data
port=3308
log_bin=/data/mysql/data/mysql-bin
binlog_format=ROW
server-id=1				#注意,开启了binlog如果不填写server-id则数据库无法启动,参考官方文档
character-set-server = utf8
collation-server = utf8_unicode_ci
创建复制账号
grant replication slave on *.* to rep1@'%' identified by 'mysql';
加锁
flush tables with read lock;
记录binlog位置点
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      154 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
从库开启server-id,执行命令
change master to 
master_host='192.168.56.40',
master_port=3308,
master_user='rep1',
master_password='mysql',
master_log_file='mysql-bin.000001',
master_log_pos=154;


start slave;
show slave status\G
主库解锁
unlock talbes;