MySQL · myrocks · 事务锁分析

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 概述MyRocks中RocksDB作为基于快照的事务引擎,其在事务支持上有别于InnoDB,有其自身的特点。在早期的月报[myrocks之事务处理] 中,我们对锁的实现有过简单的分析,本文会以一些例子来介绍MyRocks是如果来加锁解锁的。

概述

MyRocks中RocksDB作为基于快照的事务引擎,其在事务支持上有别于InnoDB,有其自身的特点。在早期的月报[myrocks之事务处理] 中,我们对锁的实现有过简单的分析,本文会以一些例子来介绍MyRocks是如果来加锁解锁的。

锁类型

MyRocks早期只支持排他锁,支持SELEC… IN SHARE MODE后,MyRocks才开始引入共享锁。

 /* Type of locking to apply to rows */
 enum { RDB_LOCK_NONE, RDB_LOCK_READ, RDB_LOCK_WRITE } m_lock_rows;

#587是关于共享锁的一个有趣BUG,有兴趣的同学可以看看。
MyRocks的锁都是内存锁,因此MyRocks事务不宜持有过多的锁,以避免占用过多的内存。
MyRocks通过参数rocksdb_max_row_locks来控制单个事务所持有锁的总数。另外,rocksdb锁系统还支持以下参数
max_num_locks:系统锁个数总限制
expiration_time:锁过期时间

如果锁个数超出限制,客户端会返回下面的错误

failed: 12054: Status error 10 received from RocksDB: Operation aborted: Failed to acquire lock due to max_num_locks limit

隔离级别

MyRocks的事务隔离级只支持的READ-COMMITED和REPEATABLE-READ。隔离级别的支持和snapshot密切相关,隔离级别为READ-COMMITED时,事务中每的个stmt都会建立一个snapshot, 隔离级别为REPEATABLE-REA时,只在事务开启后第一个stmt建立一次snapshot。MyRocks中隔离级别不同不会影响加锁和解锁的行为,因此,后面在分析MyRocks的加锁解锁时不区分隔离级别。

隐式主键

MyRocks支持创建无主键的表,但RocksDB作为KV存储,是需要KEY的。因此,RocksDB内部会给表增加一个名为”HIDDEN_PK_ID”的隐式主键列,此值自增,类似与自增列。此列对于MySQL server层是透明的,读取表数据时会自动跳过”HIDDEN_PK_ID”列。

对于无主键的表,MyRocks的锁都是加在隐式主键上的。

对于binlog复制来说,MyRocks隐式主键并不会提升复制速度,因为隐式主键对server层是透明的,主键列不会记入binlog。 因此,建议MyRocks表都指定主键。

加锁分析

以此表结构来分析各类语句的加锁情况。

create table t1(id int primary key, c1 int unique, c2 int, c3 int, key idx_c2(c2)) engine=rocksdb;
insert into t1 values(1,1,1,1);
insert into t1 values(2,2,2,2);
insert into t1 values(3,3,3,3);
insert into t1 values(4,4,4,4);
  • 示例 select
select * from t1;

MVCC, 普通读不加锁

  • 示例 select .. in share mode
select * from t1 where id=1 in share mode;

对主键id=1记录加S锁

  • 示例 select .. for update
select * from t1 where id=1 for update;

对主键id=1记录加X锁

  • 示例 insert
begin;
insert into t1 values(1,1,1,1);
rollback;

主键id=1加X锁 唯一索引c1=1加X锁

  • 示例 delete by主键
begin;
delete from t1 where id=1;
rollback;

主键id=1加X锁

  • 示例 delete by唯一索引
begin;
delete from t1 where c1=2;
rollback;

主键id=2加X锁,其他索引不加锁

  • 示例 delete by普通索引
begin;
delete from t1 where c2=3;
rollback;

主键id=3加X锁,其他索引不加锁

  • 示例 delete by无索引
begin;
delete from t1 where c3=4;
rollback;

对主键每条加X锁,其他索引不加锁
实际上server层过滤不符合条件的行会释放锁,最终只对主键id=4加X锁

  • 示例 delete by 主键不存在的行
begin;
delete from t1 where id=100;
rollback;

主键id=100加X锁

  • 示例 delete by 其他索引不存在的行
begin;
delete from t1 where c1=100;
rollback;

没有锁可以加

以上例子基本可以覆盖所有加锁的情况,再举例几个例子练习下

  • 示例 select for update
begin;
select * from t1 where  c2=3 for update;
rollback;

主键id=3加X锁, 其他索引不加锁

  • 示例 update更新无索引列
begin;
update t1 set c3=5 where c3=4;
rollback;

对主键每条加X锁,其他索引不加锁
实际上server层过滤不符合条件的行会释放锁,最终只对主键id=4加X锁

  • 示例 update更新索引列
begin;
update t1 set c2=5 where c3=4;
rollback;

对主键每条加X锁,其他索引不加锁
实际上server层过滤不符合条件的行会释放锁,最终只对主键id=4加X锁
同时会对唯一索引c2=5加X锁

对于无主键表的表说,RocksDB内部会有隐式主键,所加锁都在隐式主键上

