聊聊Oceanbase的悬挂事务
在OceanBase数据库中, 数据库事务分为普通事务和分布式事务。长事务和悬挂事务会导致资源长时间不释放,等待会话长时间被阻塞,“悬挂事务”通常指的是那些未能正常结束的事务,即事务既没有被成功提交(COMMIT),也没有被回滚(ROLLBACK),如同oracle数据库中的dba_2pc_pending两阶段的分布式事务。 这类事务处于未完成状态,可能会占用数据库资源,并对后续的事务处理产生影响。需要重点关注这类异常的事务。
- 悬挂事务是指客户端与 OBProxy 之间已经断开,但 OBProxy 与数据库端的链接仍然存在,由于事务超时时间比较长,连接上的长时间存在的事务。
- 长事务是指链路连接正常,事务执行时间比较长的事务。
悬挂事务的原因
悬挂事务可能由以下几种情况引起:
- 应用程序异常:如果应用程序在执行事务的过程中出现异常崩溃,未能妥善处理事务的提交或回滚,就会导致事务悬挂。
- 长时间运行的事务:某些事务可能由于业务逻辑复杂或数据量庞大,执行时间过长,而未能在预定时间内完成。
- 锁竞争:在并发环境中,多个事务可能因为争夺同一资源的锁而陷入死锁状态,导致事务无法继续执行直至超时或手动干预。
- 网络故障:网络不稳定或断开也可能导致事务请求未能成功到达数据库服务器,进而造成事务悬挂。
- 资源耗尽:如果系统资源(如内存、CPU、磁盘空间等)不足,可能导致事务无法完成。
悬挂事务的影响
悬挂事务可能对数据库系统产生以下负面影响:
- 资源消耗:悬挂事务会占用数据库的连接、锁等资源,影响系统的整体性能。
- 数据一致性问题:如果悬挂事务持有某些数据的锁,其他事务可能无法访问这部分数据,从而导致数据一致性问题。
- 死锁:悬挂事务可能导致其他事务在等待资源释放时陷入死锁状态。
- 性能下降:悬挂事务的存在可能导致系统响应时间延长,影响用户体验。
处理悬挂事务的方法
为了处理悬挂事务,可以采取以下措施:
- 超时设置:设置合理的事务超时时间,当事务运行时间超过设定值时自动回滚。
- 定期检查:定期检查数据库中的活动事务,查找并处理悬挂事务。
- 手动回滚:对于已知的悬挂事务,可以通过手动回滚的方式来释放其占用的资源。
- 优化事务逻辑:简化事务处理逻辑,减少事务执行时间,提高事务的原子性。
- 增强容错机制:增强应用程序的容错机制,确保在异常情况下能够正确处理事务。
- 使用OceanBase提供的工具:OceanBase数据库本身提供了一些工具和功能,如监控工具、事务管理工具等,可以帮助检测和处理悬挂事务。
排查方法
可以通过以下命令查询是否存在悬挂事务与长事务,其中 now() - ctx_create_time > 600
表示创建后执行时间大于 10 分钟的事务。
obclient> SELECT * FROM __all_virtual_trans_stat WHERE (now() - ctx_create_time) > 600;
当前存在的活动事务:
SELECT * FROM __all_trans;
通过查看返回的结果,可以发现那些长时间未完成的事务,并进一步分析其原因,采取相应的措施来处理。
查看数据库里是否存在长事务:
SELECT * FROM OCEANBASE.__all_virtual_trans_stat WHERE part_trans_action <= 2 AND ctx_create_time < date_sub(now(), INTERVAL 600 SECOND) AND is_exiting != 1
查看事务是否为 XA 事务:
其中事务 ID 为上述 sql 中查出的svr_ip。如果sql执行结果为空,则表明长事务非XA事务;如果执行有结果,则对应的结果即为 XA 事务。
SELECT * FROM OCEANBASE.__all_virtual_global_transaction WHERE trans_id LIKE '%事务ID%';
查看是否有悬挂事务:
SELECT * FROM __all_virtual_trans_stat WHERE part_trans_action > 2 AND ctx_create_time < date_sub(now(), INTERVAL 600 SECOND) AND is_exiting != 1;
查询具体的表名:
SELECT table_id,table_name FROM __all_virtual_table WHERE data_table_id = 'xxxx'; select table_name,index_status from __all_virtual_table where table_id in ( select /*+READ_CONSISTENCY(WEAK),query_timeout(100000000) */ table_id from __all_virtual_meta_table where data_version != (select value from __all_zone where name = 'global_broadcast_version'));
任何活跃事务都会持有 MemTable 的 reference,如果事务长时间不结束,则会使 MemStore 冻结后无法释放,最终导致内存不足。目前,OCP 的各个版本均支持对悬挂事务和长事务进行监控,一旦报警,需要去确认报警原因,并及时排除风险。有关使用 OCP 监控长事务与悬挂事务的方法,请参见《OCP 告警参考》。
可以通过配置 ob_query_timeout
与 ob_trx_timeout
配置项,避免事务长时间不结束,影响系统稳定性。有关以上两个配置项的详细信息与配置方式,请参见 影响 OceanBase 数据库连接超时的相关配置。
- 处理长事务,请执行下列命令。
- 回滚普通长事务。注意,kill 会话需要直连对应的 OBServer,无需通过 proxy 连接数据库。
SELECT svr_ip FROM OCEANBASE.__all_virtual_processlist WHERE id=会话ID; kill 会话ID;
- 终止 XA 事务,请执行下列命令。
- 前往系统租户,查找 XA 事务的 XID。
SELECT hex(gtrid),hex(bqual),format_id FROM OCEANBASE.__all_virtual_global_transaction WHERE tenant_id = 租户ID AND format_id <> -2 AND state = 3 AND gmt_modified < date_sub(now(), INTERVAL 1800 SECOND);
- 如果是 Oracle 模式租户,可以前往普通租户查看 XA 事务的 XID。
SELECT rawtohex(gtrid),rawtohex(bqual),format_id FROM sys.all_virtual_tenant_global_transaction_agent WHERE format_id <> -2 AND state = 3 AND ROUND((sysdate - cast(GMT_MODIFIED as date)) * 86400) > 1800;
前往普通租户执行,终止 XA 事务。
set serveroutput on; declare l_xid DBMS_XA_XID; l_ret PLS_INTEGER; BEGIN l_xid.formatid := format_id; l_xid.gtrid := hextoraw('hex(gtrid)'); l_xid.bqual := hextoraw('hex(bqual)'); l_ret := DBMS_XA.XA_ROLLBACK(xid = > l_xid); dbms_output.put_line(l_ret); END; /
- 前往系统租户,查找 XA 事务的 XID。
- 回滚普通长事务。注意,kill 会话需要直连对应的 OBServer,无需通过 proxy 连接数据库。
其它悬挂事务情况
- 事务涉及的分区无主,导致事务状态机推进不了;
- 事务在 leader 上已经推进完成,但由于备机的内存、网络带宽等资源限制,日志同步慢、回放慢,导致事务状态结束慢。
上述两种场景,处理方法是不一样的,下文分别描述。
分区无主
OceanBase 数据库的架构决定分区是有多副本的,多副本中只有一个 leader (主),其它都是 follower (从)。而当 leader 所在 OBsever 宕机了,此时就没有了 leader,少数派副本异常情况下,此时其它副本就会根据 PAXOS 协议重新选主,在此过程中正在运行的事务有可能就产生长事务。
对于这种场景,使用如下方式进行处理:
- 查询当前事务涉及的所有的表信息,SQL 如下,其中
participants
里的每个tid
代表一个表。SELECT svr_ip, trans_id, participants FROM OCEANBASE.__all_virtual_trans_stat WHERE part_trans_action> 2 AND ctx_create_time < date_sub(now(), INTERVAL 600 SECOND) AND is_exiting != 1;
- 分别确认上述分区列表是否有主,SQL 如下,若
role
列皆为 follower,则表示全部是从副本,没有 leader。SELECT svr_ip, svr_port,table_id, partition_idx, role, status, replica_type FROM OCEANBASE.__all_virtual_clog_stat WHERE table_id=表ID;
若为分区无主即当前事务为长事务,可按照长事务进行处理。
副本应用日志慢
副本应用日志慢的原因有很多。比如某个 OBSever 服务器突然资源异常,OS 上跑任务消耗了大量的 IO、网络等资源,导致该服务器上的 OBSever 响应慢;主副本分布不均匀,某服务器上的 leader 特别多,leader 进行应用需求响应,消耗大量资源,导致 follower 的可用资源比较少,从而一直追不上该 follower 对应的 leader;某个 OBserver 服务器硬件异常,比如网卡异常,导致 PAXOS 协议传到 follower 非常慢,一直处于等待中,追赶中;该 OBSever 正在合并或备份中等。
对于这种场景,使用如下方式进行处理:
- 查询当前事务涉及的所有的表信息,SQL 如下,其中
partition
里的每个tid
代表一个表。SELECT svr_ip, svr_port,trans_id, 'partition' FROM OCEANBASE.__all_virtual_trans_stat WHERE part_trans_action > 2 AND ctx_create_time < date_sub(now(), INTERVAL 600 SECOND) AND is_exiting != 1;
- 根据第一步查询到的
partition
中记录的table_id
信息,确认当前pkey
对应的leader
位置。SELECT svr_ip,svr_port FROM OCEANBASE.__all_virtual_clog_stat WHERE role='LEADER' AND table_id = 表ID;
如果第一步和第二步对应的
svr_ip
不同,说明异常事务在 follower 上存在。 - 查询上述事务对应的分区,目前集群中的记录条数。
SELECT count(1) FROM OCEANBASE.__all_virtual_trans_stat WHERE trans_id LIKE '%{选取第一步 trans_id 中的 hash 字段}%'AND`partition` LIKE '%xxx%';
如果上述查询结果为 1 条,说明只有备机上存在。这种情况请联系OceanBase 技术支持团队处理。
总之,悬挂事务是数据库管理中需要关注的一个方面,通过对事务的合理管理和优化,可以有效地避免或减少悬挂事务的发生,从而保证数据库系统的稳定性和性能。
目前这篇文章还没有评论(Rss)