MySQL中的binlog和redo浅析(r12笔记第5天)

   有一个小问题可能很多人都想起过,那就是MySQL中既然已经有了binlog,为什么还需要redo,这个问题看起来好像很简单,但是细细品来,还是有不少值得注意的地方。

   
对于数据恢复,尤其是异常宕机的情况下,再次启动的时候,如何恢复,恢复的数据依据,这个尤为重要,在MySQL中是有checkpoint的技术来做一个基本的检查点控制,也就是常说的LSN,对于事务性数据库,大都会采用write
ahead
log的策略,即当前事务提交的时候,先写redo,在修改相应的页,如果发生宕机导致数据丢失的时候,可以通过重做日志来完成数据的恢复,但是MySQL和其它有些数据库有些特别的是这个binlog,它不是采用checkpoint的实现方式,我们可以设想这样一个情况,一个事务提交的时候,信息会写入redo,而在这个操作的过程中,其实binlog的写入也是同步的,如果redo的信息在redo
log
buffer中可能还没有刷新到磁盘中,出现宕机的情况,就可能导致从库的数据已经应用了binlog传输的数据变化,而redo中还没来得及提交,这可能就会有数据不一致的情况发生,如果在异常状态下启动数据库就会开启数据恢复的模式,可能从库的数据就会出现不一致。

   这种情况听起来有些特别,但是对于我们理解redo和binlog的问题蛮有帮助,我们来做一个测试吧,仅仅在测试环境中进行调试所用。

首先为了减少数据的变更影响,我们先做一个flush logs的操作,尽可能保留少,数据变化新的日志内容

在主库端切换日志:
flush logs;

查看binlog的情况,使用show master status或者show binary logs都可以。
mysql> show master status\G
*************************** 1. row ***************************
             File: binlog.000014
         Position: 230
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set: 1bb1b861-f776-11e6-be42-782bcb377193:1,
25ee7482-07cd-11e7-a40c-0026b935eb76:1-1502468
1 row in set (0.00 sec)

我们得到mysql服务的进程号。
# ps -ef|grep -w mysqld|grep -v grep|awk '{print $2}'
1751

我们创建一个表test 字段为id和name(id int ,name varchar(20))

已经存在4条数据如下:

mysql> select *from test.test;
+------+------+
| id   | name |
+------+------+
|    1 | aa   |
|    2 | bb   |
|    3 | cc   |
|    4 | dd   |
+------+------+
4 rows in set (0.00 sec)

从库 查看数据和主库此时是同步的。这是我们测试的一个基础。

我们可以通过gdb的方式进行简单调试。
# gdb -p 1751

就马上进入了调试模式,我们可以设置一个断点。

我们在设置断点之前先插入2条数据,从库此时也是5条数据。

mysql> insert into test values(5,'ee');
Query OK, 1 row affected (0.00 sec)

mysql> insert into test values(6,'ff');
Query OK, 1 row affected (0.00 sec)

然后设置断点,这是关键所在。
(gdb) b MYSQL_BIN_LOG::process_commit_stage_queue
Breakpoint
1 at 0xec73ca: file
/export/home/pb2/build/sb_0-21378219-1480347226.17/mysql-5.7.17/sql/binlog.cc,
line 8430. (2 locations)

然后在主库尝试插入一条记录
insert into test values(7,'gg');
毫无疑问,这条语句会hang住。因为我们的断点就在提交的时候。

这个时候我们前进一小步,使用c即continue

(gdb) c
Continuing.
[Switching to Thread 0x409c0940 (LWP 1798)]

Breakpoint 1, MYSQL_BIN_LOG::process_commit_stage_queue (this=0x1e8ba00, thd=0xec254e0, first=0xec254e0)
    at /export/home/pb2/build/sb_0-21378219-1480347226.17/mysql-5.7.17/sql/binlog.cc:8430
8430    /export/home/pb2/build/sb_0-21378219-1480347226.17/mysql-5.7.17/sql/binlog.cc: No such file or directory.
        in /export/home/pb2/build/sb_0-21378219-1480347226.17/mysql-5.7.17/sql/binlog.cc
这个时候那条SQL语句依旧是hang的状态,但是可以看出堆栈,binlog是写入完成了

从库此时是应用了数据变更,此时是7条数据。
我们也可以抓取一下binlog,看看里面是否已经写入了数据。
[root@grtest s1]# /usr/local/mysql/bin/mysqlbinlog -vv binlog.0000014
可以明显看到这样的语句:

...

BINLOG '
DK3KWBPqDAAALgAAAHcDAAAAAOUAAAAAAAEABHRlc3QABHRlc3QAAgMPAhQAAw==
DK3KWB7qDAAAJwAAAJ4DAAAAAOUAAAAAAAEAAgAC//wHAAAAAmdn
'/*!*/;
### INSERT INTO `test`.`test`
### SET
###   @1=7 /* INT meta=0 nullable=1 is_null=0 */
###   @2='gg' /* VARSTRING(20) meta=20 nullable=1 is_null=0 */
# at 926
#170316 23:19:40 server id 3306  end_log_pos 953        Xid = 55
COMMIT/*!*/;
我们此时模拟宕机的情况,杀掉进程

 kill -9 1751 29617

然后把binlog改个名字,关闭log_bin
[root@grtest s1]# mv binlog.000014  binlog.000014.bak
再次启动之后,就会发现此时的主库中数据还是6条,而从库却是7条。
  而如果我们把binlog改回来,开启log_bin并启动主库
