复制是基于master server 跟踪数据库的所有改变(更新,删除等) 记录到它的binary log里
binary log 记录了所有对于数据库结构或者数据库内容的修改
典型的,SELECT 语句是不记入的 因为它们没有修改数据库的结构和内容。
每个slave 连接到master 请求一个binary log的拷贝。 slave从master 拉数据,碧昂比master 推送数据到slave
slave 也执行它接收的bianry log里的events.
这个影响了原始的改变 (有Master 产生),表被创建或者结构被修改,数据被插入,删除
因为每个slave是单独的,从master的binary log 在slave上重现在每个slave上是单独,
额外的,因为每个slave 接收到一份binary log的拷贝通过master,slave 可以读取和更新数据库的copy
它自己可以起到和停止复制进程不影响更新最新的数据库状态无论是master还是slave
Masters和slaves 显示它们的状态关于复制的进程 因此你可以监控它们
master的binary log 是写入到slave本地的relay log 在它被处理前。
slave 也记录关于master的binary log的当前位置 和本地的relay log
数据库改变在slave上过滤
17.2.1 Replication Implementation Details
MYSQL 复制功能是石油3个线程实现,一个在master上 另外2个在slave上:
1.Binlog dump thread
master 创建一个线程来发送binary log 内容到slave当slave连接的时候,
这个线程可以在SHOW PROCESSLIST 中看到Binlog dump线程:
mysql> SHOW PROCESSLIST ;
+——-+————+———————-+——–+————-+——–
+———————————————————————–+——————+
| Id | User | Host | db | Command | Time | State
| Info |
+——-+————+———————-+——–+————-+——–
+———————————————————————–+——————+
| 18028 | zjzc_app | 192.168.33.29:54537 | NULL | Sleep | 165 |
| NULL |
| 18029 | zjzc_app | 192.168.33.29:54538 | NULL | Sleep | 165 |
| NULL |
| 24555 | root | 192.168.33.19:59398 | zjzc | Sleep | 270 |
| NULL |
| 24556 | root | 192.168.33.19:59399 | zjzc | Sleep | 270 |
| NULL |
| 27052 | zjzc_app | 192.168.33.11:13485 | NULL | Sleep | 404 |
| NULL |
| 27053 | zjzc_app | 192.168.33.11:13486 | NULL | Sleep | 404 |
| NULL |
| 29686 | backup | 192.168.32.116:46587 | NULL | Binlog Dump | 262963 | Master has sent all
binlog to slave; waiting for binlog to be updated | NULL |
| 30470 | quartz_app | 192.168.32.170:49519 | quartz | Sleep | 65 |
| NULL |
| 30471 | quartz_app | 192.168.32.170:49520 | quartz | Sleep | 5 |
| NULL |
| 30868 | quartz_app | 192.168.32.170:50324 | quartz | Sleep | 65 |
| NULL |
| 30869 | quartz_app | 192.168.32.170:50325 | quartz | Sleep | 5 |
| NULL |
| 38431 | zjzc_app | 192.168.32.170:37808 | zjzc | Sleep | 3 |
| NULL |
| 38432 | zjzc_app | 192.168.32.170:37809 | zjzc | Sleep | 3 |
| NULL |
| 38433 | zjzc_app | 192.168.32.170:37811 | zjzc | Sleep | 3 |
| NULL |
| 38434 | zjzc_app | 192.168.32.170:37812 | zjzc | Sleep | 3 |
| NULL |
| 38435 | root | localhost | NULL | Query | 0 | init
| SHOW PROCESSLIST |
+——-+————+———————-+——–+————-+——–
+———————————————————————–+——————+
16 rows in set (0.02 sec)
binary log dump 线程需要一个锁在master的binary log拥堵读取发送到slave的event
当event 被读取后, lock被释放
2.Slave I/O thread 当START SLAVE语句在slave server上执行后,slave 创建一个I/O thread,
用于连接master ,告诉master 发送binary logs 的更新记录。
slave I/O thread 读取master的Binlog Dump 的更改 ,把它们复制到本地文件(slave的relay log)
relay-log日志记录的是从服务器I/O线程将主服务器的二进制日志读取过来记录到从服务器本地文件,然后SQL线程
会读取relay-log日志的内容并应用到从服务器.
这个线程的状态是通过Slave_IO_running显示在SHOW SLAVE STATUS的输出夅
3.Slave SQL thread
slave 创建一个SQL thread 来读取relay log ,由slave I/O thread 写入,执行里面的events
在前面的描述里,每个master/slave连接有3个线程。一个master有多个slaves的创建一个binary log dump thread
为每个连接的slave,每个slave有它自己的I/O 和SQL threads
一个slave使用2个threads 从master来分散度写,用单独的任务执行它们。
因此, 读语句的任务不会慢下来 如果语句执行是慢的。比如,如果 slave server 有一段时间没有运行,
它的I/O thread 可以很快的从master取得所有的binary log 内容,当slave运行的时候,
尽管SQL thread远远落后. 如果在SQL thread 已经执行了所有的获取的语句前停止slave,
I/O thread 已经至少获取了自从一个安全的语句的拷贝 存储在本地的slave的relay log中,
当下次slave 启动的时候执行。
SHOW PROCESSLIST 语句提供了信息告诉你 master上发生了什么 和 slave的复制。
下面的例子阐释了在SHOW PROCESSLIST中的3个线程
在master上,SHOW PROCESSLIST 输出如下:
mysql> SHOW PROCESSLIST\G
***************** 1. row *****************
Id: 2
User: root
Host: localhost:32931
db: NULL
Command: Binlog Dump
Time: 94
State: Has sent all binlog to slave; waiting for binlog to
be updated
Info: NULL
这里, thread 2 是一个Binlog Dump 复制thread 用于slave的连接。 State信息表明了 所有的updates已经发送到
了slave
master在等待更多的updates发生。如果你没有看到Binlog Dump threads 在master server上,这意味着复制没有运
行
也就是是没有slave 当前在连接
***************** 10. row *****************
Id: 855318
User: backup
Host: dr-mysql01.zjcap.com:42858
db: NULL
Command: Binlog Dump
Time: 328260
State: Master has sent all binlog to slave; waiting for binlog to be updated
Info: NULL
Slave的输出:
mysql> SHOW PROCESSLIST\G
***************** 1. row *****************
Id: 10
User: system user
Host:
db: NULL
Command: Connect
Time: 11
State: Waiting for master to send event
Info: NULL
***************** 2. row *****************
Id: 11
User: system user
Host:
db: NULL
Command: Connect
Time: 11
State: Has read all relay log; waiting for the slave I/O
thread to update it
Info: NULL
状态信息表明了thread 10是I/O thread 正在连接到master server,thread 11
是SQL thread 在处理存储在relay logs里的更新。
Time列的值表明 slave相比master 多晚了 。
如果足够的时间消耗在master这边 没有Binlog dump thread 上激活,
master 决定slave 没有在连接了。
至于其他的客户端连接,超时由net_write_timeout and net_retry_count决定;
17.2.2 Replication Relay and Status Logs
复制的Relay 和Status logs
在复制阶段,一个slave server 创建了多个日志用于保存binary log的events
在master和slave之间传递, 记录了关于当前状态和位置的信息在relay log.
这里有3种类型的日志,如下:
1.relay log 有从matser的binary log 读取的事件组成通过slave I/O thread.
在relay log 里的events 被SQL thread执行
- master info log 包含状态和当前的配置信息用于slave的连接到master.
这些logs 包含里master 的主机名,登入认证和日志的位置 表明多久slave 从master读取binary log
MySQL 5.6之前,这个log 总是在master.info里,但是在Mysql 5.6和以后版本,log信息可以写入到
mysql.slave_master_info table
代替文件,通过–master-info-repository=TABLE启动
3.relay log info 日志记录了slave 的relay log的执行点信息
在5.6版本前, 这个日志总是写在relay-log.info里,但是在5.6以后版本,这些日志可以写到
mysql.slave_relay_log_info t
在5.6.7版本前, slave_master_info and slave_relay_log_info tables 的Master_id列,表明了
slave的server ID 有master的server ID代替。
Crash-safe 复制: 为了用于复制可以实现crash-safe必须使用表用于记录状态和relay信息,
这些表必须是一个事务型的引擎 比如InnoDB
因此,为了强制在slave上实现crasg safety 你必须运行启用–relay-log-recovery,除了设置–relay-log-info-
repository to TABLE
在MySQL 5.6.6之前的版本,如果mysqld 不能初始化复制logging tables,slave拒绝启动。
在Mysql 5.6.6以后,会给出一个warning,但是slave 被允许继续执行
这种情况最有可能发生在 升级了MySQL的版本 不支持slave logging tables 到支持slave logging tables
17.2.2.1 The Slave Relay Log
salve的Relay log
relay log, 像binary log,由一组编号包含描述数据库变化事件的文件
一个index 文件包含了所有使用的relay log files
术语 ‘relay log file’ 通常表示一个单独的文件包含数据库的events.
这个术语”relay log”总的来说表示编号的中继日志文件的设置加上索引文件
Relay log 文件和binary log 文件有相同的格式可以用mysqlbinlog 读取
默认的,relay log file 命名是以host_name-relay-bin.nnnnnn 格式在数据目录下,
where host_name 是slave server 的名字 ,nnnnn是sequence 号。连续的relay log 文件
是创建使用连续的sequence numbers,以00001开始。slave使用一个index file 来跟踪当前使用的relay log
files.
默认的relay log 索引文件是host_name-relay-bin.index 在数据目录
默认的relay log 文件和relay log 索引文件可以被覆盖 ,分别的
the –relay-log and –relay-log-index server options
如果一个slave使用默认的host-bases relay log 文件名,改变slave的host name 在复制已经设立后
会导致复制失败 报 Failed to open the relay log and Could not find target log during relay log
initialization。
这是一个已知的问题, 如果你预期 一个slave的主机名可能将来改变(比如,如果networking 被实在在slave上,
salve的主机名可以被修改) 你可以完全避免这个问题使用–relay-log和–relay-log-index 选项
来指定relay log 文件。
如果你遇到复制已经开始,一个方式是停止slave server,预先把老的文件的文件写到写的文件,然后重启slave
在Unix系统上,你可以这么做:
shell> cat new_relay_log_name.index >> old_relay_log_name.index
shell> mv old_relay_log_name.index new_relay_log_name.index
slave server 创建一个新的relay log文件在下面的条件:
- I/O thread 每次启动时
2.当日志被flushed,比如 用FLUSH LOGS or mysqladmin flush-logs.
3.当前的relay log 变的太大了,有下面的参数决定:
mysql> show variables like ‘%max_relay_log_size%’;
+——————–+——-+
| Variable_name | Value |
+——————–+——-+
| max_relay_log_size | 0 |
+——————–+——-+
1 row in set (0.00 sec)
1.如果max_relay_log_size值大于0,这就是relay log 的最大值
2.max_relay_log_size is 0,max_binlog_size 决定了relay log 文件的最大值
mysql> show variables like ‘%max_binlog_size%’;
+—————–+———–+
| Variable_name | Value |
+—————–+———–+
| max_binlog_size | 536870912 |
+—————–+———–+
1 row in set (0.00 sec)
SQL thread 自动的删除每个relay log file 只要它已经被执行,不再需要
没有明确的机制用于删除relay log
17.2.2.2 Slave Status Logs
Slave 状态日志:
一个复制的slave server 创建2个日志,默认的.这些文件被命名为master.info和relay-log.info
在数据目录下,名字和位置可以通过–master-info-file and –relay-log-info-file 改变。
分别的,在MySQL 5.6以后,这两种日志都可以写入到数据库通过在启动的时候带上相应的选项:
使用 –master-info-repository 把master info 的日志信息写入到mysql.slave_master_info
使用–relay-log-info-repository 把relay log 写人到mysql.slave_relay_log_info table。
两种状态日志包含了SHOW SLAVE STATUS语句输出的信息, 因为状态日志 存储在磁盘上,
他们存在于一个slave的关闭。 下次slave 启动后,它读取两个日志来确定 从master多久没读binary log了
和处理它自己的relay logs
master info log 文件或者表 必须被保护,因为它包含了密码用于连接到master
slave I/O thread 更新master info log,下面的表格显示了相应的master.info文件的信息
and the columns displayed by SHOW SLAVE STATUS.
SHOW SLAVE STATUS Column Description
Master_Log_File 当前读取master的binary log的名字
Read_Master_Log_Pos 从master读取的binary log 当前的position
Master_Host master的host name(IP地址)
Master_User 用于连接master的user name
Master_Port 连接到master的端口
Connect_Retry 周期(单位秒) slave会等待在尝试重新连接到master 前
slave的SQL thread 更新relay log info 日志,在Mysql 5.6中,relay-log.info 文件包括了一行统计和复制延迟的
值
通过show slave status:显示
SHOW SLAVE STATUS Column Description
Relay_Log_File 当前的relay log 文件名字
Relay_Log_File: mysqld-relay-bin.000005
Relay_Log_Pos relay log 文件当前的位置, 到这个点之前的events都是已经在slave上
执行了
Relay_Master_Log_File master的binary log 文件的名字
5.6之前的版本 relay-log.info 文件不包含一行统计或者延时值
注意:
如果你下载的slave server 的标本比5.6早,老版本不支持直接读取relay-log.info
relay-log.info文件的内容和状态 可以通过SHOW SLAVE STATUS 语句可能不能匹配
如果 relay-log.info 没有被刷新到磁盘,最理想的是,你可以查看relay-log.info在一个slaves上(slave是offline
的,
mysqld没有运行)
对于一个运行的系统,你可以使用SHOW SLAVE STATUS,或者查看slave_master_info and slave_relay_log_info
tables
17.2.3 How Servers Evaluate Replication Filtering Rules
server 如何评估复制过滤规则:
如果master server 不把语句写入到它的binary log,语句就不会被复制。如果server 记录了语句,语句会发送到
所有的slaves 每个salves 有权决定是执行还是忽略它
在master上,你可以通过设置 –binlog-do-db and –binlog-ignore-db选项来控制binary 的记录。
你不能使用这些选项来控制 哪个数据库和表被复制,代替的是,在slave上使用过滤来控制被执行的events
在slave这边,是否决定执行或者忽略接收到的语句是根据–replicate-*选项,在slave 启动的时候
在最简单的情况下,当这里没有–replicate-*选项,slave执行它从master接收到的所有的语句。否则,结果取决于特
定的选项.
数据库级别的选项是(–replicate-do-db, –replicate-ignore-db) 首选被核对:
为了让他更加简单的确定哪个选项是生效的,推荐避免混合”do” 和”ignore”选项,或者
通配和非通配选项。
如果任何的–replicate-rewrite-db 选项是指定的,它们在–replicate-* 过滤规则前
注意:
在MySQL 5.6,所有的复制过滤选项遵循相同的规则 对于case 灵敏度,应用的数据库或者表的名字 包括
lower_case_table_names变量
17.2.3.1 Evaluation of Database-Level Replication and Binary Logging Options
评估数据库级别复制和binary log 选项
当评估复制选项时,slave 开始通过检查 是否有应用 –replicate-do-db or –replicate-ignore-db选项
当使用–binlog-do-db or –binlog-ignore-db,处理时类似的,但是选项时在master上
在基于语句的复制,默认的数据库被检查是否匹配。
在基于行的复制,数据库哪里改变会被检查
不管binary logging格式,数据库选项的检查进行如下:
步骤涉及如下:
- 是否有–replicate-do-db 选项?
Yes. Execute the statement and exit.
No. Ignore the statement and exit.
No. Continue to step 2.
2.是否有–replicate-ignore-db 选项?
Yes. Do any of them match the database?
Yes. Ignore the statement and exit.
No. Continue to step 3.
No. Continue to step 3.
继续检查table-level 复制选项,如果有
注意:
一个语句仍旧被允许在这个阶段没有实际执行,语句没有被执行直到所有的table-level选项
都被检查
17.2.3.2 Evaluation of Table-Level Replication Options
评估Table-Level 复制选项:
slave检查和评估表选项 只有当下面2个条件都成立:
- 没有匹配的数据库选项
2.一个或者多个选项被发现,被评估到达一个执行的条件
首先,作为初步条件, slave检查是否是statement-based的复制,如果是,
语句执行在一个存储函数里,slave执行语句然后退出。
如果是row-based复制被启用,slave不知道是否一个发生在存储过程里在master上,
因此这种条件不执行。
注意:
对于statement-based的复制,复制的事件表现为语句(所有的变化做了一个特定的事件,都与一个单一的SQL语句关联
)
对于row-based replication,每个事件是在一个单一的表记录的变化
(因此一个简单的语句 比如UPDATE mytable SET mycol = 1可能产生很多个row-based events)
17.2.3.3 Replication Rule Application
复制规则实现:
这个章节提供了额外的解释和例子 使用不同的复制过滤选项的不同组合
一些典型的选项如下:
Condition (Types of Options) 结果
No –replicate-* options at all 执行所有的evnets 从master接收到的
–replicate-*-db options, but no table options: slave接收或者忽略事件使用database 选项。
它执行所有那些选项允许的events ,因为这里有
表限制
更加复杂的例子如下,我们检查结果用于 both statement-based and row-based
假设 我们有2个表mytbl1 in database db1 and mytbl2 in database db2在Master上,
slave运行在下面的选项
replicate-ignore-db = db1
replicate-do-table = db2.tbl2
放我们执行下面的语句在master上
USE db1;
INSERT INTO db2.tbl2 VALUES (1);
结果在slave上,有很大的不同依赖binary log格式,可能不匹配在任何情况下,最初的期望。
Statement-based replication USE 语句导致db1 是默认的数据库。 因此
–replicate-ignore-db 选项匹配了, INSERT语句被忽略 表选项不会被检查
Row-based replication