解锁

事务提交或回滚时都会将事务所持有的锁都释放掉。
另外一种情况是,对于不满足查询条件的记录,MySQL会提前释放锁。

总结

  • MyRocks只会对主键和唯一索引加锁,普通索引不会加锁。
  • 只有插入或更新了唯一索引时,才会对唯一索引加锁,对唯一索引加锁的目的是为了保证唯一性。
  • 按主键锁定查找不存在的行时,会对不存在的行主键加X锁。
  • 按二级索引查找时,只会对主键加锁,不会对二级锁引加锁。
  • S锁只应用于SELECT … IN SHARE MODE语句。

堆栈

最后提供一些堆栈信息,方便学习

  • 走唯一索引对主键加锁
    #0  rocksdb::TransactionLockMgr::TryLock
    #1  rocksdb::PessimisticTransactionDB::TryLock
    #2  rocksdb::PessimisticTransaction::TryLock
    #3  rocksdb::TransactionBaseImpl::GetForUpdate
    #4  myrocks::Rdb_transaction_impl::get_for_update
    #5  myrocks::ha_rocksdb::get_for_update
    #6  myrocks::ha_rocksdb::get_row_by_rowid
    #7  get_row_by_rowid
    #8  myrocks::ha_rocksdb::read_row_from_secondary_key
    #9  myrocks::ha_rocksdb::index_read_map_impl
    #10 myrocks::ha_rocksdb::read_range_first
    #11 handler::multi_range_read_next
    #12 QUICK_RANGE_SELECT::get_next
    #13 rr_quick
    #14 mysql_delete
    #15 mysql_execute_command
    #16 mysql_parse
    #17 dispatch_command
    
  • 提交时解锁
    #0  rocksdb::TransactionLockMgr::UnLockKey
    #1  rocksdb::TransactionLockMgr::UnLock
    #2  rocksdb::PessimisticTransactionDB::UnLock
    #3  rocksdb::PessimisticTransaction::Clear
    #4  rocksdb::PessimisticTransaction::Commit
    #5  myrocks::Rdb_transaction_impl::commit_no_binlog
    #6  commit
    #7  myrocks::rocksdb_commit
    #8  ha_commit_low
    #9  TC_LOG_DUMMY::commit
    #10 ha_commit_trans
    #11 trans_commit
    #12 mysql_execute_command
    #13 mysql_parse
    #14 dispatch_command
    
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
16天前
|
关系型数据库 MySQL 数据库
【MySQL实战笔记】 06 | 全局锁和表锁 :给表加个字段怎么有这么多阻碍?-01
【4月更文挑战第17天】MySQL的锁分为全局锁、表级锁和行锁。全局锁用于全库备份,可能导致业务暂停或主从延迟。不加锁备份会导致逻辑不一致。推荐使用`FTWRL`而非`readonly=true`因后者可能影响其他逻辑且异常处理不同。表级锁如`lock tables`限制读写并限定操作对象,常用于并发控制。元数据锁(MDL)在访问表时自动加锁,确保读写正确性。
66 31
|
3天前
|
存储 关系型数据库 MySQL
MySQL的锁机制
MySQL的锁机制主要用于管理并发事务对数据的一致性和完整性的访问控制
17 4
|
5天前
|
SQL 安全 关系型数据库
【Mysql-12】一文解读【事务】-【基本操作/四大特性/并发事务问题/事务隔离级别】
【Mysql-12】一文解读【事务】-【基本操作/四大特性/并发事务问题/事务隔离级别】
|
7天前
|
存储 关系型数据库 MySQL
MySQL 8 索引原理详细分析
了解索引的详细原则,不仅有助于优化,能把索引搞清楚的,面试中优势也会很突显。 关于数据库优化的话题,V哥觉得还有很多地方可以聊,如果你有兴趣,欢迎关注一起讨论。
MySQL 8 索引原理详细分析
|
8天前
|
存储 关系型数据库 MySQL
Mysql学习--深入探究索引和事务的重点要点与考点
Mysql学习--深入探究索引和事务的重点要点与考点
|
8天前
|
存储 SQL 关系型数据库
|
8天前
|
存储 SQL 关系型数据库
Mysql_数据库事务
Mysql_数据库事务
|
10天前
|
缓存 关系型数据库 MySQL
【专栏】MySQL高可用与性能优化——从索引到事务
【4月更文挑战第27天】本文探讨了提升MySQL性能和高可用性的策略,包括索引优化、查询优化和事务管理。通过合理使用B-Tree和哈希索引,避免过度索引,以及优化查询语句和利用查询缓存,可以改善性能。事务管理中,应减小事务大小并及时提交,以保持系统效率。主从或双主复制可增强高可用性。综合运用这些方法,并根据实际需求调整,是优化MySQL的关键。
|
10天前
|
Java 关系型数据库 MySQL
{MySQL}索引事务和JDBC
{MySQL}索引事务和JDBC
19 0
|
11天前
|
关系型数据库 MySQL 数据库
MySQL锁解密:读锁与写锁
【4月更文挑战第20天】
21 1

相关产品

  • 云数据库 RDS MySQL 版