#mysql的复制原理以及流程

mysql的复制原理以及流程

#mysql的复制原理以及流程

mysql的复制描述

简单来说就是保证主服务器(Master)和从服务器(Slave)的数据是一致性的,向Master插入数据后,Slave会自动从Master把修改的数据同步过来(有一定的延迟),通过这种方式来保证数据的一致性,就是Mysql复制。

我们用mysql的复制可以解决哪些问题

一、高可用和故障切换

复制能够帮避免MySql单点失败,因为数据都是相同的,所以当Master挂掉后,可以指定一台Slave充当Master继续保证服务运行,因为数据是一致性的(如果当插入Master就挂掉,可能不一致,因为同步也需要时间),当然这种配置不是简单的把一台Slave充当Master,毕竟还要考虑后续的Salve同步Master

二、负载均衡

因为读写分离也算是负载均衡的一种,所以就不单独写了,因为一般都是有多台Slave的,所以可以将读操作指定到Slave服务器上(需要代码控制),然后再用负载均衡来选择那台Slave来提供服务,同时也可以吧一些大量计算的查询指定到某台Slave,这样就不会影响Master的写入以及其他查询

三、数据备份

一般我们都会做数据备份,可能是写定时任务,一些特殊行业可能还需要手动备份,有些行业要求备份和原数据不能在同一个地方,所以主从就能很好的解决这个问题,不仅备份及时,而且还可以多地备份,保证数据的安全

四、业务模块化

可以一个业务模块读取一个Slave,再针对不同的业务场景进行数据库的索引创建和根据业务选择MySQL存储引擎, 不同的slave可以根据不同需求设置不同索引和存储引擎

复制原理

1)在Slave 服务器上执行sart slave命令开启主从复制开关,开始进行主从复制。

2)此时,Slave服务器的IO线程会通过在master上已经授权的复制用户权限请求连接master服务器,并请求从执行binlog日志文件的指定位置(日志文件名和位置就是在配置主从复制服务时执行change master命令指定的)之后开始发送binlog日志内容

3)Master服务器接收到来自Slave服务器的IO线程的请求后,二进制转储IO线程会根据Slave服务器的IO线程请求的信息分批读取指定binlog日志文件指定位置之后的binlog日志信息,然后返回给Slave端的IO线程。返回的信息中除了binlog日志内容外,还有在master服务器端记录的新的binlog文件名称,以及在新的binlog中的下一个指定更新位置。

4)当Slave服务器的IO线程获取到Master服务器上IO线程发送的日志内容、日志文件及位置点后,会将binlog日志内容依次写到Slave端自身的Relay Log(即中继日志)文件(MySQL-relay-bin.xxx)的最末端,并将新的binlog文件名和位置记录到master-info文件中,以便下一次读取master端新binlog日志时能告诉Master服务器从新binlog日志的指定文件及位置开始读取新的binlog日志内容

5)Slave服务器端的SQL线程会实时检测本地Relay Log 中IO线程新增的日志内容,然后及时把Relay LOG 文件中的内容解析成sql语句,并在自身Slave服务器上按解析SQL语句的位置顺序执行应用这样sql语句,并在relay-log.info中记录当前应用中继日志的文件名和位置点

这种复制架构实现了获取事件和重放事件的解偶,允许这两个过程异步进行。也就是说I/O线程能够独立于SQL线程之外工作。但这种架构页限制了复制的过程,其中最重要的一点是主库上并发运行的查询再从库只能串行化执行,因为只有一个SQL线程重放中继日志中的事件。这是很多工作负载的性能瓶颈所在。因为始终受限于单线程。

复制类型

1、基于语句的复制

在Master上执行的SQL语句,在Slave上执行同样的语句。MySQL默认采用基于语句的复制,效率比较高。一旦发现没法精确复制时,会自动选着基于行的复制

2、基于行的复制

把改变的内容复制到Slave,而不是把命令在Slave上执行一遍。从MySQL5.0开始支持

3、混合类型的复制

默认采用基于语句的复制,一旦发现基于语句的无法精确的复制时,就会采用基于行的复制
相应地,binlog的格式也有三种:STATEMENT,ROW,MIXED。

主从复制配置

