跳转至

Vertica 锁和锁冲突

1. 介绍

当多个用户需要同时访问数据库时,使用锁(如读锁或写锁)。当多个用户尝试读取而其他用户写入数据库时​​,这可以防止数据被破坏或失效。

2. 在 Vertica 上运行的每个查询是否都需要锁?

如果事务隔离级别设置为默认的“Read Committed”,则不会,这意味着事务所做的任何更改在提交之前都不能被任何其他事务读取。这可以防止事务读取稍后回滚的另一个事务插入的数据。 Vertica 还有另一个事务隔离级别,即“Serializable“,它锁定表以防止查询的 WHERE 子句结果被其他事务更改。锁定表可能会影响性能,因为一次只有一个事务能够访问表。这是最严格的 SQL 事务隔离级别。 事务将保留其隔离级别,直到完成为止,即使会话的事务隔离级别在事务中途发生变化也是如此。Vertica 内部进程(例如 Tuple Mover 和刷新操作)和 DDL 操作始终在 SERIALIZABLE 隔离级别运行,以确保一致性。

3. 锁对象

哪些对象上可以加锁?

  • Tables
  • Projections

系统锁

  • Global Catalog (Meta-data global across all nodes)
  • Local Catalog (Meta-data local to a node)
  • Elastic Cluster

4. 锁兼容性矩阵

此表用于与其他用户的兼容性。 以下矩阵中带项目符号 (•) 的单元格显示哪些锁可同时用于同一对象。空单元格表示在当前(已授予)模式释放其对对象的锁之前,不会授予查询请求的模式。

Requested mode Granted mode
U T S I IV SI X D O
U
T
S
I
IV
SI
X
D
O

4. 锁类型介绍

对象锁

锁类型 描述
Usage (U) Vertica 使用使用锁 (U) 来执行 Tuple Mover 合并操作。
这些 Tuple Mover 操作在后台自动运行,因此,当对象以 U 模式锁定时,表上的其他操作(需要 O 锁或 D 锁的操作除外)都可以运行。
Tuple Mover (T) Vertica 使用 Tuple Mover (T) 锁来执行删除向量操作。
当删除向量工作开始时,Tuple Mover 操作会将表锁定模式从 U 升级到 T,这样就不会同时发生其他更新或删除。
Shared (S) 对在序列化事务隔离级别运行的 SELECT 查询使用共享 (S) 锁。
这允许查询并发运行,但 S 锁会导致事务按串行顺序运行。S 锁可确保一个事务不会影响另一个事务,直到一个事务完成并释放其 S 锁。

READ COMMITTED 事务模式下的选择操作不需要 S 表锁。有关更多信息,请参阅 事务
Insert (I) Vertica 需要插入 (I) 锁才能将数据插入表中。
多个事务可以同时将一个对象锁定在插入模式下,从而允许同时进行多个插入和批量加载。
此行为对于并行加载和高提取率至关重要。
Insert Validate (IV) 对于系统对启用的 PRIMARY 或 UNIQUE 键约束执行约束验证的插入操作,需要插入验证 (IV) 锁。
Shared Insert (SI) 当事务中同时发生读取和插入时,Vertica 需要共享插入 (SI) 锁。
SI 模式禁止删除/更新操作。SI 锁也由锁升级产生。
Exclusive (X) Vertica 在执行删除和更新时使用排他 (X) 锁。
只有 Tuple Mover 合并操作(U 锁)才能在具有 X 锁的对象上并发运行。
Drop Partition (D) DROP_PARTITIONS 要求对目标表添加 D 锁。
此锁仅与 I 锁操作兼容,因此在删除分区操作期间只允许执行表加载操作(例如 INSERT 和 COPY)。
Owner (O) 所有者 (O) 锁是最强的 Vertica 锁模式。
当对象的数据和结构发生变化时,它会获取 O 锁。
此类变化可能发生在某些 DDL 操作中,例如 DROP_PARTITIONS、TRUNCATE TABLE 和 ADD COLUMN。
当对象以 O 模式锁定时,它不能被任何模式下的另一个事务同时锁定。

4.2 系统锁

4.2.1 Global Catalog Locks

需要锁定跨所有节点的全局目录以进行以下操作。 在以下场景中采用 GCL (X) 锁定:

  • DDL 提交
  • DML 提交
  • 刷新
  • 恢复
  • 重分布数据
  • 邀请节点加入集群

这些 GCL 操作会阻止需要锁定的其他 GCL 操作。

4.2.2 Local Catalog Locks

仅在以下场景中采用 X 模式:

  • DML 和 DDL
  • Moveout
  • Mergeout

