mysql主从复制原理介绍2

mysql m/s架构和mysqlm/m架构是mysql下的成熟解决方案了。网上相关文章也比较多,我在此趁着搬迁blog的机会,把相关知识总结分享一下。
相信能够看到这篇文章的朋友应该已经掌握了mysql的基本知识,我就不重复描述了,我就普及下和复制相关的理论知识。

一、复制能解决的问题

数据分布(多个地区的数据分发)
负载均衡(读写分离)
备份
高可用和故障切换的核心功能
测试mysql升级

二、复制的原理

mysql复制的原理现阶段都是一样的,master将操作记录到bin-log中,slave的一个线程去master读取bin-log,并将他们保存到relay-log中,slave的另外一个线程去重放relay-log中的操作来实现和master数据同步。

三、复制的历史

mysql-3.2 开始支持基于命令的复制,也就是statement-based replication。
mysql-5.1 开始支持基于行的复制和混合复制,也就是row-based replication和mixed-based relication。
mysql-5.5 开始支持semi-synchronous的复制,也叫半同步复制,目的在于事务环境下保持主从一致。
mysql-5.6 开始支持延时复制。

四、什么是SBR和RBR和MBR以及他们的优缺点?

这段内容来自homeserver.com.tw.
SBR:以sql语句的方式把master的操作记录到binlog中。
RBR:把修改的行记录到binlog中。
MBR:默认使用SBR方式记录日志,但是遇见一些特殊语句,如语句中包含uuid()、INSERT DELAYED、使用DML操作NDB表、大于等于两个AUTO_INCREMENT字段会被更新的时候都会使用RBR格式。具体参见:http://dev.mysql.com/doc/refman/5.1/en/binary-log-mixed.html
SBR优点:
1、稳定成熟
2、binlog文件较小
3、binlog中包含了所有资料库更改信息,方便数据库分析和恢复。
4、复制的master和slave,现在大部分版本都支持,不过建议slave的版本>=master的版本。
SBR缺点:
1、不是所有update语句都会被复制,尤其是包含不确定操作的时间。
2、调用具有不确定因数的UDF(user defaine function)时复制可能会出问题。
3、尽量避免使用以下函数:
LOAD_FILE();
UUID();
USER();
FUND_ROWS();
SYSDATE();
4、INSERT … SELECT 会产生比RBR更多的行级锁。
5、复制要进行全表扫描时(索引问题导致的),需要比RBR请求更多的行级锁。
6、对于有auto_increment字段的innodb表而言,insert语句会阻塞其他insert语句
7、对于一些复杂的语句,在从服务器上也会消耗很多资源。而RBR只会处理影响的行
8、确定的UDF也会在从服务器上执行。
9、slave数据必须和master一致,不然可能复制出错。
10、只支持REPEATABLE READ可重复读和以上的隔离级别

RBR的优点:
1、任何情况都可以复制,安全可靠。
2、和大多数数据库复制原理一样
3、多数情况下,从服务器上的表如果有主键的话,复制就会快很多。
4、复制以下几种语句行锁更少
INSERT … SELECT
包含AUTO_INCREMENT的INSERT
没有附带条件或者没有修改多条记录的UPDATE或DELETE语句
5、执行INSERT,UPDATE,DELETE语句时锁更少
6、从服务器上使用多线程复制成为可能
RBR的缺点:
1、binlog占用空间大。
2、复杂的回滚时binlog中会包含大量的数据。
3、服务器上执行update时所有发生改变的记录都会写到binlog中,而SBR只会写一条sql语句。
4、UDF产生的大BLOD值会导致复制变慢。
5、无法从binlog中看见复制写的语句。
6、当在非事务表上执行一段积累的SQL语句时,最好采用SBR模式,否则很容易导致主从数据不一致。

MIXED介绍
在使用MIXED格式下,mysql采用STATEMENT格式进行二进制日志文件的记录,但是有一些情况下会使用ROW格式,可能的情况如下:
1、表的存储引擎为NDB,这个时候DML操作都会以ROW格式记录
2、使用了uuid()、user(),current_user(),found_rows(),row_count(),等不确定函数。
3、使用了insert delay语句
4、使用了用户定于的函数(UDF)
5、使用了临时表(temporary table)

