当前位置:首页 > 技术分析 > 正文内容

面试回答:为什么MySQL默认RR隔离级别,大厂要改成RC?

1. 先说结论

MySQL默认的隔离级别是可重复读(Repeatable Read, RR),但阿里等大厂通常会将其改为读已提交(Read Committed, RC)。主要原因是为了提升系统的吞吐量和并发性能,同时通过其他手段(如程序逻辑优化)来规避可能出现的幻读和不可重复读问题。


2. 从源码角度深入分析

(1) RR和RC的锁机制

在RR隔离级别下,MySQL使用了Next-Key Lock,这是一种组合锁,包括Record Lock(记录锁)和Gap Lock(间隙锁)。这种锁机制可以有效防止幻读,但也带来了额外的性能开销。

  • Record Lock:锁定具体的记录。
  • Gap Lock:锁定记录之间的间隙。
  • Next-Key Lock:锁定记录及其之间的间隙,范围是左开右闭的。

在RC隔离级别下,MySQL只使用Record Lock,不会添加Gap LockNext-Key Lock。这意味着在RC级别下,虽然解决了脏读问题,但可能会出现不可重复读和幻读问题。

(2) RR和RC的快照读机制

在RR级别下,事务会以第一次普通读时快照数据为准,该事务后续其他的普通读都是读的该份快照数据。这需要维护多个版本的数据,增加了内存和计算开销。

而在RC级别下,每次读取数据时,MySQL都会生成一个新的快照版本,读取最新的数据。这种机制减少了锁的使用,提高了并发性能,但可能会导致不可重复读和幻读问题。

从源码角度看,RR的间隙锁和一致性视图的生成会导致更多的锁竞争和资源消耗,尤其是在高并发场景下,这可能会成为性能瓶颈。而RC通过减少锁的范围和动态生成一致性视图,能够更好地支持高并发


3. 真实案例警示

案例背景:

某大厂的订单系统在高并发场景下,使用RR隔离级别时,频繁出现锁等待和死锁问题,导致系统响应变慢。

问题复现(Demo):

-- 表结构
CREATE TABLE orders (
    id INT PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10, 2)
);

-- 事务1(RR级别)
START TRANSACTION;
SELECT * FROM orders WHERE user_id = 1 FOR UPDATE; -- 锁住user_id=1的记录及其间隙

-- 事务2(RR级别)
START TRANSACTION;
INSERT INTO orders (id, user_id, amount) VALUES (2, 1, 100.00); -- 被间隙锁阻塞

在RR级别下,事务1的SELECT ... FOR UPDATE会锁住user_id=1的记录及其间隙,导致事务2的插入操作被阻塞。如果并发量高,这种锁冲突会迅速累积,导致系统性能下降。

经过分析,我们发现RR隔离级别下的间隙锁虽然解决了幻读问题,但在高并发写场景下,间隙锁会严重影响性能。因此,我们将隔离级别改为RC,同时通过程序逻辑优化来避免幻读和不可重复读问题,最终系统性能显著提升。


4. 实验数据比对

为了更直观地展示RR和RC隔离级别在性能上的差异,我们进行了一组实验对比:

实验环境

  • 数据库:MySQL 8.0
  • 测试工具:Sysbench
  • 测试场景:高并发写入(100个并发线程,持续10分钟)

实验结果

隔离级别

并发线程数

吞吐量(TPS)

平均响应时间(ms)

死锁次数

RR

100

1200

350

5

RC

100

1800

220

0

从实验数据可以看出:

  • 在高并发写场景下,RC隔离级别的吞吐量比RR隔离级别高出50%(1800 TPS vs 1200 TPS)。
  • 平均响应时间减少了近40%(220ms vs 350ms)。
  • 死锁次数显著减少(RC为0次,RR为5次)。

5. 最佳实践建议或大厂解决方案

(1) 隔离级别调整

  • 将MySQL默认隔离级别从RR改为RC。通过修改配置文件或动态设置:
  • sql复制
  • SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
  • 这样可以显著减少锁的开销,提升系统并发性能。

(2) 程序逻辑优化

  • 避免幻读和不可重复读问题:虽然RC隔离级别会带来幻读和不可重复读的风险,但可以通过程序逻辑来规避。例如:
  • 在事务中尽量避免多次查询同一数据。
  • 使用乐观锁或悲观锁机制,确保数据一致性。
  • 在关键业务逻辑中,通过加锁(如SELECT ... FOR UPDATE)来防止并发问题。

(3) 缓存与分布式锁

  • 引入缓存机制:使用Redis等分布式缓存,减少对数据库的直接访问,从而降低锁的争用。
  • 分布式锁:在分布式系统中,通过分布式锁(如Redisson)来协调多个服务实例之间的并发操作。

6. 记住一句话

“在高并发场景下,性能优化比严格的事务隔离更重要,通过合理的程序设计和架构优化,可以在降低隔离级别的情况下,依然保证系统的稳定性和数据一致性。”

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/3957.html

分享给朋友:

“面试回答:为什么MySQL默认RR隔离级别,大厂要改成RC?” 的相关文章

「干货」通俗易懂的Deno 入门教程

作者: semlinker转发链接:https://mp.weixin.qq.com/s/2eqRTsf_z7Bcs6dziXe73Q一、Deno 简介Deno 是一个 JavaScript/TypeScript 的运行时,默认使用安全环境执行代码,有着卓越的开发体验。Deno 含有以下功能亮点:默...

Vue.js 组件通信的 3 大妙招

在 Vue.js 中,组件化是其核心概念之一,允许你将复杂的界面拆分成多个独立的、可复用的组件。在构建大型应用时,如何高效地在组件之间传递数据和触发事件是非常重要的。Vue.js 提供了多种方式来处理组件间的通信,下面是最常用的 3 种方式:1.父子组件通信:通过 Props 和 Events在 V...

学无止境:Git 如何优雅地回退代码

来源:https://zhenbianshu.github.io前言从接触编程就开始使用 Git 进行代码管理,先是自己玩 Github,又在工作中使用 Gitlab,虽然使用时间挺长,可是也只进行一些常用操作,如推拉代码、提交、合并等,更复杂的操作没有使用过,看过的教程也逐渐淡忘了,有些对不起 L...

10分钟搞定gitlab-ci自动化部署

gitlab-ci 是持续集成工具/自动化部署工具,类似 jenkins。持续集成 是将代码集成到共享存储库并尽可能早地自动构建/测试每个更改的实践 - 通常一天几次。概述在编码完成时都会进行打包发布过程,如果每次都手动操作这一步骤就会浪费时间,效率低下。所以就有了持续集成。准备事项请提前安装以下软...

Java教程:gitlab-使用入门

1 导读本教程主要讲解了GitLab在项目的环境搭建和基本的使用,可以帮助大家在企业中能够自主搭建GitLab服务,并且可以GitLab中的组、权限、项目自主操作GitLab简介GitLab环境搭建GitLab基本使用(组、权限、用户、项目)2 GitLab简介GitLab是整个DevOps生命周期...

前后端分离自动化运维平台开发

运维平台采用前后端分离:前端vue,框架vue-element-admin;后端python,框架django-rest-framework.目前运维平台模块如下:1、 CMDB管理应用管理、环境管理、开发语言管理、产品项目管理、资产管理2、 构建发布持续构建、持续部署、Jar工程依赖构建3、 容器...