4.2.3 Elastic Cluster Locks

  • 弹性集群是指扩大或缩小集群以满足数据库的需求
  • 需要重新分布数据
  • 在进行段平衡时在节点上获取 EC 锁 (X)
  • 一次只有一个节点在进行段平衡。

5. 锁转换

通常,同一对象是来自不同会话的并发锁定请求的目标。下面的矩阵显示了 Vertica 如何响应同一对象上的多个锁定请求,如下所示:

  • 如果相应的锁定模式兼容,则将向对象上的并发请求授予锁定。例如,D(删除分区)和 I(插入)锁定兼容,因此 Vertica 可以向并发加载和删除分区操作授予同一张表上的多个锁定请求。
  • 对象上的并发请求的锁定模式不兼容,但请求还支持更高(更强)的锁定模式。在这种情况下,Vertica 会转换(升级)这些请求的锁定模式(例如,将 S 和 I 转换为 SI)。升级后的锁定模式使对象上的请求能够并发进行。
  • 对象上的并发请求的锁定模式不兼容,并且都无法升级为通用锁定模式。在这种情况下,对象锁定请求将排队并按顺序授予。
Requested mode Granted mode
U T S I IV SI X D O
U U T S I IV SI X D O
T T T S I IV SI X D O
S S S S SI SI SI X O O
I I I SI I IV SI X D O
IV IV IV SI IV IV SI X D O
SI SI SI SI SI SI SI X O O
X X X X X X X X O O
D D D O D D O O D O
O O O O O O O O O O

6. 锁强度

锁强度是指一种锁模式与另一种锁模式交互的能力。O 锁是最强的,与所有其他锁都不兼容。相反,U 锁是最弱的,可以与除 D 锁和 O 锁之外的所有其他锁同时运行。 下图描述了锁定模式强度的关系:

Lock Conflict Diagram

7. 监控锁能用到的系统表

7.1 Locks

用于查看所有节点的锁授予和请求。 提供有关锁请求、释放和尝试的信息,例如等待时间/计数和保持时间/计数。

=> select * from locks;

-[ RECORD 1 ]-----------+---------------------------------------------------------
node_names              | node01,node02,node03,node04
object_name             | Table:fact
object_id               | 45035996273772278
transaction_description | Txn: a000000000112b 'COPY fact FROM '/data_dg/fact.dat'
                          DELIMITER '|' NULL '\\N';'
lock_mode               | I
lock_scope              | TRANSACTION
request_timestamp       | 2011-04-17 14:01:07.662325-04
grant_timestamp         | 2011-04-17 14:01:07.662325-04

7.2 Lock_usage

提供有关锁请求、释放和尝试的信息,例如等待时间/计数和保持时间/计数。

=> SELECT * FROM lock_usage;

-[ RECORD 1 ]-+----------------------------------
node_name | v_myvdb_node0004
session_id | raster-f1.verticaco-13199:0x100
object_name | Global Catalog
mode | S
avg_hold_time | 00:00:00.032718
max_hold_time | 00:00:00.251213
hold_count | 34
avg_wait_time | 00:00:00.000048
max_wait_time | 00:00:00.000119
wait_count | 0
-[ RECORD 2 ]-+----------------------------------
node_name | v_myvdb_node0004
session_id | raster-f1.verticaco-13199:0x102
object_name | Global Catalog
mode | S
avg_hold_time | 00:00:00.038148
max_hold_time | 00:00:00.185088
hold_count | 34
avg_wait_time | 00:00:00.000049
max_wait_time | 00:00:00.000124
wait_count | 0

7.3 dc_lock_attempts

提供了锁定尝试的历史记录(已解决的请求)。

dbadmin=> select * from dc_lock_attempts;

-[ RECORD 1 ]------+--------------------------------------------------------------------
time | 2015-06-26 18:19:25.148806+00
node_name | v_test_crane_node0001
session_id | rchoudhary1-18296:0xd65a8
user_id | 45035996273704962
user_name | dbadmin
transaction_id | 45035996275166062
object | 2
object_name | Cluster Topology
mode | S
promoted_mode | S
scope | TRANSACTION
start_time | 2015-06-26 18:19:25.148792+00
timeout_in_seconds | 1800
result | granted
description | Granted immediately
-[ RECORD 2 ]------+--------------------------------------------------------------------
time | 2015-06-26 18:19:25.150532+00
node_name | v_test_crane_node0001
session_id | rchoudhary1-18296:0xd65a8
user_id | 45035996273704962
user_name | dbadmin
transaction_id | 45035996275166062
object | 0
object_name | Global Catalog
mode | X
promoted_mode | X
scope | TRANSACTION
start_time | 2015-06-26 18:19:25.150517+00
timeout_in_seconds | 300
result | granted
description | Granted immediately