注意:针对系统库mysql里面的表发生变化的处理规则如下:
1、如果采用insert,update,delete直接操作表,则日志根据binlog_format设定的格式记录。
2、如果使用grant,revoke,set password等DCL语句,那么无论如何都会使用SBR模式记录。
3、blockhole引擎不支持row格式,ndb引擎不支持statement格式。

五、搭建主从复制

1、环境设定

role         IP           mysql-version           binlog_format
master       10.1.1.14    percona-mysql-5.5.20    statement
slave        10.1.1.15    percona-mysql-5.5.20    statement

2、master和slave都安装mysql参见http://isadba.com/index.php/2011/12/percona-5-5%E5%AE%89%E8%A3%85%E7%AC%94%E8%AE%B0/

我这里使用的是mysql的分支版本percona数据库,其实和mysql官方的差不多。
好了,现在我们的mysql已经跑起来了。配置文件使用默认的my-innodb-heavy-4g.cnf,现在我们开始修改配置文件。

3、修改配置文件my.cnf
和复制相关的参数:

log-bin=mysql-bin    //开启二进制日志,必须的。
binlog_format={stament|row|mixed}    //二进制日志的格式,上面已经介绍了。
server-id= 1    //serverid,在一个复制架构中全局唯一,一般master是1开始
sync_binlog=1    //在master上开启,用来同步刷新数据到硬盘,如果开启数据安全性会提高很多,但是会牺牲性能,根据自己需求权衡吧
auto_increment_increment=2    //auto_increment每次增长的值,主主复制的时候用来,避免auto_increment发生冲突。
auto_increment_offset=1    //auto_increment增长的偏移量,这两个值一起的意思就是auto_increment从1开始,每次增长2个,也就是1,3,5,7....
skip_slave_start    //slave数据库启动后,不自动开启slave线程。
read_only    //禁止非super权限的用户修改永久表。在主主复制情况下,用来锁定一个master保证数据一致性。
log_slave_updates    //slave上配置,将执行的sql语句记录到binlog,如果这个slave是其他db的master,需要开启这个选项。
slave_skip_errors=all    //slave配置,自动跳过所有错误,不建议使用,这样不利于保证主从数据的一致性。

innodb_flush_logs_at_trx_commit=1    //innodb引擎时可用通常和sync_binlog=1一起使用
innodb_support_xa=1        //innodb引擎时使用,这两个参数的目的是保证主从数据的一致性。

以下这些参数比较少使用,功能大概就是复制指定的库或者过滤某个库不复制,要使用此功能的朋友需要自己再详细测试下。
我一般不使用这些参数,因为他们不太好控制,容易导致主从数据不一致。
binlog-do-db=test    
binlog-ignore-db=mysql    
replicate-do-db=test    
replicate-ignore-db=mysql
replicate-do-table=
replicate-ignore-table=
replicate_wild_do_table=
replicate_wild_ignore_table=mysql.%

更多参数参见http://dev.mysql.com/doc/refman/5.5/en/replication-options.html

修改配置文件
10.1.1.14:
主库使用默认的配置,主要检查是否有以下三条记录

log-bin=mysql-bin
binlog_format=mixed
server-id=1

10.1.1.15:

log-bin=mysql-bin
binlog_format=mixed
server-id=2
log_slave_updates
skip_slave_start

配置完后需要检查这些选项是不是在配置文件中出现多次,因为mysql默认以最后一次出现的参数为准。

配置完成后从新启动mysql服务器。当然,现在不用重启10.1.1.14.

4、授权及配置复制
下面我们先以数据库没有数据为例演示

10.1.1.14:
mysql> grant replication slave,file on *.* to 'slave'@'10.1.1.15' identified by 'slave';
Query OK, 0 rows affected (0.01 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)
mysql> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 |      337 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
10.1.1.15:
mysql> CHANGE MASTER TO
    -> MASTER_HOST='10.1.1.14',            
    -> MASTER_USER='slave',      
    -> MASTER_PASSWORD='slave',    
    -> MASTER_PORT=9188,
    -> MASTER_LOG_FILE='mysql-bin.000003',
    -> MASTER_LOG_POS=337,
    -> MASTER_CONNECT_RETRY=10;
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: 10.1.1.14
                  Master_User: slave
                  Master_Port: 9188
                Connect_Retry: 10
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 337
               Relay_Log_File: zj14-relay-bin.000002
                Relay_Log_Pos: 253
        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: 337
              Relay_Log_Space: 408
              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: 1
