Mysql主从复制总结

来源:互联网 发布:cnki数据库在哪找 编辑:程序博客网 时间:2024/06/06 04:04
1.Replication 线程
   Mysql的 Replication 是一个异步的复制过程,从一个 Mysql instace(我们称之为 Master)复制到另一个 Mysql instance(我们称之 Slave)。在 Master 与 Slave 之间的实现整个复制过程主要由三个线程来完成,其中两个线程(Sql线程和IO线程)在 Slave 端,另外一个线程(IO线程-binlog dump线程)在 Master 端。
  MySQL 复制的基本过程如下:
  1. Slave 上面的IO线程连接上 Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;
   2. Master 接收到来自 Slave 的 IO 线程的请求后,通过负责复制的 IO 线程根据请求信息读取指定日志指定位置之后的日志信息,返回给 Slave 端的 IO 线程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息在 Master 端的 Binary Log 文件的名称以及在 Binary Log 中的位置;
  3. Slave 的 IO 线程接收到信息后,将接收到的日志内容依次写入到 Slave 端的Relay Log文件(mysql-relay-bin.xxxxxx)的最末端,并将读取到的Master端的bin-log的文件名和位置记录到master- info文件中,以便在下一次读取的时候能够清楚的高速Master“我需要从某个bin-log的哪个位置开始往后的日志内容,请发给我”
   4. Slave 的 SQL 线程检测到 Relay Log 中新增加了内容后,会马上解析该 Log 文件中的内容成为在 Master 端真实执行时候的那些可执行的 Query 语句,并在自身执行这些 Query。这样,实际上就是在 Master 端和 Slave 端执行了同样的 Query,所以两端的数据是完全一样的。
  实际上,在老版本中,MySQL 的复制实现在 Slave 端并不是由 SQL 线程和 IO 线程这两个线程共同协作而完成的,而是由单独的一个线程来完成所有的工作。

=====================================

2 .复制配置

有两台MySQL数据库服务器Master和slave,Master为主服务器,slave为从服务器,初始状态时,Master和slave中的数据信息相同,当Master中的数据发生变化时,slave也跟着发生相应的变化,使得master和slave的数据信息同步,达到备份的目的。

要点:
负责在主、从服务器传输各种修改动作的媒介是主服务器的二进制变更日志,这个日志记载着需要传输给从服务器的各种修改动作。因此,主服务器必须激活二进制日志功能。从服务器必须具备足以让它连接主服务器并请求主服务器把二进制变更日志传输给它的权限。
        
环境:
Master和slave的MySQL数据库版本同为5.0.18
操作系统:unbuntu 11.10
IP地址:10.100.0.100

2.1、创建复制帐号

1、在Master的数据库和slave数据库中建立一个备份帐户:每个slave使用标准的MySQL用户名和密码连接master。进行复制操作的用户会授予REPLICATION SLAVE权限。

mysql > GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO backup@’10.100.0.*’ IDENTIFIED BY ‘123456’;
命令如下:注意我们把这个账户限制在本地网络,因为这是一个特权账号(尽管该账号无法使用select或者修改数据,但是任然能从二进制日志中获得一些数据)。

(如果因为mysql版本新旧密码算法不同,可以设置:set password for 'backup'@'10.100.0.200'=old_password('1234'))

2.2、拷贝数据

