15 | 答疑(一):日志和索引相关问题

1、binlog 是否完整   COMMIT / xid

2、redo log  binlog 怎么关联    xid

3、prepare  redo log 加上完整 binlog,重启就能恢复,why这么设计(备用binlog一致)

4、为什么两阶段提交?redo log写完,再写 binlog。崩溃恢复时,必须得两个日志都完整才可以。是不是一样的逻辑?(redo log不能回滚)

5、why两日志?历史原因,实际只有binlog恢复崩溃

6、可不可以只要redo?能崩溃恢复,不能高可用 保留历史记录

7、redo多大?一般 4 个文件、每个 1GB 

8、数据落盘,从redo log还是buffer pool 更新过来?

两阶段提交不同瞬间,MySQL异常重启,怎么保证数据完整?

图 1 两阶段提交示意图

不是update 语句执行流程吗,怎么调用 commit ?两个“commit”的概念混淆了:

1)上述“commit 语句”,MySQL 语法中,提交事务。跟 begin/start transaction 配对用。执行时,包含“commit 步骤(2)”。

2)图中“commit ”,事务提交小步骤(最后一步),执行完,事务提交。

没显式开启事务,update 语句自己就是一个事务,执行完成,用到“commit 步骤“。

A :binlog 还没写,redo log 也还没提交,崩溃恢复,事务回滚。binlog 没写,不会传备库。

B, binlog 写完,redo log 没 commit , crash

崩溃恢复判断规则(有commit 才提交):

1.  redo log 事务完整,有commit 标识,提交

2.  redo log 事务完整 prepare, 对应binlog 完整提交.否则回滚:

追问 1怎么知道 binlog 是否完整?

有完整格式:

statement 格式的 binlog,最后有 COMMIT

row 格式的 binlog,最后有XID event

binlog-checksum 验证 binlog 正确性。磁盘原因,中间出错的情况。

追问 2redo log binlog 怎么关联?

共同数据字段XID。崩溃恢复顺序扫描 redo log:

只有 parepare、没有 commit 的 redo logXID 去 binlog 找对应事务

追问 3prepare 阶段的 redo log 加上完整 binlog,重启就能恢复,为什么这么设计?

保证主、备库数据一致性。 

B, binlog 已写,被从库(用 binlog 恢复的库)用,主库也要提交这个事务。

追问 4:为什么还要两阶段提交呢?redo log写完,再写 binlog。崩溃恢复时,必须得两个日志都完整才可以。是不是一样的逻辑?

场景,事务持久性问题。每人都“ok”,一起提交。

redo log 提交完成了,事务不能回滚(如回滚,覆盖别的事务更新)。

如 redo log 直接提交,binlog 写入失败,InnoDB 回滚不了,数据和 binlog 日志不一致了。

追问 5:不引入两个日志,就没有两阶段提交必要。只用 binlog 来支持崩溃恢复,又能支持归档,不就可以了?

只保留 binlog, “更新到内存” -> “写 binlog”-> “提交事务”不可以。

历史原因,InnoDB 是 MySQL 插件,binlog 没有崩溃恢复能力,用 InnoDB 原有 redo log 。

实现上原因:只用 binlog 来实现崩溃恢复的流程,没有 redo log 

图 2 只用 binlog 支持崩溃恢复

binlog 不能恢复“数据页”。binlog2 写完,没commit 的时候,crash。

事务 2 回滚, binlog2 补回来;事务 1 来说,认为提交完了,不会再用 binlog1。

InnoDB 用 WAL,依赖日志恢复数据页。事务 1 可能丢失数据页。binlog 没记录数据页更新细节,补不回来

追问 6:只用 redo log,不要 binlog

只从崩溃恢复角度可以。正式生产库,binlog 开。有着 redo log 无法替代的功能。

1)归档。redo log 循环写,历史日志没法保留。

2)高可用的基础,binlog 复制。

2)数据分析系统,靠消费 MySQL 的 binlog 更新数据。关掉下游没法输入。

追问 7redo log 一般设置多大?

redo log 太小的话,很快写满,强行刷 redo log, WAL 能力发挥不出来。

redo log  4 个文件、每个 1GB 

追问 8:数据写入后落盘,从redo log更新过来还是从buffer pool

redo log 没有记录数据页完整数据,不能更新磁盘数据页