1 row in set (0.00 sec)

当看见如下内容的时候证明我们复制搭建成功,复制开始运行了。
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

我们这里是两个新安装的数据库,如果是已经有数据的数据库你需要
a、将主库锁表后(flush tables with read lock\G),
b、备份主库数据
c、记录主库当前的show master status;
d、然后unlock tables;解除锁定。
e、slave端恢复master刚才备份的数据
f、执行change master to…..

5、测试
a、主库上创建一张表,并插入和删除数据查看slave上的情况

10.1.1.14:
mysql> create table t (id int(11) not null auto_increment,name varchar(32) not null,primary key (id));
mysql> insert into t(name) select 'andy';
mysql> insert into t(name) select 'isadba';
mysql> select * from t;
+----+--------+
| id | name   |
+----+--------+
|  1 | andy   |
|  2 | isadba |
+----+--------+
2 rows in set (0.00 sec)

10.1.1.15:
mysql> use test
Database changed
mysql> select * from t;
+----+--------+
| id | name   |
+----+--------+
|  1 | andy   |
|  2 | isadba |
+----+--------+
看来复制时正常的,现在我们在主库上删除isadba行。

10.1.1.14:
mysql> delete from t where name='isadba';
Query OK, 1 row affected (0.00 sec)

mysql> select * from t;
+----+------+
| id | name |
+----+------+
|  1 | andy |
+----+------+

10.1.1.15:
mysql> select * from t;
+----+------+
| id | name |
+----+------+
|  1 | andy |
+----+------+
b、从复制失败中恢复复制
我们先在slave中插入一条记录,然后在master上也出入一条记录,就会出现复制最常见的问题。

10.1.1.15:
insert into t (name) select 'mysql'; 现在还是一切正常,等我们master也插入相行后,slave就会报错了。

10.1.1.14:
mysql> insert into t(name) select 'mysql_master';
Query OK, 1 row affected (0.00 sec)

10.1.1.15:
mysql> show slave status\G
Slave_IO_Running: Yes
Slave_SQL_Running: No
Last_Errno: 1062
Last_Error: Error 'Duplicate entry '3' for key 'PRIMARY'' on query. Default database: 'test'. Query: 'insert into t(name) select 'mysql_master''
这就是最容易出现的主键冲突,现在我们来解决这个问题:
解决分两种,一种是跳过错误,让这个错误存在,一种是完整的修复,让数据一致。
在slave使用
set global sql_slave_skip_counter=1;
start slave;    //这样可以跳过错误,现在复制恢复正常了。但是master和slave的数据却不一样了。

10.1.1.14:
mysql> select * from t;
+----+--------------+
| id | name         |
+----+--------------+
|  1 | andy         |
|  3 | mysql_master |
+----+--------------+
10.1.1.15:
mysql> select * from t;
+----+-------+
| id | name  |
+----+-------+
|  1 | andy  |
|  3 | mysql |
+----+-------+

我们需要删除不同的这条记录,保证主从一致,在主库上执行如下操作,如果是RBR的日志,可能slave还会报错,不过没关系,那就在客户端也删除id是3那条记录,
并且掉过复制报错就行了。上面有一个Last_Errno: 1062的行,我们可以把1062这个错误号加到配置文件中(slave_skip_errors),让复制发现这种错误自动跳过。如果数据一致性要求高
的话,我不推荐使用此选项,应该成程序根源上找问题和方法解决。

10.1.1.14:
mysql> delete from t where id=3;
Query OK, 1 row affected (0.00 sec)

到此mysql M/S复制基本搭建完成。

六、在主从复制基础上完成主主复制

上面M/S架构已经搭建完成了,现在我们要做一些修改把M/S配置改变成M/M架构。
1、修改配置文件
主要解决
a、自增长冲突的问题
b、关闭其中一个服务的写入
检查配置文件是否有以下内容,并且保证每个值都没有重复定义

