首页 » OceanBase » 聊聊Oceanbase的悬挂事务

聊聊Oceanbase的悬挂事务

在OceanBase数据库中, 数据库事务分为普通事务和分布式事务。长事务和悬挂事务会导致资源长时间不释放,等待会话长时间被阻塞,“悬挂事务”通常指的是那些未能正常结束的事务,即事务既没有被成功提交(COMMIT),也没有被回滚(ROLLBACK),如同oracle数据库中的dba_2pc_pending两阶段的分布式事务。 这类事务处于未完成状态,可能会占用数据库资源,并对后续的事务处理产生影响。需要重点关注这类异常的事务。

  • 悬挂事务是指客户端与 OBProxy 之间已经断开,但 OBProxy 与数据库端的链接仍然存在,由于事务超时时间比较长,连接上的长时间存在的事务。
  • 长事务是指链路连接正常,事务执行时间比较长的事务。

悬挂事务的原因

悬挂事务可能由以下几种情况引起:

  1. 应用程序异常:如果应用程序在执行事务的过程中出现异常崩溃,未能妥善处理事务的提交或回滚,就会导致事务悬挂。
  2. 长时间运行的事务:某些事务可能由于业务逻辑复杂或数据量庞大,执行时间过长,而未能在预定时间内完成。
  3. 锁竞争:在并发环境中,多个事务可能因为争夺同一资源的锁而陷入死锁状态,导致事务无法继续执行直至超时或手动干预。
  4. 网络故障:网络不稳定或断开也可能导致事务请求未能成功到达数据库服务器,进而造成事务悬挂。
  5. 资源耗尽:如果系统资源(如内存、CPU、磁盘空间等)不足,可能导致事务无法完成。

悬挂事务的影响

悬挂事务可能对数据库系统产生以下负面影响:

  1. 资源消耗:悬挂事务会占用数据库的连接、锁等资源,影响系统的整体性能。
  2. 数据一致性问题:如果悬挂事务持有某些数据的锁,其他事务可能无法访问这部分数据,从而导致数据一致性问题。
  3. 死锁:悬挂事务可能导致其他事务在等待资源释放时陷入死锁状态。
  4. 性能下降:悬挂事务的存在可能导致系统响应时间延长,影响用户体验。

处理悬挂事务的方法

为了处理悬挂事务,可以采取以下措施:

  1. 超时设置:设置合理的事务超时时间,当事务运行时间超过设定值时自动回滚。
  2. 定期检查:定期检查数据库中的活动事务,查找并处理悬挂事务。
  3. 手动回滚:对于已知的悬挂事务,可以通过手动回滚的方式来释放其占用的资源。
  4. 优化事务逻辑:简化事务处理逻辑,减少事务执行时间,提高事务的原子性。
  5. 增强容错机制:增强应用程序的容错机制,确保在异常情况下能够正确处理事务。
  6. 使用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 数据库连接超时的相关配置

  1. 处理长事务,请执行下列命令。
    1. 回滚普通长事务。注意,kill 会话需要直连对应的 OBServer,无需通过 proxy 连接数据库。
      SELECT svr_ip FROM OCEANBASE.__all_virtual_processlist WHERE id=会话ID;
      kill 会话ID;
      
    2. 终止 XA 事务,请执行下列命令。
      1. 前往系统租户,查找 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);
        
      2. 如果是 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;
        /
        

其它悬挂事务情况

  1. 事务涉及的分区无主,导致事务状态机推进不了;
  2. 事务在 leader 上已经推进完成,但由于备机的内存、网络带宽等资源限制,日志同步慢、回放慢,导致事务状态结束慢。

上述两种场景,处理方法是不一样的,下文分别描述。

分区无主

OceanBase 数据库的架构决定分区是有多副本的,多副本中只有一个 leader (主),其它都是 follower (从)。而当 leader 所在 OBsever 宕机了,此时就没有了 leader,少数派副本异常情况下,此时其它副本就会根据 PAXOS 协议重新选主,在此过程中正在运行的事务有可能就产生长事务。

对于这种场景,使用如下方式进行处理:

  1. 查询当前事务涉及的所有的表信息,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;
    
  2. 分别确认上述分区列表是否有主,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 正在合并或备份中等。

对于这种场景,使用如下方式进行处理:

  1. 查询当前事务涉及的所有的表信息,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;
    
  2. 根据第一步查询到的 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 上存在。

  3. 查询上述事务对应的分区,目前集群中的记录条数。
    SELECT count(1) 
    FROM OCEANBASE.__all_virtual_trans_stat 
    WHERE trans_id LIKE '%{选取第一步 trans_id 中的 hash 字段}%'AND`partition` LIKE '%xxx%';
    

    如果上述查询结果为 1 条,说明只有备机上存在。这种情况请联系OceanBase 技术支持团队处理。

总之,悬挂事务是数据库管理中需要关注的一个方面,通过对事务的合理管理和优化,可以有效地避免或减少悬挂事务的发生,从而保证数据库系统的稳定性和性能。

专利论文二阶段提交分布式事务更新数据库的实现方法和装置

 

打赏

,

对不起,这篇文章暂时关闭评论。