7.4 dc_lock_releases

提供了锁释放的历史记录。

dbadmin=> select * from dc_lock_releases;
-[ RECORD 1 ]--+-----------------------------------------------------------------
time           | 2015-06-27 16:31:40.858302+00
node_name      | v_test_crane_node0001
session_id     | rchoudhary1-18296:0xe35a4
user_id        | 45035996273704962
user_name      | dbadmin
transaction_id | 45035996275229154
object         | 45035996275888532
object_name    | Table:retailsolutions.vs_parameters_session_raw_keys
mode           | U
grant_time     | 2015-06-27 16:31:40.857761+00
-[ RECORD 2 ]--+-----------------------------------------------------------------
time           | 2015-06-27 16:31:40.859978+00
node_name      | v_test_crane_node0001
session_id     | rchoudhary1-18296:0xe35a4
user_id        | 45035996273704962
user_name      | dbadmin
transaction_id | 45035996275229155
object         | 45035996275888532
object_name    | Table:retailsolutions.vs_parameters_session_raw_keys
mode           | U
grant_time     | 2015-06-27 16:31:40.85943+00

7.5 dc_lock_requests

提供锁请求的历史记录。

dbadmin=> select * from dc_lock_requests;

8. 常用的监控口径

8.1 正在执行的SQL锁情况

select /*+label(dbadmin_monlocks)*/
       object_name ObjectName,
       l.transaction_id TransactionID,
       ra.pool_name PoolName,
       lock_mode as M,
       substr(min(l.request_timestamp)::char(19),6,19) LockRequestTS,
       substr(max(l.grant_timestamp)::char(19),12,19) LockGrantTS,
       substr(min(ra.queue_entry_timestamp)::char(19),12,19) RQEntryTS,
       substr(max(ra.acquisition_timestamp)::char(19),12,19) RAcqTS,
       timestampdiff(s,min(ra.queue_entry_timestamp),max(ra.acquisition_timestamp)) RWaitS,
       timestampdiff(s,min(l.grant_timestamp),sysdate) LockHeldS,
       timestampdiff(s,max(ra.acquisition_timestamp),sysdate) AExecS,
       substr(replace(transaction_description,E'\r',''),instr(replace(transaction_description,E'\r',''),'''') + 1, 80) SQL
  from locks l left join resource_acquisitions ra using(transaction_id)
 group by 1,2,3,4,transaction_description
 order by LockRequestTS
;

8.2 所有锁的情况

select /*+label(dbadmin_monlocks)*/
    object_name ObjectName,
    l.transaction_id TransactionID,
    lock_mode as M,
    substr(request_timestamp::char(19),6,19) RequestTS,
    substr(grant_timestamp::char(19),12,19) GrantTS,
    timestampdiff(s,request_timestamp,nvl(grant_timestamp,sysdate)) RWaitS,
    substr(replace(transaction_description,E'\r',''),instr(replace(transaction_description,E'\r',''),'''') + 1, 80) SQL
  from locks l
 order by request_timestamp
;

8.3 正在执行的GCL X锁情况

--正在执行的GCL X锁情况
select /*+label(dbadmin_monlocks)*/
    object_name ObjectName,
    l.transaction_id TransactionID,
    lock_mode as M,
    substr(request_timestamp::char(19),6,19) RequestTS,
    substr(grant_timestamp::char(19),12,19) GrantTS,
    timestampdiff(s,request_timestamp,nvl(grant_timestamp,sysdate)) RWaitS,
    substr(replace(transaction_description,E'\r',''),instr(replace(transaction_description,E'\r',''),'''') + 1, 80) SQL
  from locks l
  where object_name = 'Global Catalog'
 order by request_timestamp
;

8.4 GCL X锁历史情况分析

--GCL X锁历史情况分析,从历史备份表中进行统计
select time::char(15), count(*) total_count,
       sum(case when description = 'Granted immediately' then 1 else 0 end) as Granted_immediately_count,
       sum(case when description = 'Granted after waiting' then 1 else 0 end) as Granted_after_waiting_count,
       avg(queued) avgQueuedTimeS,
       min(queued) minQueuedTimeS,
       max(queued) maxQueuedTimeS
  from (select time, timestampdiff('ss',start_time,time) as queued, node_name, transaction_id, object_name, mode, description
          from dc_lock_attempts
         where object_name = 'Global Catalog') x
 where time > sysdate -3
 group by 1
 order by 1;

扩展阅读