首批通过分布式安全可靠测评,为关键业务系统打造
OceanBase Sysbench 性能问题分析
更新时间:2026-04-07 20:57:20
深入分析 OceanBase 数据库在 Sysbench 测试中遇到的性能问题,通过排查瓶颈、优化配置及性能调优,提供解决方案,助力提升数据库在高并发场景下的稳定性和效率。同时提供一些性能问题的案例作为参考,帮助用户解决可能遇到的性能问题。
Sysbench 问题的快速定位方法
当 Sysbench 出现 TPS 低于预期、波动较大、降为 0 或异常终止时,应优先采用快速定位排查问题的方法。
问题现象一:Sysbench TPS 低于预期
排查问题步骤如下:
分析 Sysbench 参数。
优先分析 Sysbench 运行命令中的参数。
如果设置了
--rand-type=special或者未设置--rand-type参数,则可以设置为--rand-type=uniform,减少数据间的锁竞争。如果表数量或大小太小,可以调大数据集:比如
tables=100,table_size=1000000。如果是
read_write或write_only场景,可以检查是否有死锁加以验证:SELECT * FROM oceanbase.cdb_ob_deadlock_event_history ORDER BY create_time DESC LIMIT 10;
确认连接方式。
- 如果 Primary Zone 为单 Zone 并且直连 OBServer 节点,确认连接的是否是 Leader。
- 如果 Primary Zone 为 Random,需要连接 OBProxy 进行测试。
查询租户信息。
SELECT * FROM oceanbase.dba_ob_tenants;查询租户 Leader。
SELECT svr_ip, sql_port, count(1) FROM oceanbase.cdb_ob_ls_locations WHERE tenant_id=1 AND role='leader' GROUP BY svr_ip;
观察 CPU 开销。
若 Sysbench 参数和客户端连接方式没有问题,可通过查看 CPU 使用率继续排查。
查看线程 CPU 占用。
top -H -p pidof observer如果每个业务线程基本打满一个核,继续看线程数量是否接近机器核数。
- 如果业务线程(如 T1002_L0_G2)数量远低于机器核数,CPU 总开销也远没有达到机器上限,那么很可能是
cpu_count分配太少导致的。在这种情况下,您可以检查创建租户命令,确认cpu_count是否设置得太低。 - 如果 CPU 总开销接近机器上限,那么机器性能已到极限,只有用更高配置的机器才能跑出更高的性能。
- 如果业务线程(如 T1002_L0_G2)数量远低于机器核数,CPU 总开销也远没有达到机器上限,那么很可能是
查看租户规格。
show create tenant xxx; SELECT * FROM oceanbase.dba_ob_resource_pools; SELECT * FROM oceanbase.dba_ob_units;如果业务线程都没有打满一个核(比如 CPU 占用 20%~50%),那就是其他地方遇到了瓶颈。
- 如果存在网络线程(如 RpcIO)打满一个核,可能是网络线程数量偏少,网络通信成为了瓶颈,需要增加线程数量
net_thread_count。 - 如果所有线程 CPU 占用率都不高,则可能是硬件方面成为瓶颈,需要继续分析。
- 如果存在网络线程(如 RpcIO)打满一个核,可能是网络线程数量偏少,网络通信成为了瓶颈,需要增加线程数量
分析硬件原因。
排除 CPU 因素之后,剩下的硬件原因主要是磁盘和网络,磁盘和网络问题的排查思路如下。
- 确认网卡带宽上限,观察测试时网络带宽是否成为瓶颈(可以将 Sysbench 部署在 OBServer 机器上进行测试)。
- 确认网络延迟(ping),延迟过高也可能导致 SQL 执行变慢。
- 确认日志盘 16K 写入的带宽上限(通过 FIO测试),观察测试时磁盘 IO 是否成为瓶颈(可以更换 SSD 或 NVM 进行测试)。
查看网络 IO 的命令:
sar -n DEV 1查看网卡带宽上限的命令:
##(eth0 为网卡名) ethtool eth0其他。
排除上述因素外,还可能存在一些特殊情况,比如测试时间段和 observer 后台任务冲突。
曾经有用户反映,在进行业务测试时,发现有两组数据明显低于预期。经过检查各种配置,未发现明显的问题。最终发现,该用户是在凌晨 2 点进行的业务测试,而该时间段恰好是 OceanBase 数据库进行每日转储合并的默认时间。因此,数据库的性能受到了极大的影响。
问题现象二:Sysbench TPS 波动或降为 0
当出现 Sysbench TPS 波动或降为 0 时,可能有以下几种情况存在。
TPS 偶尔小幅波动
可能原因:OceanBase 数据库定期进行转储合并,会占用 CPU 资源,导致业务线程受到影响,
cpu_count越多影响越小。比如 4c8g 的租户,转储时 tps 可能下降 80%;32c64g 的租户,转储时 tps 可能下降 10%。处理方法:
调大租户资源单元的
max_cpu。调大租户 CPU 并发度。
alter system set cpu_quota_concurrency=4 tenant = xxx;减少转储线程数量(
merge_thread_count)或降低线程优先级(compaction_high_thread_score、compaction_mid_thread_score、compaction_low_thread_score),会让转储的单位时间开销降低,但是需要付出时间上的代价,转储整体的开销是不变的。
TPS 短暂降为 0 后间歇恢复
- 可能原因:发生死锁,且 Sysbench 设置了
--mysql-ignore-errors=1062,1213,6002; - 处理方法:
先检查是否有死锁。
SELECT * FROM oceanbase.cdb_ob_deadlock_event_history ORDER BY create_time DESC LIMIT 10;确认后进行后续操作。
- Sysbench 增加
--rand-type=uniform参数。 - 调大数据集:比如
tables=100,table_size=1000000;(table_size默认为 10000)。
- Sysbench 增加
TPS 降为 0 后持续无恢复
- 可能原因:发生死锁,且恰好没有被检测到,同时超时时间设置得很长,导致 TPS 跌 0 后不报错、不退出、不恢复。
- 处理方法:
先检查是否有死锁。
SELECT * FROM oceanbase.cdb_ob_deadlock_event_history ORDER BY create_time DESC LIMIT 10;确认后进行后续操作。
- Sysbench 增加
--rand-type=uniform参数。 - 调大数据集:比如
tables=100,table_size=1000000;(table_size默认为 10000)。
- Sysbench 增加
TPS 降为 0 后快速恢复
可能原因:Clog 盘满了无法写入,导致 TPS 跌 0,之后 Clog 回收空间,TPS 恢复。
处理方法:检查租户磁盘空间使用量:
SELECT tenant_id, svr_ip, svr_port, log_disk_in_use, log_disk_size FROM oceanbase.gv$ob_units;考虑分配更大的磁盘空间。
若排除上述原因后问题依然存在,请联系技术支持人员协助排查。
问题现象三:Sysbench 异常终止或报错
TPS 短暂降为 0 后间歇恢复,偶尔报错 6002 或 1213
- 可能原因:发生死锁,数据集太小或没有设置
rand-type,默认的 Special 类型会导致 Key 比较集中。长时间没有退出是因为大部分 SQL 还在死锁中,线程在等待 SQL 执行结束。 - 处理方法:
先检查是否有死锁。
SELECT * FROM oceanbase.cdb_ob_deadlock_event_history ORDER BY create_time DESC LIMIT 10;确认后进行后续操作。
- Sysbench 增加
--rand-type=uniform参数。 - 调大数据集:比如
tables=100,table_size=1000000;(table_size默认为 10000)。
- Sysbench 增加
Sysbench 异常终止报错 1062
- 可能原因:1062 是主键、唯一索引冲突,Sysbench 是随机生成数据,是可能导致主键冲突的。
- 处理方法:Sysbench 增加参数:
--mysql-ignore-errors=1062
Sysbench 异常终止报错 1213
- 可能原因:发生死锁,死锁的部分事务被杀掉。
- 处理方法:即使数据集非常大,并且使用了
--rand-type=uniform参数,也可能会发生死锁。因此,可以使用--mysql-ignore-errors=1062,1213参数来忽略死锁错误。
Sysbench 异常终止报错 6002
- 可能原因:6002 也可能是死锁导致的,只是最后没有报 1213 而是 6002。
- 处理方法:调大数据集,增加
--rand-type=uniform参数,减少锁冲突。增加 Sysbench 参数:--mysql-ignore-errors=1062,1213,6002。
Sysbench 异常终止报错 4012
可能原因:锁竞争严重,或者死锁,也可能只是 OBServer 节点性能较差且客户端压力太大导致超时。
处理方法:调大超时时间(单位 us):
set global ob_query_timeout = 50000000000;
Sysbench 异常终止报错 5930
可能原因:开启了SQL 预编译功能,即
--db-ps-mode=auto,但是 OceanBase 数据库对预编译支持不够完善。处理方法:
- 调大租户参数:
alter system set open_cursors=65535;。 - 也可以关闭 SQL 预编译功能进行测试:
--db-ps-mode=disable;。
- 调大租户参数:
Sysbench 异常终止并有其他报错
- 可能原因:可能是 OceanBase 数据库的 BUG。
- 处理方法:请记录错误日志,然后联系技术支持人员协助排查。
Sysbench 问题的常规排查流程
如果在快速定位问题时没有找到原因,可以按照完整的检查流程进行排查。如果在这个过程中遇到不理解的地方,可以参考后面对应的章节或链接的文档进行查看。如果最终仍然无法解决问题,请联系技术支持人员协助排查。
常规分析思路:
- 检查硬件资源,CPU、内存、磁盘资源不足直接影响性能,甚至 TPS 会降为 0。
- 查看租户配置,租户分配的资源太少,硬件就没有充分利用起来。
- 查看 Sysbench 参数,线程数会直接影响 TPS,数据集太小或者数据分布太集中,会导致锁竞争甚至死锁。
- 最后再考虑 OBServer 是否有 BUG。
说明
以下内容中提供的命令按需使用即可,不用全部执行一遍。
硬件检查
硬件资源不足,比如 CPU 内存资源太小(小于 4c8g),自然性能较差;磁盘如果快写满了,也会影响写入速度;网络延迟太高也有影响。
- CPU:
lscpu - 内存:
top、cat /proc/meminfo - 磁盘:
df -h - 网络延迟:
ping ip
OceanBase 部署配置检查
在机器硬件资源够用的情况下,如果 OceanBase 数据库部署时的参数设置比较小,没能充分利用资源,也会导致性能下降。大多数配置都可以动态调整,只有极少数只能在部署时配置。
连接 SYS 租户,查看全局视图。
SELECT * FROM GV$OB_SERVERS;查看网络线程数量(该配置项无法动态修改)。
show parameters where name = 'net_thread_count';查看已部署集群。
obd cluster list查看已部署集群配置。
obd cluster edit-config [cluster name]
在 OBServer 所在机器上查看 OBServer 启动参数。
ps -ef | grep observer
租户配置检查
在 OBServer 节点资源充足的情况下,测试租户的资源是否成为瓶颈,可以通过以下命令检查。
查看租户基本信息。
SELECT * FROM oceanbase.dba_ob_tenants;查看建租户命令。
show create tenant [tenant name];查看租户对应的资源池(可以加
tenant_id筛选)。SELECT * FROM oceanbase.dba_ob_resource_pools;查看对应 Unit 的配置。
SELECT * FROM oceanbase.dba_ob_units;
Sysbench 参数检查
Sysbench 参数就在 Sysbench 执行命令中,可以对照参数说明逐一检查。
死锁问题定位
查看死锁记录。
SELECT * FROM oceanbase.cdb_ob_deadlock_event_history ORDER BY create_time DESC LIMIT 10;其中
role=victim表示被杀掉的事务。查看事务相关 SQL。
SELECT usec_to_time(REQUEST_TIME), TRACE_ID, TX_ID, QUERY_SQL FROM gv$ob_sql_audit WHERE TX_ID=52635 ORDER BY REQUEST_TIME;如果搜不到相关事务,说明没有开启 SQL Audit 功能,可以查看
enable_sql_audit配置项是否设置为 True:show parameters where name = 'enable_sql_audit';如果查询到是 False,那就看不到事务对应的 SQL 命令,通过日志筛选事务 ID 可能找到一些信息。
查询 SQL 对应日志。
查到事务相关 SQL 后,用发生冲突的那条 SQL 的 Trace ID,在日志里面搜索:
grep '[trace id]' observer.log*可以看到该条 SQL 所有的日志,一般最后一条包含报给客户端的错误码:
sending error packet(err=-4101用最后一条
commit或begin命令的 Trace ID,也可以搜索到相关日志:sending error packet(err=-6002如果没有日志,那就是日志级别不对,或者日志限流了。需要将日志级别调成
WDIAG,日志带宽限制调大:alter system set syslog_level='WDIAG'; alter system set syslog_io_bandwidth_limit='2G';注意
修改配置项之前发生的死锁信息无法查找。
转储合并分析
查看耗时超过 5s 的转储合并任务。
SELECT * FROM GV$OB_MERGE_INFO WHERE tenant_id=1002 AND (END_TIME-START_TIME)>5 LIMIT 10;查看某张表的合并记录。
SELECT * FROM GV$OB_TABLET_COMPACTION_HISTORY WHERE TABLET_ID IN (SELECT TABLET_ID FROM oceanbase.CDB_OB_TABLE_LOCATIONS WHERE TABLE_NAME = 'sbtest1') ORDER BY START_TIME DESC;主动触发转储。
alter system minor freeze tenant=xxx;
还可以在 OBServer 节点上执行 top -H,观察 MINI_MERGE、MINOR_EXE 线程的开销,但是持续时间比较短。
慢 SQL 查询
查询超过 5s 的慢 SQL,打印所有信息。
SELECT * FROM gv$ob_sql_audit WHERE elapsed_time > 5000000 LIMIT 10;自定义打印关键信息。
SELECT SVR_IP, SVR_PORT, SQL_EXEC_ID, TRACE_ID, TENANT_ID, SQL_ID, QUERY_SQL, PLAN_ID, PARTITION_CNT, IS_INNER_SQL, ELAPSED_TIME, EXECUTE_TIME, APPLICATION_WAIT_TIME FROM gv$ob_sql_audit WHERE elapsed_time > 5000000 ORDER BY elapsed_time DESC LIMIT 10;如果查不到数据,可能是没开启 SQL Audit 功能:
show parameters where name = 'enable_sql_audit'; alter system set enable_sql_audit = true;
日志问题排查
查看磁盘空间使用情况。
SELECT tenant_id, svr_ip, svr_port, LOG_DISK_IN_USE, LOG_DISK_SIZE FROM gv$ob_units;
问题复现流程
首先可以清空之前的
sql_audit记录。alter system set enable_sql_audit = false; alter system flush sql audit global;开启
sql_audit记录。alter system set enable_sql_audit = true;修改日志级别。
alter system set syslog_level='WDIAG';调小 SQL 记录阈值,尽可能记录更多的 SQL。
alter system set trace_log_slow_query_watermark = '10ms';调大系统日志带宽限制,避免因为限流导致丢失关键日志。
alter system set syslog_io_bandwidth_limit='2G';如果不希望事务超时,还可以调大超时时间。
set global ob_query_timeout = 50000000000;
之后,设置和问题场景相同的参数,开始执行 Sysbench。
Sysbench 性能问题案例分析
以 Sysbench TPS 下降为 0,偶尔报错的问题为例进行分析以及处理。
问题现象
使用 OceanBase 数据库社区版 V4.1.0,执行以下命令进行 Sysbench 测试,TPS 下降为 0 并报错。
sysbench --db-driver=mysql --threads=500 --time=300000 --mysql-host=xxxxxxx --mysql-port=2883 --mysql-user='tpcc@t1' --mysql-password='******' --report-interval=2 --tables=100 /usr/share/sysbench/oltp_read_write.lua --db-ps-mode=disable run
机器配置:

问题原因与分析
初步判断是因为 table_size 较小,而数据分布默认是 special 模式,导致数据比较集中,主键冲突严重,最终发生了死锁,TPS 降为 0。
首先测试租户超时时间调大。
set global ob_query_timeout = 50000000000; set global ob_trx_timeout = 50000000000;为了尽快复现,我们将
Tables设置为 1,其他参数不变。sysbench oltp_read_write.lua --mysql-host=[ip] --mysql-port=2881 --mysql-user=root@user --mysql-db=test --table_size=10000 --tables=1 --threads=500 --time=3600 --report-interval=1 --db-ps-mode=disable run生成现象:TPS 跌到 0,但偶尔 TPS 和 QPS 会大于 0。

查看死锁视图。
SELECT * FROM oceanbase.CDB_OB_DEADLOCK_EVENT_HISTORY ORDER BY create_time DESC LIMIT 10;
可以看到最近的死锁记录,
role=victim表示被杀掉的事务,role=witness表示见证冲突的事务。cycle_size=2说明只有两个事务相互冲突,cycle_size>2说明多个事务和一个事务冲突。这里我们为了便于观察选择一个cycle_size=2的 Event,通过event_id可以筛选出一组冲突的事务。SELECT * FROM oceanbase.CDB_OB_DEADLOCK_EVENT_HISTORY WHERE cycle_size=2 ORDER BY create_time DESC LIMIT 10;
Visitor 字段中可以看到事务 ID,通过事务 ID 可以找到该事务相关的所有 SQL 命令:
SELECT TRACE_ID, TX_ID, QUERY_SQL FROM gv$ob_sql_audit WHERE TX_ID=5042912 ORDER BY REQUEST_TIME; SELECT TRACE_ID, TX_ID, QUERY_SQL FROM gv$ob_sql_audit WHERE TX_ID=5042591 ORDER BY REQUEST_TIME;
从图中可以看到两个事务发生了交叉依赖的情况,即:
- 事务 1 更新 id=4978。
- 事务 2 更新 id=5049。
- 事务 1 更新 id=4978。
- 事务 2 删除 id=5049。
发生死锁之后,事务 64317 回滚,事务 64235 成功提交。因为事务 64317 的创建时间更晚,这个可以查看 sql_audit 找到事务的第一条 SQL,通过 SQL 的
request_time进行判断。SELECT REQUEST_TIME, SVR_IP, SVR_PORT, SQL_EXEC_ID, TRACE_ID, TENANT_ID, TX_ID, SQL_ID, QUERY_SQL, PLAN_ID, PARTITION_CNT, IS_INNER_SQL, ELAPSED_TIME, EXECUTE_TIME, APPLICATION_WAIT_TIME FROM gv$ob_sql_audit WHERE TX_ID=64317 ORDER BY REQUEST_TIME;根据 trace id 查看日志可以看到回滚的事务,错误码 6002(回滚),Abort 原因 4101(死锁)。
查找被杀事务发生冲突的那条 SQL 日志,可以看到最后一条日志发送的是 4101 错误码。但最后 Sysbench 这边并未报死锁错误,而是报了 6002 回滚错误。
[2023-07-11 15:32:40.263794] INFO [SERVER] send_error_packet (obmp_packet_sender.cpp:317) [28473][T1002_L0_G0][T1002][Y5B690B7C0505-00060030956354CB-0-0] [lt=14] sending error packet(err=-4101, extra_err_info=NULL, lbt()="0x1029cb40 0x832fadc 0x82e32f7 0x5b65d4f 0x5960718 0x595c58f 0x595a25a 0x8075f6c 0x595964c 0x80754ea 0x595665a 0x8075b24 0x1061b777 0x10613e9f 0x7f0215489e25 0x7f0214f48f1d")查找事务最后一条 "BEGIN" 命令对应的日志(因为事务没有显示执行
commit命令,下一个事务的begin命令会导致当前事务隐式提交,因此begin是当前事务的最后一条 SQL),可以找到返回 6002 回滚错误。得到 Sysbench 没有处理死锁 SQL 的报错,而是将 6002 错误报了出来。[2023-07-11 15:32:40.305922] INFO [SERVER] send_error_packet (obmp_packet_sender.cpp:317) [28472][T1002_L0_G0][T1002][Y5B690B7C0505-0006003095136574-0-0] [lt=37] sending error packet(err=-6002, extra_err_info=NULL, lbt()="0x1029cb40 0x832fadc 0x82e32f7 0x5a55e57 0x5960c40 0x595c58f 0x595a25a 0x8075f6c 0x595964c 0x80754ea 0x595665a 0x8075b24 0x1061b777 0x10613e9f 0x7f0215489e25 0x7f0214f48f1d")如果搜不到日志,可能是日志限流导致,建议调大系统日志带宽限制:
alter system set syslog_io_bandwidth_limit='2G';
解决方法
根据上述对于问题原因的分析,可以得到以下结论:
- 在默认
rand-type=special场景下,可能因为 Key 冲突太多从而出现死锁,这种场景下 Sysbench 压测会退出。 - 在默认
rand-type=special场景下,如果tables和table_size也比较小,死锁出现得更为频繁,会导致大量事务卡住,测试线程无法及时退出,从而出现一段时间(几分钟)内 tps 跌 0 的情况,偶尔 tps 也可能大于 0。 - 死锁的事务会报错回滚,错误码可能是 6002(而不是 1213)。
- 如果
ob_query_timeout设置比较长,又碰巧出现死锁检测功能没有生效,事务无法被杀掉,SQL 一直阻塞,这种情况 tps 会长期为 0,且不报错。
由此我们可以通过如下的方法来解决 Sysbench TPS 下降为 0,偶尔报错的问题:
- 首先考虑调整数据分布类型,设置
--rand-type=uniform - 如果不考虑调整数据分布类型,建议调大数据集:比如
tables=100,table_size=1000000 - 若数据随机类型和数据集都不考虑调整,则可以尝试忽略错误码,但这样无法避免死锁,
--mysql-ignore-errors=1062,1213,6002