多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] # 简介 必须开启二进制日志,有些并没有开启,如果没有开启以后需要开启就需要重启服务器 **分担读负载** 利用二进制日志增量进行的,不需要太多的带宽 但是在更新大批量的更改时会对带宽造成一定的压力 mysql的复制是基于二进制日志复制的 **从库用二进制日志重放来完成的** **最主要的就是从库重放主服务的效率** mysql的主从是异步的,所以无法保证主库和从库是一致的,无法保证主库和从库的延迟 非共享架构,同样的数据分布在多台服务器上,增加数据库安全 可以实现数据库在线升级 # 日志 ![](https://box.kancloud.cn/f614e6a537b836a98e4531d362ccb80b_1980x916.jpg) 二进制日志属于服务层日志,记录了所有对mysql数据库的修改事件包括增删改查事件和对表结构的修改事件 在binglog中记录的是已经成功执行的,一些执行没有成功事务回滚是不会记录在这个日志中的 ## 二进制日志格式 ### 基于段的格式(SBR) 逻辑复制 binlog_format=STATEMENT 这是在mysql5.7之前默认的使用的格式,记录更改的sql语句 **优点** * 日志记录量相对较小,节约磁盘及网络I/O,因为是sql,不用去记录每行的变化,如果只是对一条记录修改或插入,row格式所产生的日志量还小于段产生的日志量 * 减少数据库锁的使用 **缺点** * 必须要记录上下文信息,保证语句在从服务器上执行结果和在主服务器上相同 * 对于一些特定的函数,比如UUID(),user()这样非确定函数还是无法复制,如果使用这些函数可能造成主从服务器数据不一致 * 对于存储过程,触发器,自定义函数进行修改也可能造成数据不一致 * 相比基于行的复制在执行上时需要更多的锁 * 要求主从数据库的表结构必须一致,否则可能中断复制 * 无法在从上单独执行触发器 --- 在mysql中运行 ~~~ show variables like 'binlog_format'; ~~~ 看他默认是基于什么的格式 ~~~ +---------------+-------+ | Variable_name | Value | +---------------+-------+ | binlog_format | ROW | +---------------+-------+ ~~~ 我这边mysql5.7的是基于行的 我们改为基于段格式 ~~~ set session binlog_format=statement; ~~~ 我们看下原来的binlog日志 ~~~ show binary logs; ~~~ 刷新下binlog ~~~ flush logs; ~~~ 然后我们在命令行用mysqlbinlog对binglog日志进行查看 每个人目录可能不一样,log文件是用 `show binary logs;` 这个查看,然后在磁盘上找这个文件 ~~~ /usr/local/mysql/bin/mysqlbinlog mysql-bin.000025 ~~~ 在这里面可以看到我们刚才执行的sql ### 基于行的日志格式(RBR) binlog_format=ROW 这种格式可以避免mysql复制中出现的主从不一致问题 同一个sql语句修改1000条记录情况下,基于段的日志格式只会记录这个sql语句 基于行的日志会有1000条记录分别记录每一行的数据修改 **优点** * 使mysql主从复制更安全,无论使用确定还是非确定性函数对于主从都是一样的 * 对每一行数据的修改比基于段的复制高效,这样就可以更快的在从库上完成数据的重放,降低主从的延迟 * 误操作而修改了数据库中的数据,同时又没有备份可以恢复的时候,我们可以通过分析二进制日志对日志中记录的数据修改操作做反向处理的方式来达到恢复数据的目的 **缺点** * 记录日志量较大,每行都要记录,消耗更多的磁盘IO和网络带宽,但是日志都是顺序写入的,所以顺序写入,IO消耗并不是太多 mysql官方考虑到了这一点 binlog_row_image=[FULL|MINIMAL|NOBLOB] 通过设置这个full表示主要一行中有一列修改就把这行的所有列都记录下来 MINIMAL表示只记录修改的列 NOBLOB和full很像就是对blob和text没有修改的时候就不记录这个列 --- 把格式改为行 在mysql中运行 ~~~ mysql> show variables like 'binlog_row_image'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | binlog_row_image | FULL | +------------------+-------+ ~~~ 然后我们在命令行用mysqlbinlog对binglog日志进行查看 每个人目录可能不一样,log文件是用 `show binary logs;` 这个查看,然后在磁盘上找这个文件 ~~~ /usr/local/mysql/bin/mysqlbinlog mysql-bin.000027 ~~~ 这里的数据根本看不懂 ~~~ /usr/local/mysql/bin/mysqlbinlog -vv mysql-bin.000027 ~~~ 加上 -vv 就可以看到一些对应的sql和后面跟的那行变化的所有值 我们要测试其他binlog_row_image 运行 ~~~ set session binlog_row_image=minimal; ~~~ 就可以了 ### 混合日志格式 binlog_format=MIXED 他是混合了段的格式和行的格式的一些特点 * 根据SQL语句由系统决定在基于段和基于行的日志格式中作出选择,大部分是基于段的,有些使用不确定函数的一些是使用行的 * 数据量大小由所执行的SQL语句决定 根据实际内容在以上两者中切换 # mysql复制的工作方式 ![](https://box.kancloud.cn/3635a660e82c462865ca466eec7c2dc7_1748x1190.jpg) 1. 主将变更写入二进制日志 2. 从读取主的二进制日志变更并写入到relay_log中,这个读取,从库上开启一个线程称为IO线程和主库建立个普通的客户端连接,在主库上建立个特殊二进制转储线程称为binlog down,从库上线程通过这个线程来读取主库上的二进制日志事件,他不会对事件进行轮询,如果从库上的线程追赶上主库,他会进入到sleep状态,直到主库上有数据变更通知从库的线程,才会被唤醒.relay_log格式和二进制日志格式是相同的,可以用binlog工具进行查看 根据从什么位置开始读取主库上二进制日志的方法不同又分为 基于日志点的复制 基于GTID的复制 3. 在从上重放relay_log中的日志,这一步用从的sql线程来执行,对于这一步可以配置是否记录到从服务器的二进制日志文件中,日志格式不同重放的行为也不同 # 复制拓扑 ![](https://box.kancloud.cn/e068acaa50d786e5649a1eb1d0562d9b_2273x1532.jpg) ## 主主复制 ![](https://box.kancloud.cn/885d47f74c1fdc3b52126b4307176a8f_864x954.jpg) 不会造成死循环 ### 主备模式的主主复制 当一个主出现问题的时候,另一个主才会提供服务 注意 只有一台服务器处于只读状态并且只作为热备使用 在对外提供服务的主库出现故障或是计划性的维护时才会进行转换 使原来的备库成为主库,而原来的主库会成为新的备库并处理只读或是下线状态,待维护完成后重新上线 * 确保两台服务器上的初始数据相同 在2个服务器上使用同一个备份文件,进行数据恢复方式来完成 或者 一台已经运行一段时间的mysql来增加另外一台主库,这需要特殊的处理,在已有的数据库上进行备份记录下日志点等相关信息,这个信息作为老的库和新的主库连接时作为日志的binlog日志点来使用,然后在新的主库上进行日志恢复时用这个binlog日志点 * 确保两台服务器上已经启用binlog并且有不同的server_id * 在两台服务器上启用log_slave_updates参数 * 在初始的备库上启用read_only --- 我们也可以用下面这种方式 ![](https://box.kancloud.cn/8ea97a2b2912ff0a429ff5f9a06559d0_1250x544.jpg) 每个主下面都有只读从,但是要注意的是如果一个主DB出现问题,这个主下面的从也要在从的负载中去掉以免读到出问题主的从,数据会不一致 从库数量太多,会消耗很多主库的网络流量,而且每个从库复制主库,都要主库开启一个binlog down线程 --- 级联复制 ![](https://box.kancloud.cn/640b1d3331e8b3b80bc555283380654c_2220x946.jpg) 这样就避免了主库的分发负载,如果从库很多,可以建立多个分发主库 在分发主库上要开启slave_log_updates ### 主主模式的主主复制 2个主同时对外提供服务,这种无法分担主的写的负担,因为写无论发生在那个主库上都会被附加到另外一个主上 注意 容易产生数据冲突而造成复制链路的中断,如果造成冲突需要人为解决,耗费大量的时间 而且会造成数据丢失 * 两个主中所操作的表最好能够分开,避免数据的冲突 * 使用下面2个参数控制自增id的生成,避免自增id冲突 auto_increment_increment=2 auto_increment_offset=1 | 2 #自增id从1或是从2开始,一台奇数一台偶数 # 影响主从延迟的因素 复制主要是主库执行完sql后,把相应的记录放到binlog日志中,然后从库再把这个binlog日志复制到自己的中继日志中,然后从库的sql线程从中继日志中读取数据来恢复自己的数据,这些是异步的,延迟是不可避免的 * 主库上写入二进制日志时间和主库上执行大事务的消耗的时间,解决办法是控制大事务变为小事务 * 二进制日志的传输时间和传输的日志的大小 * 默认情况下从库只有一个sql线程,主库上并发处理的到从库上就变成串行.解决办法最好使用mysql5.6中配置的多线程复制,来增加从上的sql线程的数量 * 多线程复制,mysql5.6中的多线程复制是从库上每个线程处理一个数据库上的数据回放,如果是一主多从,那么这边的多线程复制还不如单线程复制,显得有些鸡肋,解决办法mysql5.7中的可以按照逻辑时钟的方式来分配sql线程 # 如何配置多线程复制 show slave status; stop slave 在从上停止链路复制 set global slave_parallel_type = 'logical_clock'; 开启逻辑时钟 set global slave_parallel_workers=4; 设置复制的线程数量,也觉得并发处理的数量 start slave; # 复制常见问题处理 由于数据损坏或丢失所引起的主从复制错误 * 主库或从库意外宕机引起的错误,没有将最后事件刷到binlog日志中,从库再次请求这个时间,主库告诉从库二进制日志文件中没有这个事件.解决办法:使用跳过二进制日志事件,注入空事务的方式先恢复中断的复制链路,再使用其他方法来对比主从服务器上的数据 从库宕机会导致master info文件没有及时同步到磁盘上,master info文件中记录了从库已经同步了主库的二进制日志文件的信息,会导致从库重新执行了一些二进制日志.解决办法:使用跳过二进制日志事件,用其他方法来对比主从服务器上的数据 * 主库上的二进制日志损坏,意外的关闭通过change master命令来重新指定,但是这会丢失一些主库上的更新,造成数据差异,解决办法:用其他方法来对比主从服务器上的数据 * 备库上的中继日志损坏,只要主库上没事就好处理,通过change master命令指定IO线程重新从损坏的位置再次同步主库的二进制日志 * 在从库上进行数据修改造成的主从复制错误,从库应该设置为只读,但是在mysql5.7之前拥有slave权限的用户还是能对从库进行修改,主从复制依赖数据的一致性,如果数据一致性被破坏,复制链路会轻易的中断.要人为的决定是保留主库上的数据还是从库上的数据 * 主从包括从从之间不唯一的server_id或server_uuid,server_uuid是记录在数据目录中的auto.cnf文件中,一旦这个文件存在,mysql是不会重新生成server_uuid的,这个问题非常隐蔽.2个相同的server_uuid一旦重复会导致重复执行二进制日志事件也有可能丢失二进制日志事件. 也会造成选择相同的server_uuid,主从切换失败 * max_allow_packet最大允许的包设置不一致,引起主从复制错误,主库会记录从库接收多大的包,这个不正确会导致一些无限报错,中继日志损坏 # 复制无法解决的问题 * 分担主数据库的写负载,在主库上写的事件,在从库上都会重放,解决写负载只能分库分表来解决 * 自动进行故障转移及主从切换 * 提供读写分离功能 # 高可用 ## 单点故障 **共享存储** ![](https://box.kancloud.cn/f157fec82ce9d950f68db90a683a8bad_1482x622.jpg) 2个服务器共享一个磁盘,一个服务器宕机,另一个服务器接管磁盘 缺点这也是单点故障 --- **DRDB磁盘复制** ![](https://box.kancloud.cn/118ddc24fa1c434233183a02e88fac01_890x588.jpg) 通过网卡把主服务器上的块提交给备用服务器的块,DRDB是镜像不是共享存储,缺点主DB被污染,备也被污染. 发生故障转移时间长,故障恢复不能提供服务 --- **利用多写集群** percona公司提供的->pxc集群 ![](https://box.kancloud.cn/f1dd91ef2c1f5f063fd286b8955cae7b_932x742.jpg) 一个事务被集群中所有事务提交后才可提交 缺点:整个集群中性能取决于性能最差的那台集群,只支持innodb --- **NDB集群** 所有节点都进行主主复制,所有节点都可写入,所有节点都有相同的读写能力,并且每行数据都是冗余存储的 缺点:要求所有数据存放在内存中,如果放在磁盘中性能会非常差,还有其他限制,一般不会使用 --- **mysql本身复制** 常见问题 主服务器切换后 如何通知应用新的主服务器的IP地址 如何检查Mysql主服务器是否可用 如何处理从服务器和新主服务器之间那种复制关系 解决可以自己写代码解决也可以用第三方复制组件 组件常用有MMM还有MHA # MMM的主要作用 监控和管理mysql的主主复制拓扑,并在当前的主服务器失效时,进行主和主备服务器之间的主从切换和故障转移等工作 MMM监控Mysql主从复制健康情况 1. 主动主动模式的主主复制,2个主同时对外提供服务 2. 主动被动模式的主主复制,同时只有一个主提供服务,另一个主是备份 MMM是工作在第二种的复制模式,意思就是MMM同一时间只能有一个主对外提供服务 在主库出现宕机时进行故障转移并自动配置其他从对新主的复制 提供了主,写虚拟ip,在主从服务器出现问题时可以自动迁移虚拟ip **那么问题来了** 如何找到从库对应的新的主库日志点的日志同步点 如果存在多个从库出现数据不一致的情况如何处理 MMM只是简单把从做为主,在一个繁忙的系统中肯定会造成数据丢失