基于行的复制
好处:
实现简单
在多种方式下都能够正常工作,因为本质是重放sql语句
更加灵活,例如可以在备库上修改schema然后提升为主库
更容易debug,因为执行的语句是人可以看懂的
坏处:
很多是不能重放得,使用触发器和存储过程无法正常运行,一些和当时的环境相关的函数无法正常运行
运行只能串行,需要更多的锁,性能不好
基于语句的复制
好处
几乎没有行不能适应的模式,但是修改schema的时候可能失效
性能好,锁的使用少,无需串行化
数据更新记录更加彻底,可以看到sql语句不知道的更新细节
占用很少的CPU相比逻辑复制
基于行的复制能够更快的找到数据不一致的情况
坏处
全表更新的数据会出发大量的行,增加复制的负担
无法判断执行了哪些sql,执行方式是黑盒的
无法处理在备库修改schema的情况,但是逻辑复制可以
MySQL自动切换两种方式的使用,默认的使用基于语句的方式,如果无法正确的复制的话,就切换到基于行的模式
可以自己控制两种方式,使用binglog_format变量来控制
数据分布
负载均衡
备份
高可用和故障切换
Mysql升级测试
主库把数据变更记录到二进制日志中(在事务提交之前) --> binlog
备库将主库上的日志复制到自己的中继日志中(备库启用一个IO线程,连接到主库然后读取二进制日志并转储到中继日志) --> Relay log
备库读取中继日志中的事件,将其重放到备库数据之上(备库的SQL线程读取自己的中继日志并运行SQL)
实现了获取和重放事件的解耦,允许这两个过程异步运行;
限制了复制的过程,主库上并发运行的事件在从库上只能串行化执行,因为只有一个线程来重放中继日志的事件
在每台服务器上创建复制账号;
配置主库和备库;
通知备库链接到主库并从主库复制数据
使用冷备份(关闭服务器,复制数据文件然后启用从库)
使用热备份(MyISAM -- 使用mysqlhotcopy或者rsync来复制数据)
使用mysqldump
mysqldump -- single-transaction --all-databases --master-data=1 --host=server1 | mysql --host=server2
使用快照或者备份(知道对应的二进制坐标就可以使用备份+二进制坐标的方式来重放)
使用percona xtrabackup
使用其他的备库
不要使用load data from master / load table from master
,过时、缓慢、容易出错而且只能用于MyISAM
sync_binlog=1 开启这个选项,在每次提交事务之前将二进制日志同步到磁盘,如果不开启的话,可能在崩溃的时候二进制日志损坏导致不能正确的复制数据(适用于二进制日志,中继日志没必要);
innodb_flush_logs_at_trx_commit
提交事务之前刷新日志到磁盘
innodb_support_xa=1 or innodb_safe_binlog
log_bin=/xx/xx/mysql-bin 强制指定二进制日志的名字,不然是用服务器的名字来命名二进制日志的,在迁移和备份的时候会有很多问题;
relay_log=/xx/xx/relay-bin 强制指定中继日志的名字,防止很多问题
skip_slave_start 在崩溃后不要自己启动复制,因为这时候数据已经不一致了,强制启动只会导致更复杂的结果
read_only 关闭写权限,防止意外的修改从库导致的数据不一致
sync_master_info=1 sync_relay_log=1 sync_relay_log_info=1 防止msterinfo和中继日志在服务器崩溃时候的损坏(有fsync()开销
relay_log_space_limit (如果主库和备库的差距非常大中继日志可能会很大,大到磁盘爆满,所以可以开启这个来防止备库的磁盘爆满)
expire_log_days 过期二进制日志(不要手工删除日志,不然可能清理日志的命令不能正常工作)
在主库上记录二进制日志,在从库上重放日志的方式来实现异步的数据复制 ==> 意味着从库的数据可能和主库不一致,存在延迟
mysql-bin.index 记录了所有的二进制文件
mysql-relay-bin-index 记录了所有中继日志文件
master.info 保存备库连接到主库的所有信息,密码之类的
relay-log.info 记录了当前备库复制的二进制日志和中继日志的坐标
log_slave_updates让备库变成其他服务器的主库
注意所有服务器必须有一个唯一的ID,不然会导致循环复制
主库过滤: 不用使用binlog_do_db和binlog_ingore_db来过滤,他们只会在当前数据库上执行过滤
备库过滤: 设置replicate_*选项来过滤配置
一个mysql备库实例只能有一个主库
每个备库必须有一个唯一的id
一个主库可以有多个备库
如果打开了log_slave_updates选项,一个备库可以把其他主库上的数据变化传播到其他备库
为不同的角色使用不同的备库(例如添加不同的索引或者使用不同的存储引擎)
把一台备库当作待用的主库,处理复制没有其他数据传输
将一台备库放到远程数据中心,用作灾难恢复
使用其他一个备库作为备份,培训,开发或者测试使用的服务器
冲突难以解决
互相都是对方的备库,但是只有一个服务器是可写的,避免冲突的同时,可以快速切换主库备库的读写
主库的分发压力大的时候,可以设置一个备库,然后多个备库链接到这个备库,这个备库可以使用blackhole引擎,从而降低主库的负载
但是分发主库会导致二进制日志的位置不一样,备库无法简单的提升为主库,因为不知道是否已经同步完毕且数据一致
选择性复制(划分数据到不同的数据库然后复制到不同的备库上 | 通过分发主库和过滤规则来分发
分离功能(OLTP和OLAP使用不同的数据库
数据归档(PT-archieve 选择性的禁用主库的二进制日志然后清理数据或者使用一个空的清理库,备库使用ignore来忽略
将备库用作全文检索
只读备库(设置read_only
模拟多主库备份(将需要复制的备库轮流指向需要复制的主库源
创建日志服务器(binlog重放的使用使用空的数据库实例而不是mysqlbinlog 更清晰好用而且bug少
show master status/ logs;
show binlog events in ' mysql-bin.00000223' from 11111 \G;
show slave status;
备库的延迟报告不是准确的,seconds_behind_master的值只有在执行事件的时候才会得到报告
如果备库线程没有运行,延迟为NULL
一些错误可能中断复制,但是seconds_behind_master的显示是0
备库线程在运行但无法计算延时的时候,显示的是0或者NULL
一个大事务会导致延迟波动
如果分发主库落后了,备库延迟也还是0其实和源头的主库是有差距的
使用heartbeat record来记录延迟- pt-heartbeat的复制心跳
使用pt-table-checksum工具来检查主备是否数据一致(使用复制实现)
pt- table- checksum -- replicate=xx.checksum <master_host>
停止当前主库上的所有写操作
flush tables with read lock锁定所有的写入
选择一个备库作为新的主库,并确保已经完全跟上
确保数据是一致的
在新主库上执行stop slave
在新主库执行change master t o master_host=''
然后reset salve
使其断开和看主库的链接,并丢弃master.info中的消息
执行show master status 新主库的二进制坐标日志
确保其他备库已经追赶上
关闭旧的主库
在mysql5.1+如果需要的激活新主库的事件
将客户端连接到新主库
在每台备库上执行chage master to命令使用之前获取到的二进制日志的位置,指向新的主库
确定那台备库的数据最新 - 在所有备库执行show slave status 命令然后查看master_log_file/read)master_log_pos值最新的那个
让所有备库执行完毕从主库中获得的事件
执行刚才的5-7
比较每台备库和新主库上的master_log_file/read_master_log_pos的值
执行前一小节的10-12步
备库和主库的位置不一样的时候,需要找到备库最后一条执行的事件在新主库的二进制日志中的相应的位置,然后再执行change master to
通过mysqlbinlog从二进制日志或者中继日志中解析出每台备库上执行的最后一个事件然后同样使用这个命令解析新主库上的二进制日志,找到相同的查询,mysqlbinlog会打印出该事件的偏移量,再change_master to中使用这个量
把新主库和停止的备库上的偏移量相减,然后把这个差值和新主库当前的二进制日志的位置详见就可以得到期望查询的位置,通过刚的命令了简单验证一下就可以启动备库了
停止主动服务器上的所有写入
在主动服务器上执行set global read_only=1 同时配置文件里也配置,但是这不会阻止超级权限用户的修改,如果要阻止flush table with read lock
,或者kill所有的写入链接
在主动服务器执行show master status 并记录二进制日志坐标
使用主动服务器上的二进制日志坐标在被动服务器上执行select master_pos_wait(),该语句会阻塞知道复制跟上主动服务器;
在被动服务器执行set global read_only=1这样就成了主服务器;
修改应用的配置,使其写入到新的主服务器中
数据损坏或者丢失
主库意外关闭
开启sync_binlog,使用pt-checktablesum工具来检查主备一致性便于恢复
备库意外关闭
如果master.info没有写入磁盘,自动的同步可能位置都是错误的,只能忽略这些错误
pt-slave-restart工具可以使用
innodb可以在重启后观察mysql的错误日志会打印出他的回复点的二进制日志坐标,可以使用这个值来决定备库指向主库的偏移量
主库的二进制日志损坏
使用set global sql_salve_skip_counter =1 来忽略一个损坏的事件知道找到没损坏的地方或者手工修复
备库的中继日志损坏
如果主库没问题,直接用change master to 指定一个新的中继日志
二进制日志和innodb的事务日志不同步
sync_binlog safe_binlog
使用非事务型表
非事务型表在更新时候kill查询会导致复制失败或者不一致,在myisam关闭的时候一定要执行stop slave,否则会kill所有正在运行的查询导致复制失败
混合事务型和非事务型表
基于语句的复制会导致混合使用两种类型的引擎发生问题,基于行的不会受到影响
不确定语句
有些语句limit依赖查询的顺序来update可能会导致不一致
主库备库使用不同的引擎
备库发生数据变更
不唯一的服务器ID
会观察到备库和主库不停的断开和链接,复制可能正确也可能错误,要小心的配置服务器的id,最好和某些地方有所关联
未定义的服务器id
对未复制数据的依赖性(不要创建主库备库没有的库)
丢失的临时表
不复制所有的更新
innodb加锁引读引起的锁争用
在主主复制结构中写入两台从库
过大的复制延迟
单线程的设计很难调优
如果备库用于查询,锁定的时候还不能执行写入
不要重复写操作中代价比较高的部分
在复制之外并行写入
为复制线程预取缓存
来自主库的过大的包 max_allowed_packet需要主备匹配
受限制的复制带宽
磁盘空间不足 relay_log_space
复制的局限性
半同步复制
并行复制(基于schema)
复制心跳,防止悄无声息的复制中断
二进制日志的checksum
备库延迟复制
允许基于行的二进制日志事件也包含在主库执行的sql
解决group commit问题