mysql主从复制原理
复制通常用来创建主节点的副本,通过添加冗余节点来保证高可用性,当然复制也可以用于其他用途,例如在从节点上进行数据读、分析等等。在横向扩展的业务中,复制很容易实施,主要表现在在利用主节点进行写操作,多个从节点进行读操作,mysql复制的异步性是指:事物首先在主节点上提交,然后复制给从节点并在从节点上应用,这样意味着在同一个时间点主从上的数据可能不一致,异步复制的好处在于它比同步复制要快,如果对数据的一致性要求很高,还是采用同步复制较好。
最简单的复制模式就是一主一从的复制模式了,这样一个简单的架构只需要三个步骤即可完成:
1 建立一个主节点,开启binlog,设置服务器id
2 建立一个从节点,设置服务器id
3 将从节点连接到主节点上
下面我们开始操作,以mysql5.5为例,操作系统ubuntu12.10,master 10.1.6.159 slave 10.1.6.191
1 | apt-get install mysql-server |
master机器
master上面开启binlog日志,并且设置一个唯一的服务器id,在局域网内这个id必须唯一。二进制的binlog日志记录master上的所有数据库改变,这个日志会被复制到从节点上,并且在从节点上回放。修改my.cnf文件,在mysqld模块下修改如下内容:
1
2 3 |
[mysqld]
server-id = 1 log_bin = /var/log/mysql/mysql-bin.log |
log_bin设置二进制日志所产生文件的基本名称,二进制日志由一系列文件组成,log_bin的值是可选项,如果没有为log_bin设置值,则默认值是:主机名-bin。如果随便修改主机名,则binlog日志的名称也会被改变的。server-id是用来唯一标识一个服务器的,每个服务器的server-id都不一样。这样slave连接到master后,会请求master将所有的binlog传递给它,然后将这些binlog在slave上回放。为了防止权限混乱,一般都是建立一个单独用于复制的账户。
1
2 |
create user rep;
grant replication slave on *.* to rep identified by '123456'; |
binlog是复制过程的关键,它记录了数据库的所有改变,通常即将执行完毕的语句会在binlog日志的末尾写入一条记录,binlog只记录改变数据库的语句,对于不改变数据库的语句则不进行记录。这种情况叫做基于语句的复制,还有一种情况是基于行的复制,两种模式各有各的优缺点。
slave机器
slave机器和master一样,需要一个唯一的server-id
1
2 |
[mysqld]
server-id = 2 |
连接slave到master
在master和slave都已经配置好后,只需要把slave指向master即可
1
2 |
change master to master_host='10.1.6.159',master_port=3306,master_user='rep',master_password='123456';
start slave; |
接下来在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,就需要在change master to时指定要开始的binlog文件名和语句在文件中的起点位置,参数如下:master_log_file和master_log_pos。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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 事件信息的可读文本,不同的事件有不同的信息
在master的test库中创建一个rep表,并插入一条记录。
1
2 3 |
create table rep(name var);
insert into rep values ("guol"); flush logs; |
flush logs命令强制轮转日志,生成一个新的二进制日志,可以通过show binlog events in 'xxx'来查看该二进制日志。可以通过show master status查看当前正在写入的binlog文件。这样就会在slave上执行相应的改变操作。
上面就是最简单的主从复制模式,不过有时候随着时间的推进,binlog会变得非常庞大,如果新增加一台slave,从头开始复制master的binlog文件是非常耗时的,所以我们可以从一个指定的位置开始复制binlog日志,可以通过其他方法把以前的binlog文件进行快速复制,例如copy物理文件。在change master to中有两个参数可以实现该功能,master_log_file和master_log_pos,通过这两个参数指定binlog文件及其位置。我们可以从master上复制也可以从slave上复制,假如我们是从master上复制,具体操作过程如下:
1 为了防止在操作过程中数据更新,导致数据不一致,所以需要先刷新数据并锁定数据库:flush tables with read lock
2 检查当前的binlog文件及其位置:show master status
1
2 3 4 5 6 7 |
mysql> show master status\G
*************************** 1. row *************************** File: mysql-bin.000003 Position: 107 Binlog_Do_DB: Binlog_Ignore_DB: 1 row in set (0.00 sec) |
3 通过mysqldump命令创建数据库的逻辑备分:mysqldump --all-databases -hlocalhost -p >back.sql
4 有了master的逻辑备份后,对数据库进行解锁:unlock tables
5 把back.sql复制到新的slave上,执行:mysql -hlocalhost -p <back.sql把master的逻辑备份插入slave的数据库中
6 现在可以把新的slave连接到master上了,只需要在change master to中多设置两个参数master_log_file='mysql-bin.000003'和master_log_pos='107'即可,然后启动slave:start slave,这样slave就可以接着107的位置进行复制了。
有时候master并不能让你锁住表进行复制,因为可能跑一些不间断的服务,如果这时master已经有了一个slave,我们则可以通过这个slave进行再次扩展一个新的slave。原理同在master上进行复制差不多,关键在于找到binlog的位置,你在复制的同时可能该slave也在和master进行同步,操作如下:
1 为了防止数据变动,还是需要停止slave的同步:stop slave
2 然后刷新表,并用mysqldump逻辑备份数据库
3 使用show slave status查看slave的相关信息,记录下两个字段的值Relay_Master_Log_File和Exec_Master_Log_Pos,这个用来确定从后面哪里开始复制。
4 对slave解锁,把备份的逻辑数据库导入新的slave的数据库中,然后设置change master to,这一步和复制master一样。