OB锁分析
OB锁机制:https://www.oceanbase.com/docs/community/observer-cn/V3.1.3/0000000000161645
ob的锁是行级锁,没有表锁的概念,行级锁只有互斥行锁。
OceanBase 数据库使用了多版本两阶段锁来维护其并发控制模型的正确性,锁机制是保证正确的数据并发性和一致性很重要的一点。
session 1:
begin;
select * from t1 where a = 1566 for update;
session 2:
begin; select * from t1 where a = 1566 for update;
此时查看锁的信息:
SELECT * FROM v$lock;
可以看到addr直接定位到锁住的行
SELECT * FROM gv$lock_wait_stat;
1. 锁与DDL测试
session 1 :
MySQL [test]> select now(6); begin;select * from t3 for update;
+----------------------------+
| now(6) |
+----------------------------+
| 2022-05-23 11:23:42.763281 |
+----------------------------+
1 row in set (0.027 sec)
Query OK, 0 rows affected (0.012 sec)
+----+-------+----------------------+----------------------+-------+
| a | b | c | d | e |
+----+-------+----------------------+----------------------+-------+
| 1 | 6908 | w)/gf.} | = | 18937 |
| 2 | 71417 | dj>;tu | 1[b=/. | 15170 |
| 3 | 3759 | zpaugx8)irf2>5 | ]e`m;$+d | 63122 |
| 4 | 36326 | {%qb53:c/b(:y]qd((. | k | 22437 |
| 5 | 57946 | 41xauq9;xv<q#v[3?`[t | -%!}rh{;.({wpcf | 52579 |
| 6 | 55555 | sb^u/zuu}kwbg8;j | r5a#"?h0]& | 53704 |
| 7 | 79089 | u"#d | +e0vn?}t | 4398 |
| 8 | 55156 | *cgw9}*@,lgn*jqir+8o | -mla(k`l | 2222 |
| 9 | 81002 | .:9e43!qsf7qdg6/a;zg | p>:3)jrd##,hm|ea09si | 47558 |
| 10 | 17303 | |:f()m | rd29- | 22337 |
+----+-------+----------------------+----------------------+-------+
10 rows in set (0.027 sec)
MySQL [test]> desc t3;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| a | int(11) | NO | PRI | NULL | auto_increment |
| b | int(11) | YES | | NULL | |
| c | varchar(20) | YES | | NULL | |
| d | varchar(20) | YES | | NULL | |
| e | int(11) | YES | | NULL | |
| f | int(11) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
6 rows in set (0.045 sec)
MySQL [test]> update t3 set f=b+e;
ERROR 6002 (25000): transaction needs rollback
session 2 :
MySQL [test]> select now(6); begin; alter table t3 add column (f int);
+----------------------------+
| now(6) |
+----------------------------+
| 2022-05-23 11:24:53.949363 |
+----------------------------+
1 row in set (0.017 sec)
Query OK, 0 rows affected (0.094 sec)
可以看到行锁住的时候是可以执行DDL的,当执行更新的时候,事务会失败,提示需要rollback
。
2. 同一行不同字段之间的测试
在更新同一行的不同列时,事务依旧会互相阻塞,如此选择的原因是为了减小锁数据结构在行上的存储开销。而更新不同行时,事务之间不会有任何影响。
session 1 :
select now(6); begin;select e from t3 where a = 2 for update;
session 2 :
select now(6); begin;select f from t3 where a = 2 for update;
一段时间之后锁等待超时
OceanBase 数据库使用了多版本两阶段锁,事务的修改每次并不是原地修改,而是产生新的版本。因此读取可以通过一致性快照获取旧版本的数据,因而不需要行锁依旧可以维护对应的并发控制能力,因此能做到执行中的读写不互斥,这极大提升了 OceanBase 数据库的并发能力。
3. 数据库锁机制的存储
锁存储在行上,从而减少内存中所需要维护的锁数据结构带来的开销。在内存中,当事务获取到行锁时,会在对应的行上设置对应的事务标记,即行锁持有者。当事务尝试获取行锁时,会通过对应的事务标记发现自己不是行锁持有者而放弃并等待或发现自己是行锁持有者后获得行的使用能力。当事务释放行锁后,就会在所有事务涉及的行上解除对应的事务标记,从而允许之后的事务继续尝试获取。
4. 死锁的机制
ob对于死锁的解决是通过几个超时机制。
基于超时的死锁解决
OceanBase 数据库当前主要依赖超时回滚机制来解决业务逻辑上的死锁。
存在三种超时机制用来解决对应的问题:
- 锁超时机制:配置项名称为
ob_trx_lock_timeout
,默认为语句超时时间,若加锁等待超过锁超时时间,则会回滚对应的语句,并返回锁超时对应的错误码。此时,由于某一个循环依赖中的资源依赖已经消失,因此就不再存在死锁。以事务 B 获取资源 C 超时为例,只要事务 B 结束,则事务 A 就可以获取到对应的资源 D。 - 语句超时机制:配置项名称为
ob_query_timeout
,默认为10s
,若加锁等待超过语句超时时间,则会回滚对应的语句,并返回语句超时对应的错误码。此时,由于某一个循环依赖中的资源依赖已经消失,因此就不再存在死锁。以事务 B 获取资源 C 超时为例,只要事务 B 结束,则事务 A 就可以获取到对应的资源 D。 - 事务超时机制:配置项名称为
ob_trx_timeout
,默认为100s
,若加锁等待超过事务超时时间,则会回滚对应的事务,并返回语句事务对应的错误码。由于某一个循环依赖中的资源依赖已经消失,因此就不再存在死锁。以事务 B 超时为例,由于事务 B 结束,事务 A 就可以获取到对应的资源 D。