1.  数据页被修改和磁盘不一致,称为脏页内存中数据页写盘。与 redo log 毫无关系

2.  崩溃恢复场景,InnoDB 判断数据页丢失更新,将它读到内存,让 redo log 更新内存。更新完成,内存页变成脏页,回到第一种情况状态。

追问 9redo log buffer 是什么?先修改内存,还是先写 redo log文件?

更新中,日志写多次:不能没 commit 时写到 redo log 文件里

begin;

insert into t1  ...    //a、内存被修改:redo log buffer 写入日志

insert into t2  ...

commit;    //b、日志写到 redo log 文件(文件名是 ib_logfile+ 数字)

redo log buffer就是块内存,先存 redo 日志。a、b

业务设计问题

业A、B 两个用户,互相关注成好友。like 表,friend 表,like 表有 user_id、liker_id 两个字段,设置为复合唯一uk_user_id_liker_id。:

A 关注 B 为例:第一步,先查询对方有没有关注自己(B 有没有关注 A)

select * from like where user_id = B and liker_id = A;

有,则成为好友 insert into friend;

没有,单向关注关系insert into like;

A、B 同时关注对方不会成好友。第 1 步双方没互关,用了排他锁也不行,记录不存在,行锁不生效锁层面如何处理

图 3 并发“喜欢”逻辑操作顺序

select 都空。session 1 插入一个单向关注关系”。session 2 也同样

解决办法:给“like”表增加relation_ship,取值 1、2、3。

1 ,user_id 关注liker_id;

2,liker_id 关注user_id;

3,互相关注。

然后,当 A 关注 B 的时候,逻辑改成如下所示的样子:

比较 A 和 B 的大小,A<B:

如果 A>B,则执行下面的逻辑

让“like”表里的数据保证 user_id < liker_id,反向关系已存在,出现行锁冲突

insert … on duplicate 确保事务内部,强行占行锁,select 判断relation_ship 逻辑时确保行锁保护下读操作

操作符 “|” 是按位或,连同 insert  ignore保证重复调用时幂等性

like 表relation_ship = 3,  friend 表里也有 A 和 B 记录。

之前说尽量不要使用唯一索引,这个例子创建两个。例子业务根本,“一定插入重复数据,数据库要有唯一性约束”。

在“业务开发保证不会插入重复记录”的情况下,着重要解决性能问题时,尽量用普通索引

思考题

创建表 t,插入一行,修改。

表 t 唯一的一行数据 (1,2)。执行:update  t set a=2 where id=1

MySQL 处理命令三种选择:你觉得实际哪种呢?为什么?

1.  更新都是先读后写,MySQL 读出数据,发现 a 值本来就是 2,不更新,直接返回

2.  MySQL 调用InnoDB 引擎提供的“修改为 (1,2)”这个接口,但是引擎发现值与原来相同不更新,直接返回

3.  InnoDB 认真执行“把这个值修改成 (1,2)",该加锁的加锁,该更新的更新

图 12 锁验证方式

B 的 update 被 blocked ,InnoDB 才能加锁,排除 1

图 13 可见性验证方式

A 第二个 select 是一致性读(快照读),看不见 B 更新。返回 (1,3)表示看见新版本,session A update 时生成。排除 2

答案 3,InnoDB ,该加锁的加锁,该更新更新

更新前判断一下,不用浪费 InnoDB 操作?其实 MySQL 是确认的。MySQL读的,确定 (id=1), 要写的 (a=3),看不出来“不需要修改”。验证:

图 14 可见性验证方式 -- 对照

补充说明:

上面都是在binlog_format=statement 下进行。如果是binlog_format=row且 binlog_row_image=FULL ,需在 binlog 记录所有字段,读数据时读出。

“既然读了就会判断”, 此时“返回 (1,2)”。

binlog_row_image=NOBLOB, 会读除 blob 外所有字段,结果还是(1,2)

图 15 binlog_row_image=FULL 读字段逻辑  

新加update_time on update current_timestamp,发现会加锁,提交update_time不变,binlog没生成,加锁实际没更新?

 timestamp 设置自动更新,更新“别的字段”时,MySQL 会读入所有涉及字段,不需要修改。