10.1.1.14:
log-bin=mysql-bin
binlog_format=mixed
server-id=1    
auto_increment_increment=2
auto_increment_offset=1
skip_slave_start
log_slave_updates
10.1.1.15:
log-bin=mysql-bin
binlog_format=mixed
server-id=2
auto_increment_increment=2
auto_increment_offset=2
skip_slave_start
log_slave_updates
read_only

更新配置文件以后,从新启动服务器。

2、在10.1.15上授权允许10.1.1.14复制。10.1.1.15:
mysql>start slave;
mysql> grant replication slave,file on *.* to 'slave'@'10.1.1.14' identified by 'slave';
Query OK, 0 rows affected (0.01 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

3、10.1.1.15上锁表,并在10.1.14上配置slave,这个时候尽量停止业务,避免数据不一致。

10.1.1.15:
mysql> flush tables with read lock;
Query OK, 0 rows affected (0.01 sec)
flush tables with read lock
mysql> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000006 |      347 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
10.1.1.14:
mysql> CHANGE MASTER TO
    -> MASTER_HOST='10.1.1.15',            
    -> MASTER_USER='slave',      
    -> MASTER_PASSWORD='slave',    
    -> MASTER_PORT=9188,MASTER_LOG_FILE='mysql-bin.000006',
    -> MASTER_LOG_POS=347,
    -> MASTER_CONNECT_RETRY=10;
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: 10.1.1.15
                  Master_User: slave
                  Master_Port: 9188
                Connect_Retry: 10
              Master_Log_File: mysql-bin.000006
          Read_Master_Log_Pos: 347
               Relay_Log_File: zj13-relay-bin.000002
                Relay_Log_Pos: 253
        Relay_Master_Log_File: mysql-bin.000006
             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: 347
              Relay_Log_Space: 408
              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: 2
1 row in set (0.00 sec)
10.1.1.15:
mysql> unlock tables;
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: 10.1.1.14
                  Master_User: slave
                  Master_Port: 9188
                Connect_Retry: 10
              Master_Log_File: mysql-bin.000004
          Read_Master_Log_Pos: 107
               Relay_Log_File: zj14-relay-bin.000005
                Relay_Log_Pos: 253
        Relay_Master_Log_File: mysql-bin.000004
             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: 107
              Relay_Log_Space: 554
              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: 1
1 row in set (0.00 sec)

4、测试,分别在两个分别插入一条数据,然后看两个服务器数据是否相同。一般生产环境下,写入点只有一个,因为两个写入点很容易出现数据不同步。


转载于:https://my.oschina.net/zijian1315/blog/202599

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL主从复制是一种数据复制技术,用于将一个MySQL主服务器上的数据自动复制到一个或多个从服务器上。主从复制原理如下: 1. 主服务器(Master)记录二进制日志(Binary Log):当主服务器上的数据发生变化时,如插入、更新、删除操作,主服务器会将这些变化记录在二进制日志中。二进制日志是一个有序的、以事件为单位的记录。 2. 从服务器(Slave)连接到主服务器:从服务器通过与主服务器建立连接来获取数据复制的权限。连接可以通过网络进行,通常使用MySQL复制线程进行数据同步。 3. 从服务器请求复制事件:从服务器向主服务器发送复制请求,请求从指定的二进制日志位置开始复制数据。 4. 主服务器发送复制事件:主服务器接收到从服务器的复制请求后,开始将相应的二进制日志事件发送给从服务器。 5. 从服务器应用复制事件:从服务器接收到主服务器发送的二进制日志事件后,按照事件的顺序应用这些事件,将数据变化在从服务器上重演,从而实现数据的复制。 6. 从服务器持续复制:一旦从服务器追上了主服务器当前的位置,它就会持续地监听主服务器发送的新的二进制日志事件,并应用到自己的数据上,实现实时的数据同步。 通过主从复制,可以实现数据的冗余存储、负载均衡、数据备份和故障恢复等应用场景。需要注意的是,主从复制只是单向的数据复制,从服务器不能直接写入数据,只能读取主服务器上的数据。如果需要双向同步,可以设置主从切换或使用其他技术。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值