现在我们两个实例Mysql
server1 : 127.0.0.1 3306 master
server2 : 127.0.0.1 3301 slave

配置master:

在主库创建一个复制帐号,这个帐号是给从库的IO线程建立连接到主库时用的,从库会用这个帐号连接主库并读取主库的二进制日志:

grant replication slave, replication client on *.* to 'repl'@'localhost' identified by '123456';
主库添加配置:
# 设置server_id,一般设置为IP, 要独一无二的
server-id       = 10
# 开启二进制日志功能,最好是绝对路径
log_bin         = /var/log/mysql/mysql-bin.log
# 主从复制的格式(mixed,statement,row,默认格式是statement)
binlog_format=mixed
# 二进制日志自动删除/过期的天数。默认值为0,表示不自动删除。
expire_logs_days=7
# 为每个session 分配的内存,在事务过程中用来存储二进制日志的缓存
binlog_cache_size=1M
# 复制过滤:不需要备份的数据库,不输出(mysql库一般不同步)
binlog-ignore-db=mysql

启用二进制日志后,重启后, show master status; 可以看到二进制相关信息

mysql> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000008 |      107 |              |                  |
+------------------+----------+--------------+------------------+

添加从库设置:
# 设置server_id,一般设置为IP, 要独一无二的
server-id       = 10
log_bin         = /var/log/mysql/mysql-bin.log
# 中继日志路径
relay_log       = /home/mysql/3301/mysql-relay-bin
# 允许从库将其重放的事件也记录到自身的二进制日志中
log_slave_updates = 1
read_only = 1
从库开启复制:
mysql>  CHANGE MASTER TO
MASTER_HOST='$host',
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='msyql-bin.00001',
MASTER_LOG_POS=0;

MASTER_LOG_POS设为0,是从日志开头开始复制,MASTER_LOG_FILE是master的二进制文件

# 启动复制
mysql> start slave;
 
# 查看复制状态
mysql> show slave status;

*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 127.0.0.1
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000008
          Read_Master_Log_Pos: 107
               Relay_Log_File: mysql-relay-bin.000020
                Relay_Log_Pos: 253
        Relay_Master_Log_File: mysql-bin.000008
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
        Seconds_Behind_Master: 0
             Master_Server_Id: 10

# Slave_IO_Running: Yes,Slave_SQL_Running: Yes 说明同步正常进行
# Seconds_Behind_Master: 0 就是完全同步了

这时就完成了主从复制的配置,当主服务器有更新,从库也会更新。

我们还可以从线程列表看出复制线程,主库上可以看到由从库I/O线程向主库发起的连接。

mysql> show processlist \G
*************************** 1. row ***************************
     Id: 44
   User: repl
   Host: localhost:32866
     db: NULL
Command: Binlog Dump
   Time: 73032
  State: Master has sent all binlog to slave; waiting for binlog to be updated
   Info: NULL

同样,我们看看从库的线程,有两个,一个I/O线程,一个SQL线程:

mysql> show processlist \G
*************************** 1. row ***************************
     Id: 4
   User: system user
   Host: 
     db: NULL
Command: Connect
   Time: 73422
  State: Waiting for master to send event
   Info: NULL
*************************** 2. row ***************************
     Id: 5
   User: system user
   Host: 
     db: NULL
Command: Connect
   Time: 72417
  State: Slave has read all relay log; waiting for the slave I/O thread to update it
   Info: NULL

这两个线程都是再system user 帐号下运行,I/O线程是写日志到中继日志的线程, SQL线程是重放SQL的线程。

从已经运行很久的服务器上复制

那么,至此我们已经完成了Mysql的主从配置。
但是上面是配置两台刚好安装号的服务器,数据相同,并且知道当前主库二进制日志。
更典型的案例是,一个运行已经一段时间的主库,要用一台新安装的从库与之同步,此时这台从库还没有数据。
所以我们得想办法,线初始化从库: 从主库复制数据、使用最近依次备份来启动从库。
这需要三个条件来让主库和从库保持同步:

复制数据到从库

mysqldump  --single-transaction --all-databases --master-data=1 -uroot -p123456|mysql -S /home/mysql/3301/mysqld.sock -uroot -p123456