@郭江伟 同学提到了两个点,都非常好,有去实际验证。结论是这样的:第一,hexdump 看出来没改应该是 WAL 机制生效了,要过一会儿,或者把库 shutdown 看看。第二,binlog 没写是 MySQL Server 层知道行的值没变,所以故意不写的,这个是在 row 格式下的策略。你可以把binlog_format 改成 statement 再验证下。

评论1

酒馆生意好,老板把孔乙己的欠账记录记小黑板上并记己点菜单。吹牛,忘了叫几两酒了。又给老板说,老板把酒改成二两。老板也不确定孔乙己叫没叫酒,就去查菜单,发现孔乙己确实点了酒,但是本来就二两,也就难得麻烦了,又要修改小黑板,又要改菜单。直接就给孔乙己说已经改好了。😄

小二连忙过来拦住,“老板,又赊账一碟茴香豆。”

老板大惊,“我怎不知?”

小二道,“老板你方才看板时没拿记账笔,记账笔没人用,自然可用”

于是把店规“变账须用记账笔。” 改为

改帐均须动笔。纵为不变之帐,仍需覆写之

评论2

创建测试数据:

mysql> create table t(id int primary key auto_increment,a int );

mysql> insert into t values(1,2);

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

mysql> update t set a=2 where id=1;

Query OK, 0 rows affected (0.00 sec)

查看系统锁情况:

show engine innodb status

---TRANSACTION 958998, ACTIVE 51 sec

2 lock struct(s), heap size 1136, 1 row lock(s)

MySQL thread id 2, OS thread handle 139663691581184, query id 22 localhost root

mysql> show processlist;

+----+------+-----------+--------------------+---------+------+----------+------------------+

| Id | User | Host | db | Command | Time | State | Info |

+----+------+-----------+--------------------+---------+------+----------+------------------+

| 2 | root | localhost | sysbench | Sleep | 352 | | NULL |

| 3 | root | localhost | NULL | Sleep | 301 | | NULL |

+----+------+-----------+--------------------+---------+------+----------+------------------+

其中Thread id=2 为update会话,说明系统有锁

另一会话执行 update t set a=2 where id=1;

ERROR 1205 (HY000): Unknown error 1205 MySQL error code 1205 (ER_LOCK_WAIT_TIMEOUT): Lock wait timeout exceeded; try restarting transaction

提交第一个会话查看生成的binlog

### INSERT INTO `sysbench`.`t`

### SET

### @1=1 /* INT meta=0 nullable=0 is_null=0 */

### @2=2 /* INT meta=0 nullable=1 is_null=0 */

# at 858

#181217 14:28:21 server id 9012 end_log_pos 889 CRC32 0xf96f7fcb Xid = 20

COMMIT/*!*/;

# at 889

#181217 14:42:14 server id 9012 end_log_pos 930 CRC32 0x3de034ba Rotate to bin.000089 pos: 4

SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;

DELIMITER ;

# End of log file

/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;

/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

发现没有update的binlog产生,也就是说该语句在server层没有实际执行

用hexdump对比update前后的数据行,事务id和回滚id也没变,说明innodb没有实际更新行。

鉴于该语句产生行锁,有事务信息,没有实际修改,可判断innodb在更新前后值一样时不会实际更新数据

评论3

1.事务执行过程中,binlog像redo log一样记录到binlog_cache里,单独内存,redo log buffer

2.redo log buffer设置成全局参数,Binlog cache size也是global 的,5.5~5.7

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容

  • 我们就从一条 update 语句开始。 其实执行流程和查询流程一致,只是最后执行器执行的是找到这条数据,并进行更新...
    帅气的名称被占用阅读 1,618评论 2 4
  • MySQL中有六种日志文件 1、重做日志(redo log)、回滚日志(undo log)、二进制日志(binlo...
    SuperGu阅读 2,286评论 0 1
  • 凡是得不到的,都是想要的,越是容易得到的,越不珍惜。 小时候的天是蓝的,山是绿的,水是清的,只是生活有些艰难,后来...
    林科_bdd5阅读 179评论 0 2
  • 人有口是心非的时候,尤其是恋爱中的女人。多少人用言不由衷的话语掩饰敏感的内心,看似张扬强势的宣言其实是纸糊的老虎。...
    慢小小阅读 416评论 1 3
  • 宝贝 你特别幸福 因为你有两个双重的名字 一个叫儿童节,一个叫生日快乐 今天是一个别样的日子 全班30名同学都来给...
    zyl林阅读 296评论 1 2