一、什么是Mysql主从复制
MySQL主从复制是其最重要的功能之一。主从复制是指一台服务器充当主数据库服务器,另一台或多台服务器充当从数据库服务器,主服务器中的数据自动复制到从服务器之中。对于多级复制,数据库服务器即可充当主机,也可充当从机。MySQL主从复制的基础是主服务器对数据库修改记录二进制日志,从服务器通过主服务器的二进制日志自动执行更新。
二、Mysq主从复制的三种类型
基于语句的复制:
主服务器上面执行的语句在从服务器上面再执行一遍,在MySQL-3.23版本以后支持。
存在的问题:时间上可能不完全同步造成偏差,执行语句的用户也可能是不同一个用户。
基于行的复制:
把主服务器上面改编后的内容直接复制过去,而不关心到底改变该内容是由哪条语句引发的,在MySQL-5.0版本以后引入。
存在的问题:比如一个工资表中有一万个用户,我们把每个用户的工资+1000,那么基于行的复制则要复制一万行的内容,由此造成的开销比较大,而基于语句的复制仅仅一条语句就可以了。
混合类型的复制:
MySQL默认使用基于语句的复制,当基于语句的复制会引发问题的时候就会使用基于行的复制,MySQL会自动进行选择。
在MySQL主从复制架构中,读操作可以在所有的服务器上面进行,而写操作只能在主服务器上面进行。主从复制架构虽然给读操作提供了扩展,可如果写操作也比较多的话(多台从服务器还要从主服务器上面同步数据),单主模型的复制中主服务器势必会成为性能瓶颈。
三、Mysql主从复制的工作原理
1、基于语句的复制:主服务器上面执行的语句在从服务器上面再执行一遍,在MySQL-3.23版本以后支持。
存在的问题:时间上可能不完全同步造成偏差,执行语句的用户也可能是不同一个用户。
2、基于行的复制:把主服务器上面改编后的内容直接复制过去,而不关心到底改变该内容是由哪条语句引发的,在MySQL-5.0版本以后引入。
存在的问题:比如一个工资表中有一万个用户,我们把每个用户的工资+1000,那么基于行的复制则要复制一万行的内容,由此造成的开销比较大,而基于语句的复制仅仅一条语句就可以了。
3、混合类型的复制:MySQL默认使用基于语句的复制,当基于语句的复制会引发问题的时候就会使用基于行的复制,MySQL会自动进行选择。
在MySQL主从复制架构中,读操作可以在所有的服务器上面进行,而写操作只能在主服务器上面进行。主从复制架构虽然给读操作提供了扩展,可如果写操作也比较多的话(多台从服务器还要从主服务器上面同步数据),单主模型的复制中主服务器势必会成为性能瓶颈。
配置Master的my.cnf文件(关键性的配置)/etc/my.cnf
log-bin=mysql-bin
server-id = 1
binlog-do-db=icinga
binlog-do-db=DB2 //如果备份多个数据库,重复设置这个选项即可
binlog-do-db=DB3 //需要同步的数据库,如果没有本行,即表示同步所有的数据库
binlog-ignore-db=mysql //被忽略的数据库
配置Slave的my.cnf文件(关键性的配置)/etc/my.cnf
log-bin=mysql-bin
server-id=2
master-host=10.1.68.110
master-user=backup
master-password=1234qwer
master-port=3306
replicate-do-db=icinga
replicate-do-db=DB2
replicate-do-db=DB3 //需要同步的数据库,如果没有本行,即表示同步所有的数据库
replicate-ignore-db=mysql //被忽略的数据库
建议:复制时若需要忽略某些数据库或者表的操作,最好不要在主服务器上面配置,因为主服务器忽略之后就不会再往二进制文件中写了,但是在从服务器上面虽然忽略了某些数据库但是主服务器上面的这些操作信息依然会被复制到从服务器上面的relay log里面,只是不会在从服务器上面执行而已。建议在从服务器中设置replicate-do-db
,而不要在主服务器上设置binlog-do-db
。
不管是黑名单(binlog-ignore-db、replicate-ignore-db
)还是白名单(binlog-do-db、replicate-do-db
)只写一个就行了,如果同时使用那么只有白名单生效。
四、Mysql主从复制的过程
MySQL主从复制的两种情况:同步复制和异步复制,实际复制架构中大部分为异步复制。
复制的基本过程如下:
Slave上面的IO进程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容。
Master接收到来自Slave的IO进程的请求后,负责复制的IO进程会根据请求信息读取日志指定位置之后的日志信息,返回给Slave的IO进程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置。
Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的 bin-log的文件名和位置记录到master-info文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log的哪个位置开始往后的日志内容,请发给我”。
Slave的Sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,并在自身执行。
五、Mysql主从复制的具体配置
复制通常用来创建主节点的副本,通过添加冗余节点来保证高可用性,当然复制也可以用于其他用途,例如在从节点上进行数据读、分析等等。在横向扩展的业务中,复制很容易实施,主要表现在在利用主节点进行写操作,多个从节点进行读操作,MySQL复制的异步性是指:事物首先在主节点上提交,然后复制给从节点并在从节点上应用,这样意味着在同一个时间点主从上的数据可能不一致。异步复制的好处在于它比同步复制要快,如果对数据的一致性要求很高,还是采用同步复制较好。
最简单的复制模式就是一主一从的复制模式了,这样一个简单的架构只需要三个步骤即可完成:
- 建立一个主节点,开启binlog,设置服务器id;
- 建立一个从节点,设置服务器id;
- 将从节点连接到主节点上。
Master机器
Master上面开启binlog日志,并且设置一个唯一的服务器id,在局域网内这个id必须唯一。二进制的binlog日志记录master上的所有数据库改变,这个日志会被复制到从节点上,并且在从节点上回放。修改my.cnf文件,在mysqld模块下修改如下内容:
[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
Slave机器
slave机器和master一样,需要一个唯一的server-id。
[mysqld]
server-id = 2
连接Slave到Master
在Master和Slave都配置好后,只需要把slave连接master即可
mysql> change master to master_host='XXXX',master_port=3306,master_user='account',master_password='XXXpassword';
接下来在master上做一些针对改变数据库的操作,来观察slave的变化情况。在修改完my.cnf配置重启数据库后,就开始记录binlog了。可以在/var/log/mysql目录下看到一个mysql-bin.000001文件,而且还有一个mysql-bin.index文件,这个mysql-bin.index文件是什么?这个文件保存了所有的binlog文件列表,但是我们在配置文件中并没有设置改值,这个可以通过log_bin_index进行设置,如果没有设置改值,则默认值和log_bin一样。在master上执行show binlog events命令,可以看到第一个binlog文件的内容。
注意:上面的sql语句是从头开始复制第一个binlog。若当前主库已经有部分binlog数据。
如果想从主库当前位置开始复制binlog,可以使用SHOW MASTER STATUS;
查看主库当前binlog的文件位置。
如果想从主库某个位置开始复制binlog,就需要在change master to时指定要开始的binlog文件名和语句在文件中的起点位置,参数如下:master_log_file和master_log_pos。
mysql> show binlog events\G
*************************** 1. row ***************************
Log_name: mysql-bin.000001
Pos: 4
Event_type: Format_desc
Server_id: 1
End_log_pos: 107
Info: Server ver: 5.5.28-0ubuntu0.12.10.2-log, Binlog ver: 4
*************************** 2. row ***************************
Log_name: mysql-bin.000001
Pos: 107
Event_type: Query
Server_id: 1
End_log_pos: 181
Info: create user rep
*************************** 3. row ***************************
Log_name: mysql-bin.000001
Pos: 181
Event_type: Query
Server_id: 1
End_log_pos: 316
Info: grant replication slave on *.* to rep identified by '123456'
3 rows in set (0.00 sec)
- Log_name 是二进制日志文件的名称,一个事件不能横跨两个文件
- Pos 这是该事件在文件中的开始位置
- Event_type 事件的类型,事件类型是给slave传递信息的基本方法,每个新的binlog都已Format_desc类型开始,以Rotate类型结束
- Server_id 创建该事件的服务器id
- End_log_pos 该事件的结束位置,也是下一个事件的开始位置,因此事件范围为Pos~End_log_pos-1
- Info 事件信息的可读文本,不同的事件有不同的信息
mysql> change master to
master_host='XXXX',
master_port=3306,
master_user='account',
master_password='XXXpassword',
master_log_file=xxxxxxfilename,
master_log_pos=xxxx;
然后开始同步:
mysql> start slave;
此时我们在主库执行一条sql语句,从库也会出现相同的结果。
五 MySQL主从复制的类型
五 MySQL主从复制错误及处理办法
主从复制什么时候会出现错误呢?
当在主库执行一条sql语句成功,但从库复制的时候,发现从库执行这条sql语句出现异常,可能出现的原因是:当表不存在、唯一索引冲突等情况时。
再此情况下,我们首先需要定位当前究竟什么什么原因导致从库复制失败。
现在从库执行:show slave status\G
获取从库的复制状态
返回的结果中,我们首先需要关注:Last_SQL_Error
代表最后一个执行的sql出错的原因。
定位到了错误的原因,我们需要根据错误原因,解决问题。这里我们需要关注三个返回值:
Relay_Master_Log_File: mysql-bin.000001
Skip_Counter: 0
Exec_Master_Log_Pos: 1543
Relay_Master_Log_File
表示主库哪个日志文件出现问题,
Exec_Master_Log_Pos
表示偏移量
根据以上提示的信息,在主库执行
mysql> SHOW BINLOG EVENTS in 'mysql-bin.000001' from 1543;
可以看到出错的sql语句,MySQL的binary log每个SQL执行实际上是由一些event组成的,我们这里要设置的就是要跳过的event的个数。本例中就是BEGIN、具体SQL语句和COMMIT这3个event,因此我们可以在从库上执行:
mysql> SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 3;
即可跳过这个语句
然后再次开启同步:
mysql> start slave;
再执行:
mysql> show slave status\G
检查从库同步状态。
上一篇:MySQL如何开启binlog?binlog三种模式的分析
欢迎关注公众号:java之旅