热点更新场景,OceanBase如何实现性能优化

news/2024/11/14 12:38:21 标签: oceanbase, 分布式数据库, 实践经验, 性能调优

案例背景

这个案例来自一个保险行业的客户:他们的核心系统底层采用了OceanBase数据库作为存储解决方案,然而,在系统上线运行后,出现了一个异常情况,执行简单的主键更新语句时SQL执行时间出现了显著的波动。为了迅速定位问题原因,DBA立即介入,通过查看OceanBase的审计日志,对引发异常的SQL语句执行情况进行分析。

异常主键更新SQL

审计日志分析

从审计日志里面对异常sql进行统计,sql通过主键ID进行更新,正常情况下不到0.5ms 即可返回,但是异常情况下,最大执行时间甚至超过11秒。根据最大执行时间的执行sql的trace_id, 检索对应observer 日志,可以发现有6005错误,failed to lock write memtable相关信息,可确定为行级锁冲突导致的sql变慢。

ERROR 6005 (HY000) : Try lock row conflict
OceanBase 错误码:6005
错误原因:更新操作加锁失败,向上层返回该错误码并重试。

此种异常问题类似热门商品在营销活动中限时秒杀,属于热点更新场景。热点更新的本质是短时间内对数据库中的同一行数据的某些字段值进行高并发的修改(余额,库存等),这其中的瓶颈主要在于关系型数据库为了保持事务一致性,对数据行的更新都需要经过“加锁,更新,写日志提交,释放锁”的过程,而这个过程实质上是串行的。 所以,提高热点行更新能力的关键在于如何尽可能缩短持有锁的时间。OceanBase 在这个问题上通过持续的探索,提出了一种基于分布式架实现的“提前解行锁(Early Lock Release)”的方案(即“ELR”),提升类似业务场景中单行并发更新的能力。

技术原理

事务提交流程

  • 优化前

当用户发起commit之后,DB端开始触发日志的持久化操作:序列化内存数据并提交本地『buffer manager』,然后发给所有备机,等多数派备机同步日志成功之后,日志才算持久化成功,最后才会解锁并给客户端应答事务提交成功。显然一个事务持锁的时间,包括了4个方面:数据写入+日志序列化+同步备机网络通信+日志刷盘的耗时。对于三地五中心或者磁盘比较差的场景,热点行的性能影响还是比较大的。

  • 优化后

整个提交流程基本不变,仅仅对解锁的时机做了调整。新方案里面,等日志序列化完成,提交到『buffer manager』之后,就开始触发解锁操作,不再等日志多数派刷盘完成,从而降低了整个事务的持锁时间。当前事务解锁之后,允许后续的事务进来操作同一行,到达了多个事务并发更新同一行的效果,从而提高了系统的吞吐能力。

基于上述原理,一个热点行场景的性能,性能的计算公式如下:

TPS=1/一个事务内热点行的持锁耗时,这里的持锁耗时,表示从加锁开始算起,到事务commit的时间间隔;

对于三地五中心场景下,由于整体sql的耗时是30ms,事务跨城的commit rt大约为30ms,因此有了热点行优化之后,性能基本能跟同城部署的性能一致。

正确性保证

(1)两个概念

前驱事务:提前解锁的事务;

后继事务:当前驱事务解锁之后,后面操作同一行的事务会读取到前驱的最新数据,这样后继和前驱产生了『依赖』,我们称当前事务为后继事务。

(2)重要问题解决方案

  • 提前解锁的事务客户端应答时机

提前解锁的事务,并不代表日志一定会同步成功。所以解锁之后,不能立即给客户端应答commit成功,需要等日志完成持久化成功之后再决定。

  • 前驱和后继并发场景下,提交状态如何决定

前驱事务如果出现了回滚,后继事务必然需要回滚。前驱没有明确commit成功之前,后继事务是不能确定commit成功,需要等前驱的状态确定。

  • 级联回滚

如果一行上默认并发的事务很多,一旦最开始的前驱事务回滚,则所有的后继事务都必须回滚,给业务带了在灾难性的问题。为了尽量降低该问题产生的概率,OB限制单行上最大允许并发的事务数量为10,且根据实际情况,可以配置。

应用改造 

Mybatis statementType选择

MYbatis支持STATEMENT,PREPARED 或 CALLABLE(存储过程) ,默认是PREPARED,保持默认PREPARED即可;不要使用statementType="CALLABLE",当使用statementType="CALLABLE"时,驱动层会执行 use database,show function like,这些语句比较费性能,因此当前来说不建议使用statementType="CALLABLE",推荐使用PREPARED