(假如是你完全新安装mysql主从服务器,这个一步就不需要。因为新安装的master和slave有相同的数据

关停Master服务器,将Master中的数据拷贝到B服务器中,使得Master和slave中的数据同步,并且确保在全部设置操作结束前,禁止在Master和slave服务器中进行写操作,使得两数据库中的数据一定要相同!

2.3、配置master

接下来对master进行配置,包括打开二进制日志,指定唯一的servr ID。例如,在配置文件加入如下值:

server_id=64log_bin=mysql-bin

server_id:为master的ID值
log_bin:二进制变更日值

注意:master和slave的id值必须不一样(可以取ip的后8位数字或者最后一段)

重启master,运行SHOW MASTER STATUS,输出如下:

2.4、配置slave

Slave的配置与master类似,你同样需要重启slave的MySQL。如下:
log_bin           = mysql-binserver_id         = 41relay_log         = mysql-relay-binlog_slave_updates = 1read_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上创建表的应用。

2.5、启动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

slaveI/OSQL线程都已经开始运行,而且Seconds_Behind_Master不再是NULL。日志的位置增加了,意味着一些事件被获取并执行了。如果你在master上进行修改,你可以在slave上看到各种日志文件的位置的变化,同样,你也可以看到数据库中数据的变化。

你可查看masterslave上线程的状态。在master上,你可以看到slaveI/O线程创建的连接:

在master上:
mysql> show processlist \G*************************** 1. row ***************************     Id: 1   User: root   Host: localhost:2096     db: testCommand: Query   Time: 0 State: NULL   Info: show processlist*************************** 2. row ***************************     Id: 2   User: repl   Host: localhost:2144     db: NULLCommand: Binlog Dump   Time: 1838 State: Has sent all binlog to slave; waiting for binlog to be updated   Info: NULL2 rows in set (0.00 sec)
行2为处理slave的I/O线程的连接。

在slave上:

mysql> show processlist \G*************************** 1. row ***************************     Id: 1   User: system user   Host:     db: NULLCommand: Connect   Time: 2291 State: Waiting for master to send event   Info: NULL*************************** 2. row ***************************     Id: 2   User: system user   Host:     db: NULLCommand: 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: testCommand: Query   Time: 0 State: NULL   Info: show processlist3 rows in set (0.00 sec)
行1为I/O线程状态,行2为SQL线程状态。

2.5、添加新slave服务器

假如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;

3、深入了解复制

已经讨论了关于复制的一些基本东西,下面深入讨论一下复制。

3.1、基于语句的复制(Statement-Based Replication)

     MySQL 5.0及之前的版本仅支持基于语句的复制(也叫做逻辑复制,logical replication),这在数据库并不常见。master记录下改变数据的查询,然后,slave从中继日志中读取事件,并执行它,这些SQL语句与master执行的语句一样。
这种方式的优点就是实现简单。此外,基于语句的复制的二进制日志可以很好的进行压缩,而且日志的数据量也较小,占用带宽少——例如,一个更新GB的数据的查询仅需要几十个字节的二进制日志。而mysqlbinlog对于基于语句的日志处理十分方便。
 
      但是,基于语句的复制并不是像它看起来那么简单,因为一些查询语句依赖于master的特定条件,例如,master与slave可能有不同的时间。所以,MySQL的二进制日志的格式不仅仅是查询语句,还包括一些元数据信息,例如,当前的时间戳。即使如此,还是有一些语句,比如,CURRENT USER函数,不能正确的进行复制。此外,存储过程和触发器也是一个问题。
     另外一个问题就是基于语句的复制必须是串行化的。这要求大量特殊的代码,配置,例如InnoDB的next-key锁等。并不是所有的存储引擎都支持基于语句的复制。

3.2、基于记录的复制(Row-Based Replication)

      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来进行控制。

3.3、复制相关的文件

除了二进制日志和中继日志文件外,还有其它一些与复制相关的文件。如下:

(1)mysql-bin.index

服务器一旦开启二进制日志,会产生一个与二日志文件同名,但是以.index结尾的文件。它用于跟踪磁盘上存在哪些二进制日志文件。MySQL用它来定位二进制日志文件。它的内容如下(我的机器上):

(2)mysql-relay-bin.index

该文件的功能与mysql-bin.index类似,但是它是针对中继日志,而不是二进制日志。内容如下:
.\mysql-02-relay-bin.000017
.\mysql-02-relay-bin.000018

(3)master.info

保存master的相关信息。不要删除它,否则,slave重启后不能连接master。内容如下(我的机器上):

 I/O线程更新master.info文件,内容如下(我的机器上):

 

.\mysql-02-relay-bin.000019

254

mysql-01-bin.000010

286

0

52813

(4)relay-log.info 

包含slave中当前二进制日志和中继日志的信息。

./mysqld-relay-bin.001873 <- Relay_Log_File
11944 <- Relay_Log_Pos
mysql-bin.000211 <- Relay_Master_Log_File
29301 <- Exec_Master_Log_Pos
 


relay-log.info, master.info 这连个文件时在建立复制时产生的,现在主要说明以下问题:

1、如果修改删除master.info文件,复制会中断么?

不会,如果stop slave,然后start slave还是能正常启动起来,因为mysql已经记住这里面的信息了,但是当你重启mysql时,在start slave,这时重启失败,会提示你change  master to

2、master.info是在什么时候写入的呢?

change master to ..其他时候该文件不会被修改也不会被读取(重启除外).


3、relay-log.info 这个文件只有在重启时会被读取,但是只要这个文件存在存在,有数据写入,他就会变化;如果删除这个文件对复制也没有影响(重启除外),

一般情况主从切换后,需要reset slave,清除relay-log.info。 
mysql service 重启时或者再次start slave需要读取其中的信息,作为change master to 依据

====================================

以下列出了slave的I/O线程 State 字段中最常见的几种状态。从MySQL 4.1.1开始,这个状态在执行 SHOW SLAVE STATUS 语句结果的 Slave_IO_State 字段也会出现。这意味着可以只执行 SHOW SLAVE STATUS 语句就能了解到更多的信息。

Connecting to master
该线程证尝试连接到master上。
Checking master version
确定连接到master后出现的一个短暂的状态。
Registering slave on master
确定连接到master后出现的一个短暂的状态。
Requesting binlog dump
确定连接到master后出现的一个短暂的状态。该线程向master发送一个请求,告诉它要请求的二进制文件以及开始位置。
Waiting to reconnect after a failed binlog dump request
如果二进制日志转储(binary log dump)请求失败了(由于连接断开),该线程在休眠时进入这个状态,并定期重连。重连的时间间隔由 --master-connect-retry 选项来指定。
Reconnecting after a failed binlog dump request
该线程正尝试重连到master。
Waiting for master to send event
已经连接到master,正等待它发送二进制日志。如果master闲置时,这个状态可能会持续较长时间,如果它等待超过slave_read_timeout 秒,就会发生超时。这时,它就会考虑断开连接,然后尝试重连。
Queueing master event to the relay log
已经读取到一个事件,正把它拷贝到中继日志中以备SQL线程处理。
Waiting to reconnect after a failed master event read
读日志时发生错误(由于连接断开)。该线程在重连之前休眠 master-connect-retry 秒。
Reconnecting after a failed master event read
正尝试重连到master。当连接确定后,状态就变成 Waiting for master to send event
Waiting for the slave SQL thread to free enough relay log space
relay_log_space_limit 的值非零,中继日志的大小总和超过这个值了。I/O线程等待SQL线程先处理中继日志然后删除它们以释放足够的空间。
Waiting for slave mutex on exit
当前线程停止了,这个时间很短。

以下列出了slave的SQL线程 State 字段中最常见的几种状态:

Reading event from the relay log
从中继日志里读到一个事件以备执行。
Has read all relay log; waiting for the slave I/O thread to update it
已经处理完中继日志中的全部事件了,正等待I/O线程写入更新的日志。
Waiting for slave mutex on exit
当前线程停止了,这个时间很短。

SQL线程的 State 字段有时候也可能是一个SQL语句。这意味着它从中继日志中读取到一个事件了,从中提取出SQL语句,并执行它。

0 0