mv binlog.000014.bak binlog.000014

   然后再次查看数据,就会发现主从库此时的数据竟然不同。从库的数据明显要多,这也就从一个侧面映射了我们开始的一个设想,在异常宕机的情况下,redo的数据还没有刷新到redo文件中,此时已经写入了binlog,这样就在这样一个临界点导致了主从数据的不一致。

   当然我是使用一个调试的态度来做的测试,里面还有很多技巧需要巩固。

时间: 2024-09-11 18:08:34

MySQL中的binlog和redo浅析(r12笔记第5天)的相关文章

mysql中使用UDF自动同步memcached效率笔记_Mysql

接上篇:mysql使用mysql-udf-http效率测试笔记 ,这次不使用rest架构,而是使用:libmemcached和memcached_functions_mysql,测试版本是: libmemcached-0.34.tar.gz和memcached_functions_mysql-0.9.tar.gz,其它版本配对都有问题,我安装测试过有问题的版本有: 复制代码 代码如下: memcached_functions_mysql-1.1在: libmemcached-0.49\libme

MySQL中的binlog相关命令和恢复技巧_Mysql

操作命令: 复制代码 代码如下: show binlog events in 'mysql-bin.000016' limit 10; reset master 删除所有的二进制日志flush logs  产生一个新的binlog日志文件 show master logs; 或者 show binary logs; 查看二进制文件列表和文件大小 复制代码 代码如下: ./mysqlbinlog --start-datetime="2012-05-21 15:30:00" --stop-

MySQL和Oracle中的唯一性索引从差别(r12笔记第83天)

   今天在修复MySQL数据的时候,发现一个看起来"奇怪"的问题.   有一个表里存在一个唯一性索引,这个索引包含3个列,这个唯一性索引的意义就是通过这3个列能够定位到具体1行的数据,但是在实际中却发现这个唯一性索引还是有一个地方可能被大家忽略了.  我们先来看看数据的情况.  CREATE TABLE `test_base_data` (   `servertime` datetime DEFAULT NULL COMMENT '时间',   `appkey` varchar(64

MySQL中BOOL/BOOLEAN 与 TINYINT 区别 - 测试笔记

(一) 数据类型测试 (1). 布尔类型BOOL/BOOLEAN 与 微整型TINYINT a). 创建测试表结构 root@localhost : test 05:12:49> CREATE TABLE boolean_test(ID INT NOT NULL AUTO_INCREMENT, ->                           Online_Flag BOOL, ->                           Lock_Flag BOOLEAN, -&g

相同update语句在MySQL,Oracle的不同表现(r12笔记第30天)

   今天有个朋友问我一个SQL问题,大体是一个update语句,看起来逻辑没有问题,但是执行的时候却总是报错. 语句和报错信息为: UPDATE payment_data rr    SET rr.penalty_date = '2017-4-12'  where rr.id =        (SELECT min(r.id)           FROM payment_data r          where data_no =                (SELECT data_

Oracle 12c DBCA浅析(r12笔记第48天)

   我们知道在11g的环境中我们可以通过一些分析来得到DBCA的一些后台处理工作,有一点需要说明的是,如果一个12c的单实例数据库需要转换为12c的容器数据库,你去查看官方文档,会发现这是一个空白,不是做不了,而是里面有一些地方会干扰到你.   所以在11g手工探究脚本过程的基础上,12c的部分你需要再进一步.常规来说,我们可以通过如下的命令得到一个12c的数据库创建的脚本. dbca -silent  -templateName $ORACLE_HOME/assistants/dbca/te

MySQL频繁停库的问题分析(r12笔记第33天)

  最近也抽空帮一些网友解决一些问题,有些是Oracle,有些是MySQL,有时候虽然忙忙乎乎,但是解决问题之后还是很有成就感的.   今天来说一个蛮有意思的问题,听起来还很诡异.是一个网友向我咨询,看看能不能给出一些建议.当我看到日志,隐隐感觉这是一个bug的感觉. 详细的日志如下: 2017-04-13 16:25:29 40180 [Note] Server socket created on IP: '::'. 2017-04-13 16:25:29 40180 [Warning] St

从MySQL中的double write问题说开去

有句话说得好,世上只有两种工具,一种是被人骂的,另一种是没人用的.被骂得越多,侧面反映出关注度越高,使用率越高,越用越成熟,这一点上, MySQL就是一个很不错的例子.而MySQL可支持的存储引擎很多,目前以InnoDB最佳,算为上品.   自MySQL 5.5.5开始,InnoDB是作为默认的存储引擎,而之前MyISAM存储引擎其实也占有一席之地,但MySQL开发团队自宣布MySQL 8.0.0开发里程碑版本DMR开始,就把MySQL版本一下子从5.x跳跃到了8.0.其中的一个亮点就是事务性数

MySQL中GTID和自增列的数据测试(r12笔记第38天)

  昨天的一篇文章,今天有不少网友向我确认一些细节,我想最近正好在看GTID的东西,可以揉在一起来说说.    GTID这个概念看似简单,实际上还是有不少的门道. 我们来从架构的设计角度来看看存在哪些场景需要考虑GTID的变化.   一主两从的架构模式下GTID的变化   我们就以一主两从的架构为基准进行阐述.在这个架构模式下我们会用到MHA的方案.    如果这个时候Master节点宕机了,MHA就会开启检查机制. 这个时候Slave 1节点就会变为新的Master,Slave 2会从Slav