问题描述:认证密码登录场景下,
OceanBase 响应时间太长
客户业务系统自 2022 年 1 月开启改造后,当前处于 Oracle 分片与 OceanBase 分片并行的模式,后端数据库版本分别为 Oracle 19C 与 OceanBase 3.2.3。针对两种数据库,开展了系列的接口压力测试。
常用的接口压力测试结果显示,密码登录场景下,两种场景的结果差异较大,具体压测数据如下表所示:
上述压测数据环境数据库分别为 OceanBase 3.2.3.2 企业版和 Oracle 19.3,两个数据库内的业务数据完全一致,数据库的主要资源对比情况如下:
经过多次重试,200 并发压测场景下,Oracle 认证密码登录平均响应时间约为 15ms,OceanBase 认证密码登录场景平均响应时间约为 60ms。
问题分析
通过对 OceanBase 中 SQL 执行情况进行分析,本次压测场景下,涉及的响应时间较长的 SQL 主要为:
updatexxxxsetlogin_times = ?,login_date = ?,login_time = ?,op_entrust_way = nvl(?, ?),op_station = nvl(?, ?),last_login_date = ?,last_login_time = ?,last_op_entrust_way = nvl(?, ?),last_op_station = nvl(?, ?)whereauth_id = ?and auth_type = ?
通过 OCP 观察,相关 SQL 的平均响应时间约为 21ms,但平均执行时间为 4.57ms,平均 CPU 时间为 4.81ms,与响应时间相差较大。
为此,对相关的 SQL 进行了分析,发现该 SQL 的执行计划相对简单,走的唯一索引扫描,已无可优化空间。
对应的 SQL 直接数据库进行执行,时间 3ms 左右。
通过 OBServer 后台日志,可以看出,对应 SQL 执行时间一般在 2ms 左右。
什么造成了响应时间和执行时间这么大的差异呢?为此通过对 gv$sql_audit 分析可以看出,该 SQL 执行过程中,出现了失败重试的情况。
经过压测期间观察,可以看出,造成 SQL 执行错误重试的错误码为 6005。
关于 6005 错误码,官网的解释如下:
ERROR 6005 (HY000) : Try lock row conflict• OceanBase 错误码:6005• 错误原因:更新操作加锁失败,向上层返回该错误码并重试。
为此,可以清晰的看出,本次压测场景下,造成延时超出预期的主要原因为数据库压测过程中,由于表数据 Update 更新过程中,加锁失败,造成了 SQL 执行多次重试,导致接口延迟变高。
OceanBase 数据库的锁存储在行上,从而减少内存中所需要维护的锁数据结构带来的开销。在内存中,当事务获取到行锁时,会在对应的行上设置对应的事务标记,即行锁持有者。类似于大部分的两阶段锁实现,OceanBase 数据库的锁在事务结束(提交或回滚)的时候释放,从而避免数据不一致性的影响。当行锁持有者锁未释放,会造成其他事务更新失败,即出现上述的 6005 报错,并进行不断重试,整体的业务延时升高。
Oracle 锁属于悲观锁性质,Oracle 事务存在行锁时,对应行的操作就会等待,上一个事务提交成功后,后续的事务才能提交。通过 AWR 报告可以看出,压测过程中 Oracle 也存在明显的锁等待事件,平均锁等待事件为 1.85ms。
问题处理
本次压测过程中,造成本次接口延迟高的主要原因为 200 并发压测过程下 auth_id 重复,导致 Update 场景下出现了大量锁,SQL 执行进行了多次重试,SQL 执行时间与响应时间差异较大,接口延迟变高。为此,我们增加了本次测试样本量(增加至 2025,前值为 106),并再次进行了压测。
样本量增加之后,相关 SQL 执行过程中,不再出现失败重试的情况。
SQL 平均执行时间与平均响应时间也大幅下降。
压测结果显示,样本增加后,密码登录场景,OceanBase 与 Oracle 性能差异非常小,达到了预期值。
总结
本次压测过程中,当样本量为 100 左右时,OceanBase 与 Oracle 性能差异性较大,造成相关性能差异的核心原因是,压测时,由于数据的样本量小于并发数,造成业务压测过程中,产生了大量的行锁,OceanBase 两阶段锁与 Oracle 悲观锁存在差异,导致两者压测性能差异较大。当样本量升至 2000 左右后,压测过程中,不再出现锁问题,OceanBase 与 Oracle 的压测性能已无太大差异,压测性能满足预期。




