Mysql内建的复制功能是构建大型,高性能应用程序的基础。将Mysql的数据分布到多个系统上去,这种分布的机制,是经过将Mysql的某一台主机的数据复制到其它主机(slaves)上,并从新执行一遍来实现的。复制过程当中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循环。这些日志能够记录发送到从服务器的更新。当一个从服务器链接主服务器时,它通知主服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,而后封锁并等待主服务器通知新的更新。html
请注意当你进行复制时,全部对复制中的表的更新必须在主服务器上进行。不然,你必需要当心,以免用户对主服务器上的表进行的更新与对从服务器上的表所进行的更新之间的冲突。mysql
(1):基于语句的复制: 在主服务器上执行的SQL语句,在从服务器上执行一样的语句。MySQL默认采用基于语句的复制,效率比较高。 一旦发现无法精确复制时, 会自动选着基于行的复制。 (2):基于行的复制:把改变的内容复制过去,而不是把命令在从服务器上执行一遍. 从mysql5.0开始支持 (3):混合类型的复制: 默认采用基于语句的复制,一旦发现基于语句的没法精确的复制时,就会采用基于行的复制。算法
MySQL复制技术有如下一些特色: (1) 数据分布 (Data distribution ) (2) 负载平衡(load balancing) (3) 备份(Backups) (4) 高可用性和容错行 High availability and failover sql
总体上来讲,复制有3个步骤: shell
(1) master将改变记录到二进制日志(binary log)中(这些记录叫作二进制日志事件,binary log events); (2) slave将master的binary log events拷贝到它的中继日志(relay log); (3) slave重作中继日志中的事件,将改变反映它本身的数据。数据库
下图描述了复制的过程:缓存
该过程的第一部分就是master记录二进制日志。在每一个事务更新数据完成以前,master在二日志记录这些改变。MySQL将事务串行的写入二进制日志,即便事务中的语句都是交叉执行的。在事件写入二进制日志完成后,master通知存储引擎提交事务。 下一步就是slave将master的binary log拷贝到它本身的中继日志。首先,slave开始一个工做线程——I/O线程。I/O线程在master上打开一个普通的链接,而后开始binlog dump process。Binlog dump process从master的二进制日志中读取事件,若是已经跟上master,它会睡眠并等待master产生新的事件。I/O线程将这些事件写入中继日志。 SQL slave thread(SQL从线程)处理该过程的最后一步。SQL线程从中继日志读取事件,并重放其中的事件而更新slave的数据,使其与master中的数据一致。只要该线程与I/O线程保持一致,中继日志一般会位于OS的缓存中,因此中继日志的开销很小。 此外,在master中也有一个工做线程:和其它MySQL的链接同样,slave在master中打开一个链接也会使得master开始一个线程。复制过程有一个很重要的限制——复制在slave上是串行化的,也就是说master上的并行更新操做不能在slave上并行操做。服务器
有两台MySQL数据库服务器Master和slave,Master为主服务器,slave为从服务器,初始状态时,Master和slave中的数据信息相同,当Master中的数据发生变化时,slave也跟着发生相应的变化,使得master和slave的数据信息同步,达到备份的目的。网络
要点: 负责在主、从服务器传输各类修改动做的媒介是主服务器的二进制变动日志,这个日志记载着须要传输给从服务器的各类修改动做。所以,主服务器必须激活二进制日志功能。从服务器必须具有足以让它链接主服务器并请求主服务器把二进制变动日志传输给它的权限。 环境: Master和slave的MySQL数据库版本同为5.0.18 操做系统:unbuntu 11.10 IP地址:10.100.0.100session
一、在Master的数据库中创建一个备份账户:每一个slave使用标准的MySQL用户名和密码链接master。进行复制操做的用户会授予REPLICATION SLAVE权限。用户名的密码都会存储在文本文件master.info中
命令以下: mysql > GRANT REPLICATION SLAVE,RELOAD,SUPER ON *.* TO backup@’10.100.0.200’ IDENTIFIED BY ‘1234’;
创建一个账户backup,而且只能容许从10.100.0.200这个地址上来登录,密码是1234。
(若是由于mysql版本新旧密码算法不一样,能够设置:set password for 'backup'@'10.100.0.200'=old_password('1234'))
(假如是你彻底新安装mysql主从服务器,这个一步就不须要。由于新安装的master和slave有相同的数据)
关停Master服务器,将Master中的数据拷贝到B服务器中,使得Master和slave中的数据同步,而且确保在所有设置操做结束前,禁止在Master和slave服务器中进行写操做,使得两数据库中的数据必定要相同!
接下来对master进行配置,包括打开二进制日志,指定惟一的servr ID。例如,在配置文件加入以下值:
server-id=1 log-bin=mysql-bin
server-id:为主服务器A的ID值 log-bin:二进制变动日值
重启master,运行SHOW MASTER STATUS,输出以下:
Slave的配置与master相似,你一样须要重启slave的MySQL。以下:
log_bin = mysql-bin
server_id = 2
relay_log = mysql-relay-bin
log_slave_updates = 1
read_only = 1
server_id是必须的,并且惟一。slave没有必要开启二进制日志,可是在一些状况下,必须设置,例如,若是slave为其它slave的master,必须设置bin_log。在这里,咱们开启了二进制日志,并且显示的命名(默认名称为hostname,可是,若是hostname改变则会出现问题)。
relay_log配置中继日志,log_slave_updates表示slave将复制事件写进本身的二进制日志(后面会看到它的用处)。
有些人开启了slave的二进制日志,却没有设置log_slave_updates,而后查看slave的数据是否改变,这是一种错误的配置。因此,尽可能使用read_only,它防止改变数据(除了特殊的线程)。可是,read_only并是很实用,特别是那些须要在slave上建立表的应用。
接下来就是让slave链接master,并开始重作master二进制日志中的事件。你不该该用配置文件进行该操做,而应该使用CHANGE MASTER TO语句,该语句能够彻底取代对配置文件的修改,并且它能够为slave指定不一样的master,而不须要中止服务器。以下:
mysql> CHANGE MASTER TO MASTER_HOST='server1',
-> MASTER_USER='repl',
-> MASTER_PASSWORD='p4ssword',
-> MASTER_LOG_FILE='mysql-bin.000001',
-> MASTER_LOG_POS=0;
MASTER_LOG_POS的值为0,由于它是日志的开始位置。
你能够用SHOW SLAVE STATUS语句查看slave的设置是否正确:
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: server1
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 4
Relay_Log_File: mysql-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: No
Slave_SQL_Running: No
...omitted...
Seconds_Behind_Master: NULL
Slave_IO_State, Slave_IO_Running, 和Slave_SQL_Running是No
代表slave尚未开始复制过程。日志的位置为4而不是0,这是由于0只是日志文件的开始位置,并非日志位置。实际上,MySQL知道的第一个事件的位置是4。
为了开始复制,你能够运行:
mysql> START SLAVE;
运行SHOW SLAVE STATUS查看输出结果:
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: server1
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 164
Relay_Log_File: mysql-relay-bin.000001
Relay_Log_Pos: 164
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...omitted...
Seconds_Behind_Master: 0
在这里主要是看: Slave_IO_Running=Yes Slave_SQL_Running=Yes
slave的I/O和SQL线程都已经开始运行,并且Seconds_Behind_Master再也不是NULL。日志的位置增长了,意味着一些事件被获取并执行了。若是你在master上进行修改,你能够在slave上看到各类日志文件的位置的变化,一样,你也能够看到数据库中数据的变化。
你可查看master和slave上线程的状态。在master上,你能够看到slave的I/O线程建立的链接:
在master上输入show processlist\G;
mysql> show processlist \G *************************** 1. row *************************** Id: 1 User: root Host: localhost:2096 db: test Command: Query Time: 0 State: NULL Info: show processlist *************************** 2. row *************************** Id: 2 User: repl Host: localhost:2144 db: NULL Command: Binlog Dump Time: 1838 State: Has sent all binlog to slave; waiting for binlog to be updated Info: NULL 2 rows in set (0.00 sec) |
行2为处理slave的I/O线程的链接。
在slave服务器上运行该语句:
mysql> show processlist \G *************************** 1. row *************************** Id: 1 User: system user Host: db: NULL Command: Connect Time: 2291 State: Waiting for master to send event Info: NULL *************************** 2. row *************************** Id: 2 User: system user Host: db: NULL Command: Connect Time: 1852 State: Has read all relay log; waiting for the slave I/O thread to update it Info: NULL *************************** 3. row *************************** Id: 5 User: root Host: localhost:2152 db: test Command: Query Time: 0 State: NULL Info: show processlist 3 rows in set (0.00 sec) |
行1为I/O线程状态,行2为SQL线程状态。
假如master已经运行好久了,想对新安装的slave进行数据同步,甚至它没有master的数据。
此时,有几种方法可使slave从另外一个服务开始,例如,从master拷贝数据,从另外一个slave克隆,从最近的备份开始一个slave。Slave与master同步时,须要三样东西:
(1)master的某个时刻的数据快照;
(2)master当前的日志文件、以及生成快照时的字节偏移。这两个值能够叫作日志文件坐标(log file coordinate),由于它们肯定了一个二进制日志的位置,你能够用SHOW MASTER STATUS命令找到日志文件的坐标;
(3)master的二进制日志文件。
能够经过如下几中方法来克隆一个slave:
(1) 冷拷贝(cold copy)
中止master,将master的文件拷贝到slave;而后重启master。缺点很明显。
(2) 热拷贝(warm copy)
若是你仅使用MyISAM表,你可使用mysqlhotcopy拷贝,即便服务器正在运行。
(3) 使用mysqldump
使用mysqldump来获得一个数据快照可分为如下几步:
<1>锁表:若是你尚未锁表,你应该对表加锁,防止其它链接修改数据库,不然,你获得的数据能够是不一致的。以下:
mysql> FLUSH TABLES WITH READ LOCK;
< 2>在另外一个链接用mysqldump建立一个你想进行复制的数据库的转储:
shell> mysqldump --all-databases --lock-all-tables >dbdump.db
< 3>对表释放锁。
mysql> UNLOCK TABLES;
已经讨论了关于复制的一些基本东西,下面深刻讨论一下复制。
MySQL 5.0及以前的版本仅支持基于语句的复制(也叫作逻辑复制,logical replication),这在数据库并不常见。master记录下改变数据的查询,而后,slave从中继日志中读取事件,并执行它,这些SQL语句与master执行的语句同样。
这种方式的优势就是实现简单。此外,基于语句的复制的二进制日志能够很好的进行压缩,并且日志的数据量也较小,占用带宽少——例如,一个更新GB的数据的查询仅须要几十个字节的二进制日志。而mysqlbinlog对于基于语句的日志处理十分方便。
可是,基于语句的复制并非像它看起来那么简单,由于一些查询语句依赖于master的特定条件,例如,master与slave可能有不一样的时间。因此,MySQL的二进制日志的格式不只仅是查询语句,还包括一些元数据信息,例如,当前的时间戳。即便如此,仍是有一些语句,好比,CURRENT USER函数,不能正确的进行复制。此外,存储过程和触发器也是一个问题。
另一个问题就是基于语句的复制必须是串行化的。这要求大量特殊的代码,配置,例如InnoDB的next-key锁等。并非全部的存储引擎都支持基于语句的复制。
MySQL增长基于记录的复制,在二进制日志中记录下实际数据的改变,这与其它一些DBMS的实现方式相似。这种方式有优势,也有缺点。优势就是能够对任何语句都能正确工做,一些语句的效率更高。主要的缺点就是二进制日志可能会很大,并且不直观,因此,你不能使用mysqlbinlog来查看二进制日志。
对于一些语句,基于记录的复制可以更有效的工做,如:
mysql> INSERT INTO summary_table(col1, col2, sum_col3)
-> SELECT col1, col2, sum(col3)
-> FROM enormous_table
-> GROUP BY col1, col2;
假设,只有三种惟一的col1和col2的组合,可是,该查询会扫描原表的许多行,却仅返回三条记录。此时,基于记录的复制效率更高。
另外一方面,下面的语句,基于语句的复制更有效:
mysql> UPDATE enormous_table SET col1 = 0;
此时使用基于记录的复制代价会很是高。因为两种方式不能对全部状况都能很好的处理,因此,MySQL 5.1支持在基于语句的复制和基于记录的复制以前动态交换。你能够经过设置session变量binlog_format来进行控制。
除了二进制日志和中继日志文件外,还有其它一些与复制相关的文件。以下:
服务器一旦开启二进制日志,会产生一个与二日志文件同名,可是以.index结尾的文件。它用于跟踪磁盘上存在哪些二进制日志文件。MySQL用它来定位二进制日志文件。它的内容以下(个人机器上):
该文件的功能与mysql-bin.index相似,可是它是针对中继日志,而不是二进制日志。内容以下:
.\mysql-02-relay-bin.000017
.\mysql-02-relay-bin.000018
保存master的相关信息。不要删除它,不然,slave重启后不能链接master。内容以下(个人机器上):
I/O线程更新master.info文件,内容以下(个人机器上):
.\mysql-02-relay-bin.000019 254 mysql-01-bin.000010 286 0 52813 |
包含slave中当前二进制日志和中继日志的信息。
当设置log_slave_updates时,你可让slave扮演其它slave的master。此时,slave把SQL线程执行的事件写进行本身的二进制日志(binary log),而后,它的slave能够获取这些事件并执行它。以下:
复制过滤可让你只复制服务器中的一部分数据,有两种复制过滤:在master上过滤二进制日志中的事件;在slave上过滤中继日志中的事件。以下:
复制的体系结构有如下一些基本原则:
(1) 每一个slave只能有一个master;
(2) 每一个slave只能有一个惟一的服务器ID;
(3) 每一个master能够有不少slave;
(4) 若是你设置log_slave_updates,slave能够是其它slave的master,从而扩散master的更新。
MySQL不支持多主服务器复制(Multimaster Replication)——即一个slave能够有多个master。可是,经过一些简单的组合,咱们却能够创建灵活而强大的复制体系结构。
由一个master和一个slave组成复制系统是最简单的状况。Slave之间并不相互通讯,只能与master进行通讯。以下:
若是写操做较少,而读操做很时,能够采起这种结构。你能够将读操做分布到其它的slave,从而减少master的压力。可是,当slave增长到必定数量时,slave对master的负载以及网络带宽都会成为一个严重的问题。
这种结构虽然简单,可是,它却很是灵活,足够知足大多数应用需求。一些建议:
(1) 不一样的slave扮演不一样的做用(例如使用不一样的索引,或者不一样的存储引擎);
(2) 用一个slave做为备用master,只进行复制;
(3) 用一个远程的slave,用于灾难恢复;
Master-Master复制的两台服务器,既是master,又是另外一台服务器的slave。如图:
主动的Master-Master复制有一些特殊的用处。例如,地理上分布的两个部分都须要本身的可写的数据副本。这种结构最大的问题就是更新冲突。假设一个表只有一行(一列)的数据,其值为1,若是两个服务器分别同时执行以下语句:
在第一个服务器上执行:
mysql> UPDATE tbl SET col=col + 1;
在第二个服务器上执行:
mysql> UPDATE tbl SET col=col * 2;
那么结果是多少呢?一台服务器是4,另外一个服务器是3,可是,这并不会产生错误。
实际上,MySQL并不支持其它一些DBMS支持的多主服务器复制(Multimaster Replication),这是MySQL的复制功能很大的一个限制(多主服务器的难点在于解决更新冲突),可是,若是你实在有这种需求,你能够采用MySQL Cluster,以及将Cluster和Replication结合起来,能够创建强大的高性能的数据库平台。可是,能够经过其它一些方式来模拟这种多主服务器的复制。
这是master-master结构变化而来的,它避免了M-M的缺点,实际上,这是一种具备容错和高可用性的系统。它的不一样点在于其中一个服务只能进行只读操做。如图:
这种结构的优势就是提供了冗余。在地理上分布的复制结构,它不存在单一节点故障问题,并且还能够将读密集型的请求放到slave上。