---
title: "OceanBase Sysbench 高性能部署和问题分析 - OceanBase 数据库 V4.2.1 | OceanBase 文档中心"
description: OceanBase Sysbench 高性能部署和问题分析 本文以高性能为目标，对 OceanBase 数据库的安装部署、业务租户的创建以及 Sysbench 的使用细节进行说明，旨在帮助 OceanBase 数据库的使用者在 Sysbench 测试中跑出更好的性能。同时提供一些性能问题的案例作为参考，帮助大家解决可…
---
切换语言

- 中文站 - 简体中文
- International - English
- 日本站 - 日本語

文档反馈![](https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*P8CuR4UJ_FkAAAAAAAAAAAAADiGDAQ/original) OceanBase 数据库分布式版 - V 4.2.1 LTS

# OceanBase Sysbench 高性能部署和问题分析

更新时间：2026-04-16 00:11:36

[编辑](https://github.com/oceanbase/oceanbase-doc/edit/V4.2.1/zh-CN/700.reference/1100.performance-test/500.0sysbench-high-performance-deployment-and-roubleshooting.md)  

本文以高性能为目标，对 OceanBase 数据库的安装部署、业务租户的创建以及 Sysbench 的使用细节进行说明，旨在帮助 OceanBase 数据库的使用者在 Sysbench 测试中跑出更好的性能。同时提供一些性能问题的案例作为参考，帮助大家解决可能遇到的性能问题。

## 快速定位 Sysbench 问题（省流版）

### Sysbench 的 TPS 低于预期

排查问题步骤如下：

1. 分析 Sysbench 参数。

   优先分析 Sysbench 运行命令中的参数。

      - 如果设置了 `--rand-type=special` 或者未设置 `--rand-type` 参数，则可以设置为 `--rand-type=uniform`，减少数据间的锁竞争。
      - 如果表数量或大小太小，可以调大数据集：比如 `tables=100，table_size=1000000`。
      - 如果是 `read_write` 或 `write_only` 场景，可以检查是否有死锁加以验证：

       ```sql
       SELECT * FROM oceanbase.cdb_ob_deadlock_event_history ORDER BY create_time DESC LIMIT 10;

       ```
 2. 确认连接方式。

      - 如果 Primary Zone 为单 Zone 并且直连 OBServer 节点，确认连接的是否是 Leader。
      - 如果 Primary Zone 为 Random，需要连接 OBProxy 进行测试。
      1. 查询租户信息。

        ```sql
        SELECT * FROM oceanbase.dba_ob_tenants;

        ```
      2. 查询租户 Leader。

        ```sql
        SELECT svr_ip, sql_port, count(1) FROM oceanbase.cdb_ob_ls_locations WHERE tenant_id=1 AND role='leader' GROUP BY svr_ip;

        ```
 3. 观察 CPU 开销。

   若 Sysbench 参数和客户端连接方式没有问题，可通过查看 CPU 使用率继续排查。

      - 查看线程 CPU 占用。

       ```shell
       top -H -p pidof observer

       ```

       如果每个业务线程基本打满一个核，继续看线程数量是否接近机器核数。

            - 如果业务线程（如 T1002_L0_G2）数量远低于机器核数，CPU 总开销也远没有达到机器上限，那么很可能是 `cpu_count` 分配太少导致的。在这种情况下，您可以检查创建租户命令，确认 `cpu_count` 是否设置得太低。
            - 如果 CPU 总开销接近机器上限，那么机器性能已到极限，只有用更高配置的机器才能跑出更高的性能。
      - 查看租户规格。

       ```sql
       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 占用率都不高，则可能是硬件方面成为瓶颈，需要继续分析。
 4. 分析硬件原因。

   排除 CPU 因素之后，剩下的硬件原因主要是磁盘和网络，磁盘和网络问题的排查思路如下。

      1. 确认网卡带宽上限，观察测试时网络带宽是否成为瓶颈（可以将 Sysbench 部署在 OBServer 机器上进行测试）。
      2. 确认网络延迟（ping），延迟过高也可能导致 SQL 执行变慢。
      3. 确认日志盘 16K 写入的带宽上限（通过 FIO测试），观察测试时磁盘 IO 是否成为瓶颈（可以更换 SSD 或 NVM 进行测试）。

   查看网络 IO 的命令：

   ```shell
   sar -n DEV 1

   ```

   查看网卡带宽上限的命令：

   ```shell
   ##（eth0 为网卡名）
   ethtool eth0

   ```
 5. 其他。

   排除上述因素外，还可能存在一些特殊情况，比如测试时间段和 observer 后台任务冲突。

   曾经有用户反映，在进行业务测试时，发现有两组数据明显低于预期。经过检查各种配置，未发现明显的问题。最终发现，该用户是在凌晨 2 点进行的业务测试，而该时间段恰好是 OceanBase 数据库进行每日转储合并的默认时间。因此，数据库的性能受到了极大的影响。

### Sysbench 的 TPS 波动，甚至跌 0

#### TPS 偶尔降低，幅度稳定

- 可能原因：OceanBase 数据库定期进行转储合并，会占用 CPU 资源，导致业务线程受到影响，`cpu_count` 越多影响越小。比如 4c8g 的租户，转储时 tps 可能下降 80%；32c64g 的租户，转储时 tps 可能下降 10%。
 - 处理方法：

     1. 调大租户资源单元的 `max_cpu`。
     2. 调大租户 CPU 并发度。

       ```sql
       alter system set cpu_quota_concurrency=4 tenant = xxx;

       ```
     3. 减少转储线程数量（`merge_thread_count`）或降低线程优先级（`compaction_high_thread_score`、`compaction_mid_thread_score`、`compaction_low_thread_score`），会让转储的单位时间开销降低，但是需要付出时间上的代价，转储整体的开销是不变的。

#### TPS 跌 0，之后偶尔会 >0

- 可能原因：发生死锁，且 Sysbench 设置了 `--mysql-ignore-errors=1062,1213,6002；`
 - 处理方法：
     1. 先检查是否有死锁。

       ```
     2. 确认后进行后续操作。

            1. Sysbench 增加 `--rand-type=uniform` 参数。
            2. 调大数据集：比如 `tables=100，table_size=1000000；`（`table_size` 默认为 10000）。

#### TPS 跌 0，之后一直保持

- 可能原因：发生死锁，且恰好没有被检测到，同时超时时间设置得很长，导致 TPS 跌 0 后不报错、不退出、不恢复。
 - 处理方法：
     1. 先检查是否有死锁。

#### TPS 降为 0，持续几秒后恢复

- 可能原因：Clog 盘满了无法写入，导致 TPS 跌 0，之后 Clog 回收空间，TPS 恢复。
 - 处理方法：检查租户磁盘空间使用量：

  ```sql
  SELECT tenant_id, svr_ip, svr_port, log_disk_in_use, log_disk_size FROM oceanbase.gv$ob_units;

  ```

  考虑分配更大的磁盘空间。

若排除上述原因后问题依然存在，请联系技术支持人员协助排查。

### Sysbench 报错

#### TPS 跌 0，之后偶尔会 >0，偶尔报错 6002 或 1213

- 可能原因：发生死锁，数据集太小或没有设置 `rand-type`，默认的 Special 类型会导致 Key 比较集中。长时间没有退出是因为大部分 SQL 还在死锁中，线程在等待 SQL 执行结束。
 - 处理方法：
     1. 先检查是否有死锁。

#### 报错 1062

- 可能原因：1062 是主键、唯一索引冲突，Sysbench 是随机生成数据，是可能导致主键冲突的。
 - 处理方法：Sysbench 增加参数：`--mysql-ignore-errors=1062`

#### 报错 1213

- 可能原因：发生死锁，死锁的部分事务被杀掉。
 - 处理方法：即使数据集非常大，并且使用了 `--rand-type=uniform` 参数，也可能会发生死锁。因此，可以使用 `--mysql-ignore-errors=1062,1213` 参数来忽略死锁错误。

#### 报错 6002

- 可能原因：6002 也可能是死锁导致的，只是最后没有报 1213 而是 6002。
 - 处理方法：调大数据集，增加 `--rand-type=uniform` 参数，减少锁冲突。增加 Sysbench 参数：`--mysql-ignore-errors=1062,1213,6002`。

#### 报错 4012

- 可能原因：锁竞争严重，或者死锁，也可能只是 OBServer 节点性能较差且客户端压力太大导致超时。
 - 处理方法：调大超时时间（单位 us）：

  ```sql
  set global ob_query_timeout = 50000000000;

  ```

#### 报错 5930

- 可能原因：开启了SQL 预编译功能，即 `--db-ps-mode=auto`，但是 OceanBase 数据库对预编译支持不够完善。
 - 处理方法：

     - 调大租户参数：`alter system set open_cursors=65535;`。
     - 也可以关闭 SQL 预编译功能进行测试：`--db-ps-mode=disable;`。

#### 其他报错

- 可能原因：可能是 OceanBase 数据库的 BUG。
 - 处理方法：请记录错误日志，然后联系技术支持人员协助排查。

## 完整分析思路

如果在快速定位问题时没有找到原因，可以按照完整的检查流程进行排查。如果在这个过程中遇到不理解的地方，可以参考后面对应的章节或链接的文档进行查看。如果最终仍然无法解决问题，请联系技术支持人员协助排查。

常规分析思路：

1. 检查硬件资源，CPU、内存、磁盘资源不足直接影响性能，甚至 TPS 会降为 0。
 2. 查看租户配置，租户分配的资源太少，硬件就没有充分利用起来。
 3. 查看 Sysbench 参数，线程数会直接影响 TPS，数据集太小或者数据分布太集中，会导致锁竞争甚至死锁。
 4. 最后再考虑 OBServer 是否有 BUG。

#### 说明

以下内容中提供的命令按需使用即可，不用全部执行一遍。

### 硬件检查

硬件资源不足，比如 CPU 内存资源太小（小于 4c8g），自然性能较差；磁盘如果快写满了，也会影响写入速度；网络延迟太高也有影响。

- CPU：`lscpu`
 - 内存：`top`、`cat /proc/meminfo`
 - 磁盘：`df -h`
 - 网络延迟：`ping ip`

### OceanBase 部署配置检查

在机器硬件资源够用的情况下，如果 OceanBase 数据库部署时的参数设置比较小，没能充分利用资源，也会导致性能下降。大多数配置都可以动态调整，只有极少数只能在部署时配置。

- 连接 SYS 租户，查看全局视图。

  ```sql
  SELECT * FROM GV$OB_SERVERS;

  ```
 - 查看网络线程数量（该配置项无法动态修改）。

  ```sql
  show parameters where name = 'net_thread_count';

  ```
 - 查看已部署集群。

  ```shell
  obd cluster list

  ```
 - 查看已部署集群配置。

  ```shell
  obd cluster edit-config [cluster name]

  ```

在 OBServer 所在机器上查看 OBServer 启动参数。

```shell
ps -ef | grep observer

```

### 租户配置检查

在 OBServer 节点资源充足的情况下，测试租户的资源是否成为瓶颈，可以通过以下命令检查。

- 查看租户基本信息。

  ```
 - 查看建租户命令。

  ```sql
  show create tenant [tenant name];

  ```
 - 查看租户对应的资源池（可以加 `tenant_id` 筛选）。

  ```sql
  SELECT * FROM oceanbase.dba_ob_resource_pools;

  ```
 - 查看对应 Unit 的配置。

  ```sql
  SELECT * FROM oceanbase.dba_ob_units;

  ```

### Sysbench 参数检查

Sysbench 参数就在 Sysbench 执行命令中，可以对照参数说明逐一检查。

### 死锁问题定位

- 查看死锁记录。

  ```

  其中 `role=victim` 表示被杀掉的事务。
 - 查看事务相关 SQL。

  ```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：

  ```sql
  show parameters where name = 'enable_sql_audit';

  ```

  如果查询到是 False，那就看不到事务对应的 SQL 命令，通过日志筛选事务 ID 可能找到一些信息。
 - 查询 SQL 对应日志。

  查到事务相关 SQL 后，用发生冲突的那条 SQL 的 Trace ID，在日志里面搜索：

  ```shell
  grep '[trace id]' observer.log*

  ```

  可以看到该条 SQL 所有的日志，一般最后一条包含报给客户端的错误码：

  ```shell
  sending error packet(err=-4101

  ```

  用最后一条 `commit` 或 `begin` 命令的 Trace ID，也可以搜索到相关日志：

  ```shell
  sending error packet(err=-6002

  ```

  如果没有日志，那就是日志级别不对，或者日志限流了。需要将日志级别调成 `WDIAG`，日志带宽限制调大：

  ```sql
  alter system set syslog_level='WDIAG';
  alter system set syslog_io_bandwidth_limit='2G';

  ```

  #### 注意

  修改配置项之前发生的死锁信息无法查找。

### 转储合并分析

1. 查看耗时超过 5s 的转储合并任务。

   ```sql
   SELECT * FROM GV$OB_MERGE_INFO WHERE tenant_id=1002 AND (END_TIME-START_TIME)>5 LIMIT 10;

   ```
 2. 查看某张表的合并记录。

   ```sql
   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;

   ```
 3. 主动触发转储。

   ```sql
   alter system minor freeze tenant=xxx;

   ```

还可以在 OBServer 节点上执行 top -H，观察 MINI_MERGE、MINOR_EXE 线程的开销，但是持续时间比较短。

### 慢 SQL 查询

1. 查询超过 5s 的慢 SQL，打印所有信息。

   ```sql
   SELECT * FROM gv$ob_sql_audit WHERE elapsed_time > 5000000 LIMIT 10;

   ```
 2. 自定义打印关键信息。

   ```sql
   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 功能：

   ```sql
   show parameters where name = 'enable_sql_audit';
   alter system set enable_sql_audit = true;

   ```

### 日志问题排查

查看磁盘空间使用情况。

```sql
SELECT tenant_id, svr_ip, svr_port, LOG_DISK_IN_USE, LOG_DISK_SIZE FROM gv$ob_units;

```

### 问题复现流程

1. 首先可以清空之前的 `sql_audit` 记录。

   ```sql
   alter system set enable_sql_audit = false;
   alter system flush sql audit global;

   ```
 2. 开启 `sql_audit` 记录。

   ```sql
   alter system set enable_sql_audit = true;

   ```
 3. 修改日志级别。

   ```sql
   alter system set syslog_level='WDIAG';

   ```
 4. 调小 SQL 记录阈值，尽可能记录更多的 SQL。

   ```sql
   alter system set trace_log_slow_query_watermark = '10ms';

   ```
 5. 调大系统日志带宽限制，避免因为限流导致丢失关键日志。

   ```sql
   alter system set syslog_io_bandwidth_limit='2G';

   ```
 6. 如果不希望事务超时，还可以调大超时时间。

   ```

之后，设置和问题场景相同的参数，开始执行 Sysbench。

## OceanBase 数据库部署参数配置

### 安装部署流程

- 开源版安装部署流程

  使用 OBD 部署：[使用命令行部署 OceanBase 数据库生产环境](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000218707)
 - 企业版安装部署流程

     - 企业版部署：[部署流程](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000218233)

### 安装部署参数说明

除了快速安装流程，一般都需要手动修改 `.yaml` 文件进行配置。OceanBase 数据库可配置的参数很多，本文重点关注性能相关的参数，详细信息请参考前面的部署文档。

- 查询配置项：`show parameters where name = 'xxx';`
 - 查询 Server 关键参数：`SELECT * FROM GV$OB_SERVERS;`

具体涉及到的配置项包含以下几个：

- **memory_limit**

     - 参数含义：OBServer 节点内存上限，优先于 `memory_limit_percentage` 配置项
     - 默认值：0
     - 推荐配置：系统总内存的 80%~90%
     - 动态修改：`alter system set memory_limit='32G';`
     - 查询：`show parameters where name = 'memory_limit';`
     - 相关文档：[memory_limit](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220427)
 - **memory_limit_percentage**

     - 参数含义：OBServer 节点内存占系统内存的百分比（`memory_limit` 为 0 时该配置项才生效）
     - 默认值：80
     - 推荐配置：80~90
     - 动态修改：`alter system set memory_limit_percentage=80;`
     - 查询：`show parameters where name = 'memory_limit_percentage';`
     - 相关文档：[memory_limit_percentage](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220428)
 - **system_memory**

     - 参数含义：系统租户占用的内存，包含在 `memory_limit` 里面，未配置的情况下会自适应设置。
     - 默认值：企业版：30G 社区版：0M
     - 推荐配置：`memory_limit` 的 10%
     - 动态修改：`alter system set system_memory='2G';`
     - 查询：`show parameters where name = 'system_memory';`
     - 相关文档：[system_memory](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220510)
 - **cpu_count**

     - 参数含义：OBServer 节点可用 CPU 总数
     - 默认值：0（系统将会自动检测 CPU 数量）
     - 推荐配置：系统 CPU 总数（通过 `lscpu` 查看）
     - 动态修改：`alter system set cpu_count=24;`
     - 查询：`show parameters where name = 'cpu_count';`
     - 相关文档：[cpu_count](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220442)
 - **net_thread_count**

     - 参数含义：网络线程数量
     - 默认值：0（网络 I/O 线程数量为 max(6, CPU_NUM/8)）
     - 推荐配置：CPU 总数的 1/8，如果事务耗时较少，相对来说网络开销较大，可以设置为 CPU 总数的 20%
     - 该配置项只能在部署 OBServer 节点时静态设置，不能动态修改
     - 查询：`show parameters where name = 'net_thread_count';`
     - 相关文档：[net_thread_count](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220533)
 - **sql_net_thread_count**

  相关文档：[sql_net_thread_count](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220482)
 - **datafile_size**

     - 参数含义：数据文件的总大小，优先于 `datafile_disk_percentage` 配置项
     - 默认值：0
     - 推荐配置：与日志共用磁盘时设为磁盘空间的 60%，独占磁盘时设为磁盘空间的 90%
     - 动态修改：`alter system set datafile_size='80G';`
     - 查询：`show parameters where name = 'datafile_size';`
     - 相关文档：[datafile_size](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220418)
 - **datafile_disk_percentage**

     - 参数含义：数据文件占用其所在磁盘总空间的百分比
     - 默认值：0
     - 推荐配置：与日志共用磁盘时设为 60%，独占磁盘时设为 90%
     - 动态修改：`alter system set datafile_disk_percentage=60;`
     - 查询：`show parameters where name = 'datafile_disk_percentage';`
     - 相关文档：[datafile_disk_percentage](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220494)
 - **log_disk_size**

     - 参数含义：redo 日志文件的总大小，优先于 `log_disk_percentage` 配置项
     - 默认值：0
     - 推荐配置：与数据共用磁盘时设为 30，独占磁盘时设为 90
     - 动态修改：`alter system set log_disk_size='40G';`
     - 查询：`show parameters where name = 'log_disk_size';`

  相关文档：[log_disk_size](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220628)
 - **log_disk_percentage**
 - 参数含义：redo 日志文件占用其所在磁盘总空间的百分比
 - 默认值：0
 - 推荐配置：与数据共用磁盘时设为磁盘空间的 30%，独占磁盘时设为磁盘空间的90%
 - 动态修改：`alter system set log_disk_percentage=30;`
 - 查询：`show parameters where name = 'log_disk_percentage';`

  相关文档：[log_disk_percentage](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220584)

### 配置文件

这里以机器规格为 32c128g 为例，磁盘空间充足。以 “3 个 OBServer 节点 + 1 个 OBProxy” 的部署方式进行说明，暂不考虑 obagent 等其他组件。为了更好的性能，每个 OBServer 节点和 OBProxy 部署在不同的机器上，尽可能充分地利用机器的硬件资源。

```cpp
oceanbase:
  servers:
    * name: server1
      ip: xxx.xxx.1.1
    * name: server2
      ip: xxx.xxx.1.2
    * name: server3
      ip: xxx.xxx.1.3
  server1:
    mysql_port: 2881
    rpc_port: 2882
    home_path: /data/1/user_name/observer1
    zone: zone1
  server2:
    mysql_port: 2881
    rpc_port: 2882
    home_path: /data/1/user_name/observer2
    zone: zone2
  server3:
    mysql_port: 2881
    rpc_port: 2882
    home_path: /data/1/user_name/observer3
    zone: zone3
  include: obd/observer.include.yaml
  global:
    devname: eth0
    memory_limit: '100G'
    system_memory: '2G'
    datafile_size: '80G'
    cpu_count: '32'
    net_thread_count: 6
obproxy:
  servers:
    * xxx.xxx.1.5
  depends:
    * oceanbase
  include: obd/obproxy.include.yaml
  global:
    listen_port: 2891
    prometheus_listen_port: 2892
    home_path: /data/1/user_name/obproxy

```

## 业务租户参数配置

### 创建租户

OceanBase 数据库仅支持创建用户租户，系统租户由集群创建时自动创建。创建用户租户是一系列操作的组合，首先创建资源规格，然后基于该资源规格创建资源池，最后创建租户并指定其资源池。所以创建租户的顺序为：资源规格 -> 资源池 -> 租户。

有关创建租户的详细操作，参见 [创建租户](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000218355)。

#### 创建租户的命令

#### 说明

如果用 OBD 自动部署，部署之后只有一个 SYS 租户。然后可以创建一个专门进行性能测试的租户，尽可能充分利用 OBServer 节点的可用资源。

这里以 32c128g 的机器为例，创建租户的命令如下。

```shell
sh create_perf_tenant.sh ip port

```

```cpp
mysql -c -h $1 -P $2 -uroot -e "drop resource unit unit_1;"
mysql -c -h $1 -P $2 -uroot -e "create resource unit unit_1 max_cpu 24, min_cpu 16, memory_size 64000000000, log_disk_size 40000000000, max_iops 10000000;"
mysql -c -h $1 -P $2 -uroot -e "create resource pool pool_2 unit = 'unit_1', unit_num = 1, zone_list = ('zone1','zone2','zone3');"
mysql -c -h $1 -P $2 -uroot -e "create tenant perf replica_num = 3,primary_zone='zone1', resource_pool_list=('pool_2') set ob_tcp_invited_nodes='%';"
mysql -c -h $1 -P $2 -uroot@perf -e "set global ob_query_timeout = 50000000000;"
mysql -c -h $1 -P $2 -uroot@perf -e "set global ob_trx_timeout = 50000000000;"
mysql -c -h $1 -P $2 -uroot@perf -e "set global ob_plan_cache_percentage = 20;"
mysql -c -h $1 -P $2 -uroot@perf -e "set global binlog_row_image='MINIMAL';"
mysql -c -h $1 -P $2 -uroot -e "alter system set enable_early_lock_release=true tenant = perf;"
mysql -c -h $1 -P $2 -uroot -e "alter system set cpu_quota_concurrency=2 tenant = perf;"

```

如果建租户命令没有指定租户类型，默认是 MySQL 租户，指定了 Oracle 模式才是 Oracle 租户。

SYS 租户执行下面的命令，COMPATIBILITY_MODE 字段表明了租户是什么模式：

```sql
SELECT * FROM DBA_OB_TENANTS;

```

### 租户关键配置

性能关键的租户配置项如下。

- **min_cpu**

     - 参数说明：租户最小可用 CPU 数量（所有租户 `min_cpu` 之和 <= `cpu_count`）
     - 推荐值：`cpu_count`/2
     - 相关文档：`min_cpu` 参数详细信息请参见 [创建租户](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000218355) 中 **创建资源单元** 的 **参数解释**。
 - **max_cpu**

     - 参数说明：租户最大可用 CPU 数量（所有租户 `max_cpu` 之和 <= `cpu_count` * `resource_hard_limit` / 100）
     - 推荐值：`cpu_count`/2 ~ `cpu_count`（或者跟 `min_cpu` 设成一样也行）
     - 相关文档：`min_cpu` 参数详细信息请参见 [创建租户](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000218355) 中 **创建资源单元** 的 **参数解释**。
 - **cpu_quota_concurrency**

     - 参数说明：租户每个 CPU 可以并发的线程数（`max_cpu` * `cpu_quota_concurrency` = 最大业务线程数）
     - 推荐值：4（一般建议默认值不改，CPU 密集的压测可以改为 2）
     - 相关文档：[cpu_quota_concurrency](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220356)
 - **memory_size**

     - 参数说明：资源单元能够提供的 Memory 的大小
     - 推荐值：总内存的 50%~80%（如果要创建多个资源单元，则需要灵活分配）
 - **log_disk_size**

     - 参数说明：日志盘大小
     - 推荐值：够用就行，比如设置为 40~80GB，如果数据量很大则可以设置更大的数值。
 - **primary_zone**

     - 参数说明：主副本分配到 Zone 内的优先级，逗号两侧优先级相同，分号左侧优先级高于右侧。比如 `zone1,zone2,zone3`。
     - 推荐值：

           1. 三台机器规格相同且网络延迟相近，可以让 Leader 均匀分布，以提高性能：RANDOM。
           2. 如果其中一台性能更好，或者是为了方便统计和观察数据，也可以指定该 Zone 比如：`zone1`。

## 系统租户全局配置

连接系统租户修改集群级别的配置，比如修改日志级别，关闭 sql_audit 等影响性能的功能。

```cpp
ALTER system SET enable_sql_audit=false;
select sleep(5);
ALTER system SET enable_perf_event=false;
ALTER system SET syslog_level='ERROR';
alter system set enable_record_trace_log=false;

```

## Sysbench 参数配置

### Sysbench 测试流程

- 安装部署

  相关文档：详细信息请参见 [OceanBase 数据库 Sysbench 测试](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000218151) 中的 **安装 Sysbench**。
 - 准备数据

  ```shell
  cleanup：
  sysbench oltp_read_write.lua --mysql-host=x.x.x.x --mysql-port=xxxx --mysql-db=test --mysql-user=test@xxx --mysql-password=xxx --table_size=1000000 --tables=30 --rand-type=uniform --threads=1000  --report-interval=1 --time=600 cleanup
  prepare：
  sysbench oltp_read_write.lua --mysql-host=x.x.x.x --mysql-port=xxxx --mysql-db=test --mysql-user=test@xxx --mysql-password=test --table_size=1000000 --tables=30 --rand-type=uniform --threads=1000  --report-interval=1 --time=600 prepare

  ```
 - 运行测试

  ```shell
  sysbench oltp_read_write.lua --mysql-host=x.x.x.x --mysql-port=xxxx --mysql-db=test --mysql-user=test@xxx --mysql-password=xxx --table_size=1000000 --tables=30 --rand-type=uniform --threads=1000  --report-interval=1 --time=600 --db-ps-mode=disable run

  ```

### 性能关键参数配置

相关文档：[Sysbench 参数详解](https://github.com/wing324/helloworld_zh/blob/master/Linux/sysbench/sysbench%E5%8F%82%E6%95%B0%E8%AF%A6%E8%A7%A3.md)。

- **table_size**

     - 参数说明：每张表初始化的数据行数，默认 10000
     - 推荐值：100000, 1000000
 - **tables**

     - 参数说明：初始化表的数量
     - 推荐值：30 ~ 100
 - **threads**

     - 参数说明：测试线程的数量
     - 推荐值：500 ~ 2000（测试机 CPU 越多线程数可以越大）
 - **rand-type**

  参数说明：表示随机类型的模式，共有 4 种模式：uniform (固定)、gaussian (高斯)、special (特定)、pareto (帕雷特)，默认值为：special。

     1. special：Key 比较集中的分布模式，容易发生锁冲突。
     2. uniform：离散均匀分布，范围内所有数值出现概率均等，没有热点。
     3. gaussian：高斯分布，也就是正态分布，数据集中在中位数附近。
     4. pareto：帕累托分布，数据集中在最小值附近，越大的值出现概率越小。

  推荐值：uniform
 - **mysql-ignore-errors**

     - 参数说明：测试过程中忽略的错误码。Sysbench 一旦收到报错，就会停止发送新请求，直到当前请求全部返回，然后退出测试。因此如果是预期之内的问题，可以选择忽略相关错误码。
     - 可选值：`--mysql-ignore-errors=1062,1213,6002`，其中 `1062` 是主键、唯一索引冲突，`1213` 是 Dead Lock，`6002` 是 Trans Rollback。
 - **db-ps-mode**

     - 参数说明：SQL 是否需要预编译，模式有：auto/disable，默认为 disable。
     - 推荐值：disable（建议设置为 disable）
     - 如果设置了 auto，需要修改租户配置：`alter system set open_cursors=65535;`
 - **skip_trx**

     - 参数说明：跳过事务，在只读测试中可以选择是否跳过事务， 默认为 OFF，即开启事务。
     - 推荐值：只读测试可以设置为 ON，其他情况默认。
 - **auto-inc**

     - 参数说明： ID 列是否自增，默认 ON
     - 推荐值：OFF（写场景下建议关闭）
 - **warmup-time**
 - 参数说明：热身时间（单位为 s），表示测试开始多少时间之后正式开始统计，默认为 0。
 - 推荐值：10~30（数据量大时间可以略长）

## Sysbench 性能问题案例

### TPS 下降为 0，偶尔报错

#### 问题现象

使用 OceanBase 数据库社区版 V4.1.0，执行以下命令进行 Sysbench 测试，TPS 下降为 0 并报错。

```shell
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

```

机器配置：

![image.png](https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/doc/img/observer-enterprise/V4.3.0/develop/java/machine-config.png)

#### 问题原因与分析

初步判断是因为 `table_size` 较小，而数据分布默认是 special 模式，导致数据比较集中，主键冲突严重，最终发生了死锁，TPS 跌 0。

1. 首先测试租户超时时间调大。

   ```sql
   set global ob_query_timeout = 50000000000;
   set global ob_trx_timeout = 50000000000;

   ```
 2. 为了尽快复现，我们将 `Tables` 设置为 1，其他参数不变。

   ```shell
    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

   ```
 3. 生成现象：TPS 跌到 0，但偶尔 TPS 和 QPS 会大于 0。

   ![image0.png](https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/doc/img/observer-enterprise/V4.1.0/7.reference/3.performance-tuning-guide/6.performance-whitepaper/sysbench/%E6%9F%A5%E7%9C%8B%E5%86%85%E9%83%A8%E8%A1%A8-0.png)
 4. 查看死锁视图。

   ```

   ![image1.png](https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/doc/img/observer-enterprise/V4.1.0/7.reference/3.performance-tuning-guide/6.performance-whitepaper/sysbench/%E6%9F%A5%E7%9C%8B%E5%86%85%E9%83%A8%E8%A1%A8-1.png)

   可以看到最近的死锁记录，`role=victim` 表示被杀掉的事务，`role=witness` 表示见证冲突的事务。`cycle_size=2` 说明只有两个事务相互冲突，`cycle_size>2` 说明多个事务和一个事务冲突。这里我们为了便于观察选择一个 `cycle_size=2` 的 Event，通过 `event_id` 可以筛选出一组冲突的事务。

   ```sql
   SELECT * FROM oceanbase.CDB_OB_DEADLOCK_EVENT_HISTORY WHERE cycle_size=2 ORDER BY create_time DESC LIMIT 10;

   ```

   ![image2.png](https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/doc/img/observer-enterprise/V4.1.0/7.reference/3.performance-tuning-guide/6.performance-whitepaper/sysbench/%E6%9F%A5%E7%9C%8B%E5%86%85%E9%83%A8%E8%A1%A8-2.png)

   Visitor 字段中可以看到事务 ID，通过事务 ID 可以找到该事务相关的所有 SQL 命令：

   ```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;

   ```

   ![image3.png](https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/doc/img/observer-enterprise/V4.1.0/7.reference/3.performance-tuning-guide/6.performance-whitepaper/sysbench/%E6%9F%A5%E7%9C%8B%E5%86%85%E9%83%A8%E8%A1%A8-3.png)

   从图中可以看到两个事务发生了交叉依赖的情况，即：

      - 事务 1 更新 id=4978。
      - 事务 2 更新 id=5049。
      - 事务 1 更新 id=4978。
      - 事务 2 删除 id=5049。

   发生死锁之后，事务 64317 回滚，事务 64235 成功提交。因为事务 64317 的创建时间更晚，这个可以查看 sql_audit 找到事务的第一条 SQL，通过 SQL 的 `request_time` 进行判断。

   ```sql
   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 回滚错误。

   ```shell
   [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 错误报了出来。

   ```shell
   [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")

   ```

   如果搜不到日志，可能是日志限流导致，建议调大系统日志带宽限制：

   ```

#### 结论

**结论：**

1. 在默认 `rand-type=special` 场景下，可能因为 Key 冲突太多从而出现死锁，这种场景下 Sysbench 压测会退出。
 2. 在默认 `rand-type=special` 场景下，如果 `tables` 和 `table_size` 也比较小，死锁出现得更为频繁，会导致大量事务卡住，测试线程无法及时退出，从而出现一段时间（几分钟）内 tps 跌 0 的情况，偶尔 tps 也可能大于 0。
 3. 死锁的事务会报错回滚，错误码可能是 6002（而不是 1213）。
 4. 如果 `ob_query_timeout` 设置比较长，又碰巧出现死锁检测功能没有生效，事务无法被杀掉，SQL 一直阻塞，这种情况 tps 会长期为 0，且不报错。

**解决方法：**

1. 首先考虑调整数据分布类型：设置 `--rand-type=uniform`
 2. 如果不考虑调整数据分布类型，建议调大数据集：比如 `tables=100，table_size=1000000`
 3. 若数据随机类型和数据集都不考虑调整，则可以尝试忽略错误码，但这样无法避免死锁： `--mysql-ignore-errors=1062,1213,6002`

 上一篇 下一篇 ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