注意:PREPARED下也能支持call PL()调用存储过程,可以参考以下写法

delimiter $$
create procedure prc_update_budget (
`pk_id` bigint(18),
  `uk_sbid` varchar(64),
  `amount` bigint(18)
  )
begin
  update budget set
    CURRENT_AMOUNT = CURRENT_AMOUNT - `amount`,
    GMT_MODIFY = now()
    where ID = `pk_id` and CURRENT_AMOUNT >= `amount`;
    if row_count() <= 0 then
        rollback;
        signal SQLSTATE 'NOT_ENOUGH';
    else
        commit;
    end if;
end $$
delimiter ;

OBSERVER端参数优化

alter system set enable_early_lock_release=true tenant=all; 
alter system set enable_early_lock_release=false tenant=sys;      
alter system set syslog_level="ERROR";
alter system set enable_sql_audit=true;   
alter system set enable_perf_event=true;
alter system set cpu_quota_concurrency = 4;
alter system set _ob_enable_prepared_statement = true;

注意点:

走了远程执行计划的热点行sql,走不到热点行优化路径的,热点行能力也会大大下降;由于远程执行计划难以直接发现,因此最好配置巡检,主动发现。


http://www.niftyadmin.cn/n/5751914.html

相关文章

《实时流计算系统设计与实现》-Part 2-笔记

做不到实时 做不到实时的原因 实时计算很难。通过增量计算的方式来间接获得问题的&#xff08;伪&#xff09;实时结果&#xff0c;即使这些结果带有迟滞性和近似性&#xff0c;但只要能够带来尽可能最新的信息&#xff0c;那也是有价值的。 原因可分成3个方面&#xff1a; …

Anaconda 和 conda 是什么关系?就像 pip 和 python 一样吗

Anaconda 和 conda是 Anaconda Distribution 还是 Miniconda Anaconda 和 conda Anaconda 和 conda 之间的关系有点类似于 pip 和 Python&#xff0c;但又有所不同。 Anaconda 是一个数据科学和机器学习的发行版&#xff0c;它包含了 Python、conda 以及许多预装的库和工具&am…

PETR/PETRv2/StreamPETR论文阅读

1. PETR PETR网络结构如下&#xff0c;主要包括image-backbone&#xff0c;3D Coordinates Generator&#xff0c;3D Position Encoder&#xff0c;transformer Decoder四个模块。 把N 个视角的图像输入到骨干网络中以提取 2D 多视图特征。在 3D 坐标生成器中&#xff0c;首先…

C++ STL -- 模版

C STL&#xff08;标准模板库&#xff09;简介 C STL&#xff08;Standard Template Library&#xff09;是C的一部分&#xff0c;提供了一组通用的、可复用的组件&#xff0c;以简化编程过程。STL通过模板和泛型编程的方式&#xff0c;使得开发者可以使用预定义的数据结构与算…

【专题】计算机网络之网络层

1. 网络层的几个重要概念 1.1 网络层提供的两种服务 (1) 让网络负责可靠交付 计算机网络模仿电信网络&#xff0c;使用面向连接的通信方式。 通信之前先建立虚电路 VC (Virtual Circuit) (即连接)&#xff0c;以保证双方通信所需的一切网络资源。 如果再使用可靠传输的网络…

RTPS网卡白名单的一个BUG

当我们创建RTPSParticipantImpl的时候&#xff0c;有时候会指定通信使用的网卡&#xff0c;将可以用于RTPS通信的网卡的IP添加到白名单中&#xff0c;这样&#xff0c;RTPS就只会在IP所在的网卡上进行PDP&#xff0c;EDP以及业务数据交互。 如果我们的DDS应用在启动的时候&…

Mock.js生成随机数据,拦截 Ajax 请求

Mock.js 是一个用于模拟数据的 JavaScript 库&#xff0c;特别适合用于前端开发过程中生成假数据进行接口测试。它可以拦截 Ajax 请求并生成随机数据&#xff0c;还可以模拟服务器的响应来加速前端开发。 一、安装 Mock.js 可以通过以下几种方式引入 Mock.js&#xff1a; CDN…

ESP-IDF运行export.sh时遇到“${ZSH_VERSION}“附近有错误

在Ubuntu18.04环境下。 一开始我以为是有这个变量没值&#xff0c;于是我下载之后配置。发现不行。 以为是从主机到虚拟机有隐藏字符&#xff0c;删掉重打&#xff1b;以为有语法问题&#xff0c;手动赋值、改内容。 结果&#xff0c;是因为我是直接下载的GitHub zip导致的&…