前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为什么MySQL默认的隔离级别是RR而大厂使用的是RC?

为什么MySQL默认的隔离级别是RR而大厂使用的是RC?

作者头像
CBeann
发布2023-12-25 19:41:08
2620
发布2023-12-25 19:41:08
举报
文章被收录于专栏:CBeann的博客CBeann的博客

1写作目的

现在的服务都是分布式,MySQL的集群架构也是一样。那么MySQL的集群架构中有一个点是读写分离,而读写分离是基于binlog实现的。那么接下来就MySQL的读写分离和binlog为突破点进行分析为什么大厂中的默认隔离级别是RC。总体来说以时间线为基准进行讲解。

2binlog格式

图片转自https://www.jianshu.com/p/981a30944412
图片转自https://www.jianshu.com/p/981a30944412

3为什么MySQL默认的隔离级别是RR

参考互联网项目中mysql应该选什么事务隔离级别 在Oracle,SqlServer中都是选择读已提交(Read Commited)作为默认的隔离级别,为什么Mysql不选择读已提交(Read Commited)作为默认隔离级别,而选择可重复读(Repeatable Read)作为默认的隔离级别呢?

首先要明确一点:MySQL需要主从复制!。主从复制需要binlog事务的隔离级别

历史原因:5.0版本及之前binlog只支持STATEMENT这种格式。为了支持主从复制,那么事务的隔离级别只能是可重复读(Repeatable Read)。

因为当binlog为STATEMENT格式,且隔离级别为读已提交(Read Commited)时,会有bug导致主从库的数据不一致。

如下图所示,在主(master)上执行如下事务。

在这里插入图片描述
在这里插入图片描述

此时在主(master)上执行下列语句

代码语言:javascript
复制
select * from test;

输出如下

代码语言:javascript
复制
+---+
| b |
+---+
| 3 |
+---+
1 row in set

但是,你在此时在从(slave)上执行该语句,得出输出如下

代码语言:javascript
复制
Empty set

这样,你就出现了主从不一致性的问题!原因其实很简单,就是在master上执行的顺序为先删后插!而此时binlog为STATEMENT格式,它记录的顺序为先插后删!从(slave)同步的是binglog,因此从机执行的顺序和主机不一致!就会出现主从不一致!

如何解决? 解决方案有两种。

  • 隔离级别设为可重复读(Repeatable Read),在该隔离级别下引入间隙锁。当Session 1执行delete语句时,会锁住间隙。那么,Ssession 2执行插入语句就会阻塞住!
  • 将binglog的格式修改为row格式,此时是基于行的复制,自然就不会出现sql执行顺序不一样的问题!奈何这个格式在mysql5.1版本开始才引入。

因此由于历史原因,mysql将默认的隔离级别设为可重复读(Repeatable Read),保证主从复制不出问题!

4为什么大厂MySQL设置的隔离级别是RC

  • RC和RR的一个很大的区别是RR解决了不可重复读的问题。但是仔细想一想,不可重复读是问题吗?其实不是问题。我第一次读到的是1,再次读的时候为2,中间有人把1修改为2,那我读取到2就没问题。RC反应的是真实数据的变迁。主要数据真实有效(没提交就是脏读,无效),为什么怕被别人读出来呢?
  • RR下有间隙锁,使用锁就会导致资源的消耗和等待。

5MySQL主从复制的三种方式

5.1异步复制

在这里插入图片描述
在这里插入图片描述
  • Slave 端的 IO 进程连接上 Master,向 Master 请求指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;
  • Master 接收到来自 Slave 的 IO 进程的请求后,负责复制的 IO 进程根据 Slave 的请求信息,读取相应日志内容,返回给Slave 的IO进程,并将本次请求读取的 bin-log 文件名及位置一起返回给 Slave 端 Slave 端的 IO
  • 进程接收到信息后,将接收到的日志内容依次添加到 Slave 端的 relay-log(中继日志) 文件的最末端,并将读取到的 Master端的 bin-log 的文件名和位置记录到 master-info 文件中,以便在下一次读取的时候能够清楚的告诉 Master:”我需要从某个 bin-log 的哪个位置开始往后的日志内容,请发给我”;
  • Slave 端的 Sql 进程检测到 relay-log(中继日志)中新增加了内容后,会马上解析 relay-log 的内容成为在 Master 端真实执行时候的那些可执行的内容,并在本地执行。

存在的问题: 主库的数据commit到binlog后则返回SUCCESS给客户端。因为binlog同步给slave是异步的,如果此时master提交而未同步给到slave,则数据发生丢失。

5.2半同步复制

在这里插入图片描述
在这里插入图片描述

主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间。所以,半同步复制最好在低延时的网络中使用。

首先明确一点:master上已提交,然后等待slave的ACK,最后返回给客户端结果。

存在的问题

幻读:当用户发起一个事务,该事务已经写入redo日志和binlog日志,所以该数据为有效状态。在RC隔离级别下其他事务是可以读取到的。如果在等待slave的ack过程中binlog还没传输到slave上,则其他事务查询该数据为修改后的数据,此时master宕机。slave上升为master。此时在查询新master则查询不到数据,出现幻读。 数据丢失:提高数据的安全性,但不能完全避免数据丢失。

5.3增强半同步复制

在这里插入图片描述
在这里插入图片描述

现在我们已经知道,在半同步环境下,主库是在事务提交之后等待Slave ACK,所以才会有数据不一致问题。所以这个Slave ACK在什么时间去等待,也是一个很关键的问题了。因此MySQL针对半同步复制的问题,在5.7.2引入了Loss-less Semi-Synchronous,在调用binlog sync之后,engine层commit之前等待Slave ACK。这样只有在确认Slave收到事务events后,事务才会提交。

首先明确一点:在等待ack的时候,master状态为未提交。

存在的问题: 在这种模式下解决了after_commit模式带来的幻读和数据丢失问题,因为主库没有提交事务。但也会有个问题,假设主库在存储引擎提交之前挂了,那么很明显这个事务是不成功的,但由于对应的Binlog已经做了Sync操作,从库已经收到了这些Binlog,并且执行成功,相当于在从库上多了数据,也算是有问题的,但多了数据,问题一般不算严重。

6参考

互联网项目中mysql应该选什么事务隔离级别 Mysql的异步复制 MySQL 半同步复制模式说明及配置示例

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-12-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1写作目的
  • 2binlog格式
  • 3为什么MySQL默认的隔离级别是RR
  • 4为什么大厂MySQL设置的隔离级别是RC
  • 5MySQL主从复制的三种方式
    • 5.1异步复制
      • 5.2半同步复制
        • 5.3增强半同步复制
        • 6参考
        相关产品与服务
        云数据库 MySQL
        腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档