轻松掌握锁冲突问题的排查方法——《OceanBase诊断系列》之八

news2024/11/16 15:57:16

1. 前言

OceanBase数据库通过两阶段封锁机制确保读写事务并发控制的正确性。在高冲突场景下,事务处理中经常会遇到行锁冲突的问题。然而,许多OceanBase用户对于何时发生锁冲突,锁冲突的表现如何,以及如何排查锁冲突的原因,甚至于定位具体的行与锁冲突的会话。本文为读者提供一个系统的方法,帮助大家有效排查和解决锁冲突问题。

2. OceanBase 3.x & 4.1 锁冲突问题排查指北

以行锁为单位,可以抽象出与行锁有密切关系的两个对象:行锁的持有者,行锁的等待者。如果能够将这两个信息进行监控,那么对排查行锁的相关问题,将带来很大的帮助。本质来讲,行锁冲突都是由事务引起的。上述两个对象,都是隶属于事务,因此对活跃事务的监控也是必不可少的。基于以上分析,我们对不同的角色,分别实现了不同的虚拟表,用于展示上述信息,具体为:行锁持有者(__all_virtual_trans_lock_stat),行锁等待者(__all_virtual_lock_wait_stat),活跃事务(__all_virtual_trans_stat

2.1 活跃事务(__all_virtual_trans_stat)

OceanBase (root@oceanbase)> desc __all_virtual_trans_stat;
+---------------------------+---------------+------+-----+---------+-------+
| Field                     | Type          | Null | Key | Default | Extra |
+---------------------------+---------------+------+-----+---------+-------+
| tenant_id                 | bigint(20)    | NO   | PRI | NULL    |       |
| svr_ip                    | varchar(32)   | NO   | PRI | NULL    |       |
| svr_port                  | bigint(20)    | NO   | PRI | NULL    |       |
| inc_num                   | bigint(20)    | NO   | PRI | NULL    |       |
| session_id                | bigint(20)    | NO   |     | NULL    |       |
| proxy_id                  | varchar(512)  | NO   |     | NULL    |       |
| trans_type                | bigint(20)    | NO   |     | NULL    |       |
| trans_id                  | varchar(512)  | NO   |     | NULL    |       |
| is_exiting                | bigint(20)    | NO   |     | NULL    |       |
| is_readonly               | bigint(20)    | NO   |     | NULL    |       |
| is_decided                | bigint(20)    | NO   |     | NULL    |       |
| active_memstore_version   | varchar(64)   | NO   |     | NULL    |       |
| partition                 | varchar(64)   | NO   |     | NULL    |       |
| participants              | varchar(1024) | NO   |     | NULL    |       |
| autocommit                | bigint(20)    | NO   |     | NULL    |       |
| trans_consistency         | bigint(20)    | NO   |     | NULL    |       |
| ctx_create_time           | timestamp(6)  | YES  |     | NULL    |       |
| expired_time              | timestamp(6)  | YES  |     | NULL    |       |
| refer                     | bigint(20)    | NO   |     | NULL    |       |
| sql_no                    | bigint(20)    | NO   |     | NULL    |       |
| state                     | bigint(20)    | NO   |     | NULL    |       |
| part_trans_action         | bigint(20)    | NO   |     | NULL    |       |
| lock_for_read_retry_count | bigint(20)    | NO   |     | NULL    |       |
+---------------------------+---------------+------+-----+---------+-------+
23 rows in set (0.01 sec)

该表中展示了该集群中所有参与者上下文的当前状态,关键参数说明如下:
svr_ip           		   表示该上下文创建的server地址;
session_id				   表示该事务所对应session的唯一标识;
proxy_id,		   	       表示客户端(proxy/java client)所对应的”ip:port“
trans_id,		   	       表示事务的唯一标识
is_exiting,		   	   当前的事务上下文是否正在退出
partition,		           当前的事务上下文在哪个分区上创建
participants,	           当前事务的参与者列表
ctx_create_time,          事务上下文创建的时间;
ref,			           表示context当前的引用计数
sql_no,			       表示当前context上最后一次执行sql的sql_no
state,			           表示context当前的状态:INIT/PREPARE/COMMIT/ABORT/CLEAR,值域为0/1/2/3/4
part_trans_action, 	   表示当前context最后一次操作的动作:START_TASK/END_TASK/COMMIT
lock_for_read_retry_count  表示当前context在table scan过程中,是否遇到过锁冲突重试,值越大,表示冲突越严重。

2.2 行锁持有者(__all_virtual_trans_lock_stat)

OceanBase (root@oceanbase)> desc __all_virtual_trans_lock_stat;
+-----------------+--------------+------+-----+---------+-------+
| Field           | Type         | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+-------+
| tenant_id       | bigint(20)   | NO   | PRI | NULL    |       |
| trans_id        | varchar(512) | NO   | PRI | NULL    |       |
| svr_ip          | varchar(32)  | NO   | PRI | NULL    |       |
| svr_port        | bigint(20)   | NO   | PRI | NULL    |       |
| partition       | varchar(64)  | NO   | PRI | NULL    |       |
| rowkey    | varchar(512) | NO   | PRI | NULL    |       |
| session_id      | bigint(20)   | NO   |     | NULL    |       |
| proxy_id        | varchar(512) | NO   |     | NULL    |       |
| ctx_create_time | timestamp(6) | YES  |     | NULL    |       |
| expired_time    | timestamp(6) | YES  |     | NULL    |       |
+-----------------+--------------+------+-----+---------+-------+
10 rows in set (0.00 sec)

该表记录以行为单位,记录了当前集群所有活跃事务持有行的相关信息;关键参数说明如下:

rowkey,表示内部表示的行消息
session_id,proxy_id,trans_id等其他参数都是为了跟活跃事务对应起来。

2.3 行锁等待者(写锁)__all_virtual_lock_wait_stat

OceanBase (root@oceanbase)> desc __all_virtual_lock_wait_stat;
+-----------------+---------------------+------+-----+---------+-------+
| Field           | Type                | Null | Key | Default | Extra |
+-----------------+---------------------+------+-----+---------+-------+
| svr_ip          | varchar(32)         | NO   | PRI | NULL    |       |
| svr_port        | bigint(20)          | NO   | PRI | NULL    |       |
| table_id        | bigint(20)          | NO   | PRI | NULL    |       |
| rowkey          | varchar(512)        | NO   | PRI | NULL    |       |
| addr            | bigint(20) unsigned | NO   | PRI | NULL    |       |
| need_wait       | tinyint(4)          | NO   |     | NULL    |       |
| recv_ts         | bigint(20)          | NO   |     | NULL    |       |
| lock_ts         | bigint(20)          | NO   |     | NULL    |       |
| abs_timeout     | bigint(20)          | NO   |     | NULL    |       |
| try_lock_times  | bigint(20)          | NO   |     | NULL    |       |
| time_after_recv | bigint(20)          | NO   |     | NULL    |       |
| session_id      | bigint(20)          | NO   |     | NULL    |       |
| block_session_id | bigint(20)          | NO   |     | NULL    |       |
| type             | bigint(20)          | NO   |     | NULL    |       |
| lock_mode        | bigint(20)          | NO   |     | NULL    |       |
+-----------------+---------------------+------+-----+---------+-------+
12 rows in set (0.00 sec)

该表统计了当前集群中,所有正在等待行锁的请求/语句的相关信息,关键参数说明如下:
session_id,proxy_id,trans_id等其他参数都是为了跟活跃事务对应起来,不再一一赘述。
lock_ts,表示该请求开始等锁的时间点;(us)
abs_timeout,该语句的绝对超时时间(us)
try_lock_times,表示该语句曾经尝试过加锁的次数,值越大,表示锁冲突越严重
block_session_id, 表示第一个等在这个行上的事务的session

3. OB >= 4.2 锁冲突问题排查指北

随着 4.2 版本(G)V$OB_LOCKS视图的引入,锁冲突问题排查有了更加简单、直接的方法,我们基本实现了在一张视图内排查锁冲突问题。

3.1 (G)V$OB_LOCKS 介绍

字段类型是否为 NULL描述
SVR_IPVARCHAR2(46)NO持锁或请求锁的 OBServer 节点的 IP 地址
SVR_PORTNUMBER(38)NO持锁或请求锁的 OBServer 节点的端口号
TENANT_IDNUMBER(38)NO持锁或请求锁的租户的 ID
TRANS_IDNUMBER(38)NO持锁或请求锁的事务 ID
TYPEVARCHAR2(9)NO锁类型:TM:表锁TX:事务锁TR:行锁
ID1NUMBERNO锁标识符 1:表锁:可能是 TABLE_ID,也可能是 TABLET_ID事务锁:TX_ID行锁:TABLET_ID
ID2VARCHAR2(553)NO锁标识符 2:表锁:NULL事务锁:NULL行锁:TX_ID + 行 rowkey
LMODEVARCHAR2(4)NO当前持有锁的模式:NONE:表示未持有任何锁SS:ROW SHARESX:ROW EXCLUSIVES:SHARESSX:SHARE ROW EXCLUSIVEX:EXCLUSIVE
REQUESTVARCHAR2(8)NO当前请求锁的模式:NONE:表示未请求任何锁SS:ROW SHARESX:ROW EXCLUSIVES:SHARESSX:SHARE ROW EXCLUSIVEX:EXCLUSIVE
CTIMENUMBER(38)NO持有或等待锁的时间,单位为秒
BLOCKNUMBERNO表示当前事务请求的锁是否被其他事务持有:0:表示请求的锁未被其他事务持有,即该事务持有锁1:表示请求的锁被其他事务持有,即该事务被阻塞

锁视图中TYPE列表示了锁的类型,目前 Oceanbase 主要展示以下 3 种类型的锁:

  • 表锁(TM):即表 / 分区(tablet)上的锁。通常 insert / update / delete 等 dml 操作会产生分区级表锁锁,而 ddl 操作会产生表级表锁,这是由表锁的设计决定的。
  • 行锁(TR):即写行时上的锁。在 Oceanbase 的实现中,并不存在通常意义上理解的狭义行锁(即支持读 / 写等多种模式的实际存在的锁结构),而是通过行上是否有活跃事务来表现。因此,行锁可以理解为事务锁的一种特例。
  • 事务锁(TX):最常见的锁,通常可以理解为在事务内做过写操作即会产生事务锁。事务锁可以理解为行锁的退化形式,当无法维护事务到行的映射关系时,行锁即会转换成事务锁。

行锁和事务锁有着密切的关联,为了避免歧义和混乱,在(G)V$OB_LOCKS的实际实现中,我们不区分行锁和事务锁的退化 / 特例关系,而是采用了全量维护的方式。这意味着,如果一个事务持有行锁,那么其一定也持有自己的事务锁。

3.2 锁冲突排查流程

由于(G)V$OB_LOCKS目前不展示实际持锁的 session_id,因此以下的排查手段都只获取持锁的 trans_id。

  • 应急场景

在获取到持锁的 trans_id 后,通过(G)V$OB_TRANSACTION_PARTICIPANTS关联 trans_id 对应的 session_id,并通过kill session_id回滚对应事务。

  • 非应急场景

在获取到持锁的 trans_id 后,确认该事务为什么一直不解锁。不解锁的原因非常多样,可以通过 trans_id 在 observer.log 中过滤相关日志。常见的不解锁原因有以下几个:

  1. 长事务,即持锁事务本身很复杂,导致其长时间执行不结束。可通过持锁事务的 trans_id 过滤__all_virtual_processlist表,观察事务是否悬挂在某条 sql 请求上;或通过日志观察事务的对应 trace 中 slow query 相关的日志,定位哪条 sql 执行慢;
  2. 锁冲突,即该事务也在等其他事务的锁。对于该问题可先通过(G)V$OB_LOCKS过滤该 trans_id,检查是否有BLOCK=1的行,若有则进一步确认该持锁事务的不解锁原因,若无则通过 trans_id 过滤 observer.log 日志,确认悬挂过程中是否有其请求锁时报 -6005 报错(需要确认非该 trans_id 持锁报 -6005,例如该 trans_id 为 conflict_tx_id)。

说明:日志中-6x的错误码是事务相关的,其-6003/-6004/-6005和锁相关。

-6001:ERROR 6001 (25000): OB-6001:Transaction set changed during the execution:事务在执行过程中SET改变。事务回滚。
-6002: ERROR 6002 (40000): OB-6002:transaction is rolled back:事务被回滚。
-6003:ERROR 1205 (HY000): OB-1205:Lock wait timeout exceeded; try restarting transaction:锁等待时间已经超过超时时间,尝试重新启动事务。当前SQL失败,不改变事务状态,需要应用重试或做其他处理。 
-6004: ERROR 6004 (HY000): OB-6004:Shared lock conflict:执行INSERT/UPDATE/DELETE时,行锁冲突。
-6005:ERROR 6005 (HY000): OB-6005: Trylock row conflict:获取行锁冲突。
-6210:ERROR (25000): OB-4012:Transaction is timeout:事务超时。需要明确发起回滚才可以继续复用当前连接。
-6211:ERROR 6211 (25000): OB-6002:Transaction is killed:事务被杀。数据库端事务会回滚。
-6213:ERROR 6002 (HY000): OB-6002:Transaction context does not exist:事务内容不存在。数据库端事务会回滚。
-6224: ERROR 6002 (25000): OB-6002:transaction need rollback:事务需要回滚。不需要客户端发起回滚,数据库端事务会回滚。
-6225:ERROR 4012 (25000): OB-4012:Transaction result is unknown:事务结果未知。数据库端事务可能已提交或者回滚。需要业务重试。
-6226: ERROR 1792 (25006): OB-1792:Cannot execute statement in a READ ONLY transaction:不能在只读事务中执行语句。

同时如果你的环境是通过ocp部署的,还可以通过里面的SQL诊断的TOP SQL页面过滤重试次数大于0的SQL,也可以初步筛查可能的SQL.

1709171343

如果不是通过ocp部署的集群,也可以通过查询gv$sql_audit(4.x版本以后是gv$ob_sql_audit) 其中的retry_cnt字段数值大于0,是有可能发生了锁冲突的。是否真的发生了锁冲突,需要进一步通过日志来确认。在日志中出现-6003/-6004-6005的错误码则发生了锁冲突。日志分析推荐一个非常轻量的黑屏小工具obdiag。链接: OceanBase分布式数据库-海量数据 笔笔算数  , 安装配置好后可执行obdiag analyze log分析observer的日志,看是否有-6003/-6004-6005的错误日志。

4. 锁冲突排查思维导图

1709137633

5. 王炸:obdiag 一键诊断锁冲突

obdiag官网文档参见: OceanBase分布式数据库-海量数据 笔笔算数

使用 obdiag rca 命令可帮助 OceanBase 数据库相关的诊断信息分析,目前支持对 OceanBase 的异常场景进行分析,找出可能导致问题的原因。

obdiag rca list # 列出所有的根因分析场景
obdiag rca run --scene=<scene_name> #执行具体场景的根因分析

scene_name 包含如下:

  • disconnection:一键断连诊断,基于obproxy的诊断日志。
  • major_hold: 一键卡合并诊断。
  • lock_conflict: 一键锁冲突诊断。

示例:分析卡合并场景

obdiag rca run --scene=lock_conflict

6. 附录

  • obdiag 官方文档: OceanBase分布式数据库-海量数据 笔笔算数
  • obdiag github地址: GitHub - oceanbase/oceanbase-diagnostic-tool: OceanBase Diagnostic Tool is designed to help OceanBase users quickly gather necessary information and analyze the cause of the problem.
第一篇如何修炼成“神医”——《OceanBase诊断系列》之一
第二篇走进SQL审计视图——《OceanBase诊断系列》之二
第三篇一键操作敏捷诊断工具obdiag收集诊断信息实践——《OceanBase诊断系列》之三
第四篇一键操作敏捷诊断工具obdiag分析OB集群日志设计与实践——《OceanBase诊断系列》之四
第五篇专为OceanBase打造的巡检工具已推出!给OceanBase进行一次体检吧——《OceanBase诊断系列》之五
第六篇obdiag帮你读懂全链路诊断日志——《OceanBase诊断系列》之六
第七篇如何排查合并问题——《OceanBase诊断系列》之七
第八篇一文教你轻松掌握锁冲突问题的排查方法——《OceanBase诊断系列》之八

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1508628.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python爬虫(6)之处理数组

1、拆分数组 1、spilt&#xff08;&#xff09;函数 此函数的用处是将数组均分成几个数组 演示如下&#xff1a; import numpy as np ac np.array([1,2,8,9,3,5,5,8]) ac1 np.split(ac,2) ac2 np.split(ac,[3,6]) print(ac1,ac2) 结果如下&#xff1a; 其中若是一个数…

【计算机视觉】目标跟踪任务概述和算法介绍

一、前言 1.1&#xff1a;目标跟踪VS目标检测&#xff1a;区别和联系 区别&#xff1a; 任务目标 目标跟踪任务的目标是在视频序列中跟踪一个特定目标的位置&#xff0c;即给定第一帧中的目标位置后&#xff0c;在后续帧中确定目标的位置。而目标检测任务的目标是在静态图像中…

解决 Node.js 中 npm ERR! errno CERT_HAS_EXPIRED问题

出自 BV1MN411y7pw&#xff0c; P94 黑马AJAX-Node.js-Webpack教学视频中npm包下载dayjs出错情况 输入 npm i dayjs指令之后出错&#xff1a; npm ERR! errno CERT_HAS_EXPIREDnpm ERR! A complete log of this run can be found in: C:\Users\24541\AppData\Local\npm-cache…

【leetcode C++】最小栈

leetcode 155. 最小栈 题目 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void pop() 删除堆栈顶部的元素。int top() 获…

lspci详解

lspci的作用 lspci是一个Linux命令&#xff0c;用于列出系统中的PCI总线设备信息。PCI&#xff08;Peripheral Component Interconnect&#xff09;是一种常见的计算机总线标准&#xff0c;用于连接各种外部设备&#xff08;如网卡、显卡、声卡等&#xff09;到计算机主板上。…

【CVPR2024】ReID3D:首个使用激光雷达行人充实别 ReID 的工作!

【2024 行人重识别最新进展】ReID3D&#xff1a;首个关注激光雷达行人 ReID 的工作&#xff01; 摘要&#xff1a;数据集&#xff1a;方法模型&#xff1a;多任务预训练&#xff1a;ReID Network&#xff1a; 实验结果&#xff1a;结论&#xff1a; 来源&#xff1a;Arxiv 2023…

mysql中 COALESCE和CASE WHEN的使用以及创建或替换视图

create or replace view 自理能力评估视图 as SELECT ehr_zlnlpg.ID AS ID, ehr_zlnlpg.GRID AS GRID, ehr_zlnlpg.TJID AS TJID, ehr_grjbxx.Name AS 姓名, ehr_grjbxx.Sex AS 性别, ehr_grjbxx.Cardnum AS 身份证号, ehr_zlnlpg.SCORESUM AS 总…

设计模式学习笔记 - 规范与重构 - 5.如何通过封装、抽象、模块化、中间层解耦代码?

前言 《规范与重构 - 1.什么情况下要重构&#xff1f;重构什么&#xff1f;又该如何重构&#xff1f;》讲过&#xff0c;重构可以分为大规模高层重构&#xff08;简称 “大型重构”&#xff09;和小规模低层次重构&#xff08;简称 “小型重构”&#xff09;。大型重构是对系统…

UI自动化测试使用场景及脚本录制

经常有人会问&#xff0c;什么样的项目才适合进行UI自动化测试呢&#xff1f;UI自动化测试相当于模拟手工测试&#xff0c;通过程序去操作页面上的控件。而在实际测试过程中&#xff0c;经常会遇到无法找到控件&#xff0c;或者因控件定义变更而带来的维护成本等问题。 哪些场…

MySQL 事务的原理以及长事务的预防和处置

transaction_isolation 隔离级别 读未提交 读提交 视图是在每个 SQL 语句开始执行的时候创建的 可重复读 视图是在事务启动时创建的&#xff0c;整个事务存在期间都用这个视图 串行化…

目标检测算法

图像识别三大任务 目标识别&#xff1a;或者说分类&#xff0c;定性目标&#xff0c;确定目标是什么目标检测&#xff1a;定位目标&#xff0c;确定目标是什么以及位置目标分割&#xff1a;像素级的对前景与背景进行分类&#xff0c;将背景剔除 目标检测定义 识别图片中有哪…

数据结构与算法第四套试卷(青科大)

1.图 无向图入度出度之和 所有入度之和为2*边数 2.树 **知识点&#xff1a;**注意二叉排序树&#xff01;深度平衡树&#xff0c;所以可能会出现极端现象&#xff08;链表&#xff09;&#xff0c;时间复杂度为0(n)&#xff0c;如果为最好情况即为0(logn) 3.图 1.邻接表n个…

STM32利用标准库编写同时输出4路PWM信号的程序(Proteus)仿真

先看看结果&#xff1a; 这个是根据上午发的文章的基础上更改的&#xff0c;很简单&#xff0c;只是用了一个定时器&#xff0c;初始化了4个比较器而已&#xff0c;就可以单独的控制每一路PWM的占空比了&#xff0c;好了&#xff0c;把源文件展示一下&#xff0c;完事去接孩子放…

Wilson威尔逊平滑

1、威尔逊平滑引入的动机 在曝光很少的情况下&#xff0c;计算出的CTR并不真实可靠&#xff0c;而样本数越大&#xff0c;CTR的比例才越准确&#xff0c;更能反应真实情况。 为了衡量样本数对于CTR信区间的影响&#xff0c;我们引入"威尔逊&#xff08;Wilson&#xff0…

2024暑期实习八股笔记

文章目录 自我介绍MySQL索引索引种类、B树聚簇索引、非聚簇索引联合索引、最左前缀匹配原则索引下推索引失效索引优化 日志、缓冲池redo log&#xff08;重做日志&#xff09;刷盘时机日志文件组 bin log&#xff08;归档日志&#xff09;记录格式写入机制 两阶段提交undo log&…

骨传导耳机如何选购?新手必看的6个避雷小妙招!

在短短几年内&#xff0c;骨传导耳机的市场规模一路攀升&#xff0c;今年甚至有望成为最受欢迎的蓝牙耳机款式&#xff0c;但与此同时&#xff0c;整个骨传导耳机行业也频繁出现乱象&#xff0c;不专业产品鱼龙混杂&#xff0c;令人吃惊的是&#xff0c;还有许多中小网红品牌也…

ctfshow web入门 php特性总结

1.web89 intval函数的利用&#xff0c;intval函数获取变量的整数值&#xff0c;失败时返回0&#xff0c;空的数组返回&#xff0c;非空数组返回1 num[]1 intval ( mixed $var [, int $base 10 ] ) : int Note: 如果 base 是 0&#xff0c;通过检测 var 的格式来决定使用的进…

【Redis】RedisTemplate序列化传输数据

使用自定义的序列化器 使用RedisTemplate默认的序列化器发送数据&#xff0c;会将key全都当成Object处理&#xff0c;从而按照对象的方式转成json格式发送到服务器&#xff0c;这样会导致两个问题。一是不方便阅读&#xff0c;二是会大大浪费内存。因此&#xff0c;建议自定义…

SQLiteC/C++接口详细介绍(一)

上一篇&#xff1a;SQLiteC/C接口简介 下一篇&#xff1a;SQLiteC/C接口详细介绍&#xff08;二&#xff09; 引言&#xff1a; SQLite C/C 数据库接口是一个流行的SQLite库使用形式&#xff0c;它允许开发者在C和C代码中嵌入 SQLite 基本功能的解决方案。通过 SQLite C/C 数据…

企业内部培训考试系统题库功能开发说明

学练考结合中&#xff0c;练是很关键的一环&#xff0c;将考察学习成功的试题导入企业内部培训考试系统的题库中&#xff0c;既可以作为日常学习后的作业巩固练习&#xff0c;又可以组卷进入正式考试里的试卷里。日常考试前更是可以反复练习题库里的各种试题。 校营宝企业内部…