24 | MySQL是怎么保证主备一致的?

2019-01-07 林晓斌
《MySQL 实战 45 讲》
课程介绍


讲述:林晓斌

时长:大小18.15M


在前面的文章中,我不止一次地和你提到了 binlog,大家知道 binlog 可以用来归档,也可以用来做主备同步,但它的内容是什么样的呢?为什么备库执行了 binlog 就可以跟主库保持一致了呢?今天我就正式地和你介绍一下它。
毫不夸张地说,MySQL 能够成为现下最流行的开源数据库,binlog 功不可没。
在最开始,MySQL 是以容易学习和方便的高可用架构,被开发人员青睐的。而它的几乎所有的高可用架构,都直接依赖于 binlog。虽然这些高可用架构已经呈现出越来越复杂的趋势,但都是从最基本的一主一备演化过来的。
今天这篇文章我主要为你介绍主备的基本原理。理解了背后的设计原理,你也可以从业务开发的角度,来借鉴这些设计思想。

MySQL 主备的基本原理

如图 1 所示就是基本的主备切换流程。

展开全文
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。

精选留言

  • Sinyo
    置顶
    2019-01-21
    主库 A 从本地读取 binlog,发给从库 B; 老师,请问这里的本地是指文件系统的 page cache还是disk呢?
    展开

    作者回复: 好问题, 是这样的,对于A的线程来说,就是“读文件”, 1. 如果这个文件现在还在 page cache中,那就最好了,直接读走; 2. 如果不在page cache里,就只好去磁盘读 这个行为是文件系统控制的,MySQL只是执行“读文件”这个操作

    共 4 条评论
    141
  • Leon📷
    置顶
    2019-01-25
    老师,我想问下双M架构下,主从复制,是不是一方判断自己的数据比对方少就从对方复制,判断依据是什么

    作者回复: 好问题。 一开始创建主备关系的时候, 是由备库指定的。 比如基于位点的主备关系,备库说“我要从binlog文件A的位置P”开始同步, 主库就从这个指定的位置开始往后发。 而主备复制关系搭建完成以后,是主库来决定“要发数据给备库”的。 所以主库有生成新的日志,就会发给备库。

    共 10 条评论
    100
  • Joker
    2019-03-06
    老师您好,读到您关于binlog的文章之后,我有个疑问。 我之前理解是,mysql 每执行一条事务所产生的binlog准备写到 binlog file时,都会先判断当前文件写入这条binlog之后是否会超过设置的max_binlog_size值。 如果超过,则rotate 自动生成下个binlog flie 来记录这条binlog信息。 那如果 事务所有产生的binlog 大于 max_binlog_size 值呢? 那不是永久地rotate吗? mysql是如何处理的? 谢谢。
    展开

    作者回复: 好问题 一个事务的binlog日志不会被拆到两个binlog文件,所以会等到这个事务的日志写完再rotate,所以你会看见超过配置大小上限的binlog 文件

    共 3 条评论
    95
  • 观弈道人
    2019-01-07
    老师你好,问个备份问题,假如周日23点做了备份,周二20点需要恢复数据,那么在用binlog恢复时,如何恰好定位到周日23点的binlog,谢谢。

    作者回复: Mysqlbinlog有个参数—stop-datetime

    
    68
  • 妥妥
    2019-02-28
    老师,我想问下,如果一张表并没有主键,插入的一条数据和这张表原有的一条数据所有字段都是一样的,然后对插入的这条数据做恢复,会不会把原有的那条数据删除?不知道在没有主键的情况下binlog会不会也记录数据库为其生成的主键id

    作者回复: 好问题, 会删除一条,但确实可能删除到之前的那条。 主要就是因为,没有主键的时候,binlog里面就不会记录主键字段。

    共 8 条评论
    52
  • HuaMax
    2019-01-07
    课后题。如果在同步的过程中修改了server id,那用原server id 生成的log被两个M认为都不是自己的而被循环执行,不知这种情况会不会发生

    作者回复: 是的,会

    共 7 条评论
    49
  • 一大只😴
    2019-01-07
    死循环第二种情况: 双主,log_slave_updates=on,binlog_format=statement 配置文件里写成statement格式,然后两个master都重启 (从row格式改成statement试了几次没有成功,因为binlog中记录格式还是row) 测试: 表t (id ,c,d) 主键id,有一条数据(1,2,1); M1执行 stop slave; update t set c=c+1 ;或 update t set c=c+1 where id=1; set global server_id=new_server_id; start slave; 然后就能看到c的值在不断变大,想停止就把server_id改回原来的就可以了。
    展开

    作者回复: 赞

    共 2 条评论
    41
  • 三木禾
    2019-03-31
    老师,双M可能会造成数据不一致的情况么? 比如,A B同时更新同一条数据?

    作者回复: 一般说双M是只AB之间设置为互为主备,不过任何时刻只有一个节点在接受更新的

    共 4 条评论
    37
  • hua168
    2019-01-08
    大神,我前些天去面试,面试官问了一题: mysql做主从,一段时间后发现从库在高峰期会发生一两条条数据丢失(不记得是查询行空白还是查询不到了),主从正常,怎么判断? 1.我问他是不是所以从库都是一样,他说不一样 2.我说低峰期重做新的从库观察,查看日志有没有报错?他好像不满意这个答案。 二、他还问主库挂了怎么办? 1. mysql主从+keepalived/heartbeat 有脑裂,还是有前面丢数据问题 2. 用MMM或HMA之类 3.用ZK之类 三、写的压力大怎么办? 我回答,分库,分表 感觉整天他都不怎么满意,果然没让我复试了,我郁闷呀,我就面试运维的,问数据这么详细。😂 大神,能说下我哪里有问题吗?现在我都想不明白😂
    展开

    作者回复: 运维现在要求也挺高的 第一个问题其实我也没看懂,“高峰期丢数据”是指主备延迟查不到数据,还是真的丢了,得先问清楚下 不过你回答的第二点不太好,低峰期重做这个大家都知道要这么做,而且只是修复动作,没办法用来定位原因,面试官是要问你分析问题的方法(方向错误) 重搭从库错误日志里面什么都没有的(这个比较可惜,暴露了对字节不够了解,一般不了解的方法在面试的时候是不如不说的) 第二个问题三点都是你回答的吗?那还算回答得可以的,但是不能只讲名词,要找个你熟悉细节的方案展开一下 三方向也是对的 我估计就是第一个问题减分比较厉害

    共 4 条评论
    37
  • 汪炜
    2019-01-23
    老师,问个问题,希望能被回答: mmysql不是双一设置的时候,破坏了二阶段提交,事务已提交,redo没有及时刷盘,binlog刷盘了,这种情况,mysql是怎么恢复的,这个事务到底算不算提交?
    展开

    作者回复: 如果”redo没有及时刷盘,binlog刷盘了”之后瞬间数据库所在主机掉电, 主机重启,MySQL重启以后,这个事务会丢失;这里确实会引起日志和数据不一致, 这个就是我们说要默认设置为双1的原因之一哈

    共 4 条评论
    31
  • linqw
    2019-02-17
    写下学习完这篇的总结和理解,老师有空帮忙看下哦 1、简单主备,一主多备,主进行更新操作,将生成binlog文件发送给备,但是比较好奇一点的是所有备向主拿binlog文件的时候,主都是一个线程进行将binlog文件依次发送给备么?两个库互为主备可以将一个负责数据的写入,生成binlog文件,另一个作为数据的同步,将其改变的binlog同步到自身,然后其他备再从其同步binlog,多master可以做到一台宕机,快速切换到另一台作为主,防止主库宕机对业务造成的影响,但是这样可能导致一定程度的同步延迟。 2、主备复制关系搭建完成,主有数据写入的时候,发送给备的应该不是整个binlog log文件吧,是每次写入的binlog event么? 3、在图 2 主备流程图对bg-thread->undolog(disk)->data(disk)不太理解,回滚段也是先记录到内存,再记录在磁盘么?undolog(disk)再到data(disk),看了下undo log的控制参数没有看到控制类似行为的,没想通?老师帮忙解答下哦 4、binlog的三种格式,statement,记录数据库原句,有可能导致,主备所选择的索引不一致,导致主备数据不一致。row,binlog log记录的是操作的字段值,根据binlog_row_image 的默认配置是 FULL包括操作行为的所有字段值,binlog_row_image 设置为 MINIMAL,则会记录必须的字段,一般设置为row,可以根据binlog文件做其他操作,比如在误删除一行数据时,可以做insert,恢复数据。 5、如果执行的是 update 语句的话,binlog 里面会记录修改前整行的数据和修改后的整行数据,在二级索引的普通索引,有个change buffer优化,防止频繁的将数据页读入进来,可以减少buffer pool的消耗,可以在读取数据时,再将其marge,或者后台线程marge,但是在binlog log设置row格式的,update时,需要记录更新前后的数据,那这样的话,chage buffer不是用不上了么?还是说设置成row格式的时候,change buffer会没生效?老师麻烦帮忙解答下哦,没想明白
    展开

    作者回复: 2. 流式发送,一个事务提交就会发 3. “回滚段也是先记录到内存,再记录在磁盘么?” 是的。 undolog(disk)不需要到data(disk),undo log的作用看一下08篇 5. “update时,需要记录更新前后的数据,那这样的话,chage buffer不是用不上了么” --- 不是的,binlog里面的内容用的是主键索引上的,主键索引确实用不上change buffer,但是普通索引可以

    共 3 条评论
    20
  • hetiu
    2019-01-07
    老师,请教下双M模式是如何解决数据冲突的?

    作者回复: 双写?别双写。

    共 2 条评论
    18
  • 陈扬鸿
    2019-02-24
    老师,我现在生产上用的是MySQL5.6的主从同步,主库用的是ssd硬盘,备库用的是机械硬盘,现在从库落后主库好几个小时,主库上数据的写入更新比较大,这个问题是由于两端硬件问题造成的吗?线上只有一个数据库,有什么好的同步加速方案吗?麻烦老师给我解答一下,谢谢!

    作者回复: 最好是换硬件,把备库的磁盘能力提上来, 可以考虑一下备库设置 innodb_flush_log_at_trx_commit 和 sync_binlog 为非双1 试试

    共 3 条评论
    17
  • 柚子
    2019-01-07
    大佬您好,文中说现在越来越多的使用row方式的binlog,那么只能选择接受写入慢和占用空间大的弊端么?

    作者回复: 是的,当然还有minimal可选,会好些😄

    共 3 条评论
    11
  • 不迷失
    2019-01-08
    请教一下,生产环境能不能使用正常使用表连接?要注意哪些地方?DBA总是说不建议用,还催促我将使用了表连接的地方改造,但也说不出个所以然。目前在两个百万级数据的表中有用到内连接,并没有觉得有什么问题

    作者回复: 索引使用正确,不要出现全表扫描,其实OK的

    共 7 条评论
    10
  • 古娜拉黑暗之神·巴啦...
    2019-01-07
    老师,您好,问一个关于change buffer的问题。 对于insert语句来说,change buffer的优化主要在非唯一的二级索引上,因为主键是唯一索引,插入必须要判断是否存在。 那么对于update语句呢?如下(假设c有非唯一索引,id是主键,d没有索引): update t set d=2 where c=10; 原先以为:从索引c取出id之后,不会回表,也不会把修改行的数据读入内存,而是直接在change buffer中记录一下。但看了今天得内容之后又迷糊了,因为如果不把修改行的数据读入内存,它又怎么把旧数据写入binlog中呢? 所以我想问的就是,上面的sql语句会不会把修改行的内容也读进内存?如果读进内存,那读进内存的这一步难道就为了写binlog吗?如果不读进内存,那binlog中的旧数据又是怎么来的呢?还有delete语句也同理。
    展开

    作者回复: 修改的行要读入内存呀 写binlog只需要主键索引上的值 你这个语句的话,如果字段c d上都有索引,那么c用不上chsnge buffer, D可能可以同上

    共 7 条评论
    10
  • 守护.
    2019-01-07
    老师早,问一个和本次课题之外的问题.mysql 数据库,我如果开启多线程对多张表同时进行insert 操作. 每张表自增的主键id会不连续.这个问题怎么处理呢?

    作者回复: 我的建议是不处理,自增主键id不连续应该作为常态,也就是说系统不要依赖于这个它必须要连续

    共 2 条评论
    9
  • Mackie .Weng
    2019-01-14
    老师,你的课真好, 你讲的都是生产实际用到的,点赞~ 不过近期有点苦恼,要请教一下近期遇到的事 场景: SSD硬盘,我们数据一天一备份,想通过昨天凌晨备份+binlog恢复到最新数据,导出的binlog为2G,然后发现导入binlog花费了4,5小时,看了下binlog日志里面有很多这种信息 # at 2492 #190108 17:08:38 server id 2 end_log_pos 2601 CRC32 0x8b0598ec Query thread_id=12277795 exec_time=0 error_code=0 SET TIMESTAMP=1546938518/*!*/; BEGIN /*!*/; # at 2601 # at 2633 # at 2919 #190108 17:08:38 server id 2 end_log_pos 2950 CRC32 0x13806369 Xid = 1924155105 COMMIT/*!*/; 问题: 1、在导出binlog为2G而且看了下里面很多这种事务,这是什么东西,有什么用吗 2、这种事务在导出binlog的时候可以不记录吗,然后来提高恢复数据的速度? 3、如果这是正常的情况,有无推荐更好的数据恢复方案或者工具 感谢老师
    展开

    作者回复: 1. 有用,最好保留这些信息一起执行; 2. 提升不了多少速度的,花时间主要还是在更新数据的那些日志上,那些日志又不能去掉的:) 3. 这个方案是串行恢复。你可以把全量恢复出来的库,接成线上一个从库的备库,开并行复制,

    
    8
  • 风二中
    2019-01-12
    在主库执行这条 SQL 语句的时候,用的是索引 a;而在备库执行这条 SQL 语句的时候,却使用了索引 t_modified 老师,您好,这里索引选择不一样,是因为前面提到的mysql 会选错索引吗?这种情况应该发生比较少吧,这里应该都会选择索引a吧,还是说这里只是一个事例,还有更复杂的情况

    作者回复: 对,只是一个举例的

    
    8
  • 光
    2019-01-09
    林老师今天遇到个问题就是主从同步延迟,查到主从状态中出现:Slave_SQL_Running_State: Waiting for Slave Workers to free pending events。不知道这个是否会引起延迟。查了些资料说得都不是很明白。老师是否可以简短解答下。以及这种延迟如何避免。

    作者回复: 这个的意思是, 现在工作线程里面等待的队列太多,都已经超过上限了,要等工作线程消化掉一些事务再分 简单说,就是备库的应用日志的队列太慢了。。

    共 2 条评论
    8