
作者:郑增权,爱可生 DBA 团队成员,OceanBase 和 MySQL 数据库技术爱好者。
爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
本文约 2800 字,预计阅读需要 10 分钟。

1. 背景
在使用 OceanBase 数据库的过程中,对 workers_per_cpu_quota
、px_workers_per_cpu_quota
、parallel_servers_target
、cpu_quota_concurrency
等参数或变量存在如下疑惑:
具体含义是什么? 互相之间的区别/关联是什么? 大查询如何影响 CPU 资源分配和 SQL 执行耗时?
本文适用于 OceanBase v4 版本,尝试通过理论结合实验的方式探究以上问题。
2. 租户线程相关概念
2.1 租户最大线程数
为了维持租户活跃线程数恒定,同时考虑到大查询线程挂起的发生,租户就需要动态的从多租户线程池中申请线程。最大线程数用于限制单个租户的内存开销,每个租户总共可持有的最大线程数受配置项和 Unit 规格共同决定。
租户最大线程数 = unit_max_cpu × workers_per_cpu_quota
2.2 租户活跃线程数
活跃线程表示能正常处理请求的线程,与挂起线程区分,活跃线程数用于限制单个租户的 CPU 使用。租户运行时会维持活跃线程数恒定,租户的活跃线程数受配置项和 Unit 规格共同决定。
租户活跃线程数上限 = unit_min_cpu × cpu_quota_concurrency
3. 大查询与 CPU 的关联
通过配置参数 large_query_threshold
来定义执行时间超过一定阈值的查询操作为大查询。
如果系统中同时运行着大查询和小查询,OceanBase 会将一部分 CPU 资源分配给大查询,并通过配置参数 large_query_worker_percentage
(默认值为 30%)来限制执行大查询最多可以使用的租户活跃工作线程数。OceanBase 通过限制大查询能使用的租户活跃工作线程数来约束大查询最多能够使用的 CPU 资源,以此来保证系统还会有足够的 CPU 资源来执行 OLTP 负载。 large_query_threshold
参数不应该设置成为一个过大的值。否则大查询很容易抢占系统的 CPU 资源而引发 OLTP 响应过慢甚至队列堆积的问题。
4. 参数一览

5. 参数讲解
5.1 workers_per_cpu_quota 与 cpu_quota_concurrency 的关系
租户中可同时处理的线程数由 workers_per_cpu_quota
与 cpu_quota_concurrency
这两个配置项控制。
workers_per_cpu_quota
表示租户在每个 CPU 上能分配的最大工作线程数。cpu_quota_concurrency
表示租户的每个 CPU 配额所允许的最大活跃线程数,即并发数。设置时需要满足
workers_per_cpu_quota > cpu_quota_concurrency
。
5.2 parallel_servers_target
parallel_servers_target = MIN CPU × px_workers_per_cpu_quota
作用:该参数主要是控制当多条并行执行(Parallel eXecution,PX)的 SQL 总计消耗的线程数超过并行查询排队条件后,后继并行执行 SQL 需要进入排队等待。
并行查询排队:通过
PARALLEL_SERVERS_TARGET
指定租户在每个节点上最多可提供的并行执行工作线程数。在并行查询开始之前,会从所有相关 observer 预约工作线程资源。只要其中任何一个 observer 无法为并行查询提供足够的资源,该查询就不会投入执行。 此并行查询会被重新排队,等待下一次执行时重新尝试获取线程资源,直到能够获取足够的工作线程资源为止。 整个查询执行完成后,会立即释放预约的工作线程资源。 参数设置建议:
一般把 parallel_servers_target
设置为 MIN CPU * 10 即可。IO 密集型场景,CPU 可能用不满,可以将 parallel_servers_target
设置为 MIN CPU * 20。
提示
参数
px_workers_per_cpu_quota
对parallel_servers_target
默认值的影响仅发生在创建租户时,租户创建完成后,修改px_workers_per_cpu_quota
的值并不会改变parallel_servers_target
的值。
5.3 px_workers_per_cpu_quota
每个 CPU 上可以分配的并行执行线程数。 当分配给租户的 MIN CPU 为 N 时 如果并行负载均匀,那么每个节点上可以分配的线程数为 N * px_workers_per_cpu_quota
。如果并行负载访问的数据分布不均匀,某些节点上实际分配的线程数可能在短时间内超过 N * px_workers_per_cpu_quota
,当负载结束后,这些多分配的线程会被自动回收。一般情况下,不需要更改 px_workers_per_cpu_quota
的默认值。
6. 实验论证
6.1 准备环境
新建一个 1-1-1 架构,规格 8C6G 的 mysql 租户。
使用 sys
租户执行
obclient [oceanbase]> SELECT
-> t1.tenant_name,
-> CONCAT(t2.svr_ip, ':', t2.svr_port) AS"unit_server",
-> CONCAT(t4.unit_count, ' unit: ', t3.min_cpu, 'C/', ROUND(t3.memory_size 1024 / 1024 / 1024, 0), 'G') AS unit_info,
-> t3.min_cpu,
-> t3.max_cpu
-> FROM
-> OCEANBASE.DBA_OB_TENANTS t1
-> INNERJOIN OCEANBASE.DBA_OB_RESOURCE_POOLS t4 ON t1.tenant_id = t4.tenant_id
-> INNERJOIN OCEANBASE.DBA_OB_UNITS t2 ON t4.resource_pool_id = t2.resource_pool_id
-> INNERJOIN OCEANBASE.DBA_OB_UNIT_CONFIGS t3 ON t4.unit_config_id = t3.unit_config_id
-> WHERE
-> t1.tenant_id = 1008
-> ORDERBY
-> unit_server;
+-------------+-------------------+---------------+---------+---------+
| tenant_name | unit_server | unit_info | min_cpu | max_cpu |
+-------------+-------------------+---------------+---------+---------+
| mysql_ob | 10.186.64.10:2882 | 1 unit: 8C/6G | 8 | 8 |
| mysql_ob | 10.186.64.61:2882 | 1 unit: 8C/6G | 8 | 8 |
| mysql_ob | 10.186.64.62:2882 | 1 unit: 8C/6G | 8 | 8 |
+-------------+-------------------+---------------+---------+---------+
3 rows in set (0.053 sec)
MIN_CPU = 8,MAX_CPU = 8。
6.2 查看租户相关参数或变量值
使用业务租户执行
obclient [oceanbase]> show parameterslike'workers_per_cpu_quota';
+-------+----------+--------------+----------+-----------------------+-----------+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------+---------+---------+---------+-------------------+
| zone | svr_type | svr_ip | svr_port | name | data_type | value | info | section | scope | source | edit_level |
+-------+----------+--------------+----------+-----------------------+-----------+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------+---------+---------+---------+-------------------+
| zone1 | observer | 10.186.64.61 | 2882 | workers_per_cpu_quota | NULL | 10 | the ratio(integer) between the number of system allocated workers vs the maximum number of threads that can be scheduled concurrently. Range: [2, 20] | TENANT | CLUSTER | DEFAULT | DYNAMIC_EFFECTIVE |
| zone3 | observer | 10.186.64.62 | 2882 | workers_per_cpu_quota | NULL | 10 | the ratio(integer) between the number of system allocated workers vs the maximum number of threads that can be scheduled concurrently. Range: [2, 20] | TENANT | CLUSTER | DEFAULT | DYNAMIC_EFFECTIVE |
| zone2 | observer | 10.186.64.10 | 2882 | workers_per_cpu_quota | NULL | 10 | the ratio(integer) between the number of system allocated workers vs the maximum number of threads that can be scheduled concurrently. Range: [2, 20] | TENANT | CLUSTER | DEFAULT | DYNAMIC_EFFECTIVE |
+-------+----------+--------------+----------+-----------------------+-----------+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------+---------+---------+---------+-------------------+
3 rows in set (0.01 sec)
obclient [oceanbase]> showparameterslike'px_workers_per_cpu_quota';
+-------+----------+--------------+----------+--------------------------+-----------+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------+---------+--------+---------+-------------------+
| zone | svr_type | svr_ip | svr_port | name | data_type | value | info | section | scope | source | edit_level |
+-------+----------+--------------+----------+--------------------------+-----------+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------+---------+--------+---------+-------------------+
| zone1 | observer | 10.186.64.61 | 2882 | px_workers_per_cpu_quota | NULL | 10 | the ratio(integer) between the number of system allocated px workers vs the maximum number of threads that can be scheduled concurrently. Range: [0, 20] | TENANT | TENANT | DEFAULT | DYNAMIC_EFFECTIVE |
| zone3 | observer | 10.186.64.62 | 2882 | px_workers_per_cpu_quota | NULL | 10 | the ratio(integer) between the number of system allocated px workers vs the maximum number of threads that can be scheduled concurrently. Range: [0, 20] | TENANT | TENANT | DEFAULT | DYNAMIC_EFFECTIVE |
| zone2 | observer | 10.186.64.10 | 2882 | px_workers_per_cpu_quota | NULL | 10 | the ratio(integer) between the number of system allocated px workers vs the maximum number of threads that can be scheduled concurrently. Range: [0, 20] | TENANT | TENANT | DEFAULT | DYNAMIC_EFFECTIVE |
+-------+----------+--------------+----------+--------------------------+-----------+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------+---------+--------+---------+-------------------+
3 rows in set (0.01 sec)
obclient [oceanbase]> showparameterslike'cpu_quota_concurrency';
+-------+----------+--------------+----------+-----------------------+-----------+-------+--------------------------------------------------------+---------+--------+---------+-------------------+
| zone | svr_type | svr_ip | svr_port | name | data_type | value | info | section | scope | source | edit_level |
+-------+----------+--------------+----------+-----------------------+-----------+-------+--------------------------------------------------------+---------+--------+---------+-------------------+
| zone1 | observer | 10.186.64.61 | 2882 | cpu_quota_concurrency | NULL | 4 | max allowed concurrency for 1 CPU quota. Range: [1,20] | TENANT | TENANT | DEFAULT | DYNAMIC_EFFECTIVE |
| zone3 | observer | 10.186.64.62 | 2882 | cpu_quota_concurrency | NULL | 4 | max allowed concurrency for 1 CPU quota. Range: [1,20] | TENANT | TENANT | DEFAULT | DYNAMIC_EFFECTIVE |
| zone2 | observer | 10.186.64.10 | 2882 | cpu_quota_concurrency | NULL | 4 | max allowed concurrency for 1 CPU quota. Range: [1,20] | TENANT | TENANT | DEFAULT | DYNAMIC_EFFECTIVE |
+-------+----------+--------------+----------+-----------------------+-----------+-------+--------------------------------------------------------+---------+--------+---------+-------------------+
3 rows in set (0.02 sec)
obclient [oceanbase]> showvariableslike'parallel_servers_target';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| parallel_servers_target | 80 |
+-------------------------+-------+
1 row in set (0.00 sec)
obclient [oceanbase]>
根据以上数据及公式计算可知:

租户最大线程数 = 80 租户活跃线程数上限 = 32 parallel_servers_target = 80
6.3 准备数据
创建一个 12 个分区的表,并在每个分区插入 150 万条数据。库名:zengquan_zheng
,表名:test_table
。
6.4 虚拟机 CPU 及 磁盘性能
6.4.1 对 3 台虚拟机的 CPU 进行压测
VM1:10-186-64-61 VM2:10-186-64-10 VM3:10-186-64-62
sysbench cpu --cpu-max-prime=20000 --threads=$(nproc) run

虚拟机 CPU 性能排序:
VM1 > VM2 > VM3
6.4.2 OBServer 所在盘性能采样

数据盘及日志盘均共用一块硬盘。
虚拟机磁盘性能排序:
VM1 > VM3 > VM2
6.5 压测限制及观察方法

观察租户在不同 priamry_zone 和不同并发数下的表现,方法如下:
并发执行可能导致 SQL 重试,SQL实际执行次数可能大于压测并发数。 本文记录单次采样结果,实际结果可能受虚拟机所在的物理机的繁忙度/性能影响。 zone 优先级 zone3;zone2,zone1
:分号左侧优先级高于右侧,逗号则代表两侧优先级相同。观察租户队列积压: grep "dump tenant info" observer.log | grep "id:$tenant_id" | grep -o "req_queue:total_size=....."每次压测之前针对目标 SQL 的 sql_id
执行flush plan cache
以便直观观察大查询数量增长情况:
ALTER SYSTEM FLUSH PLAN CACHE sql_id='$sql_id' databases='zengquan_zheng' tenant='mysql_ob' GLOBAL;`
6. 观察触发大查询次数:select svr_ip,sql_id,query_sql,large_querys from gv$ob_plan_cache_plan_stat where tenant_id = $tenant_id and sql_id='$sql_id'
;
或在 observer.log
检索关键字 It's a large query, need delay, do not need disconnect。
6.5.3 压测结果
场景一
75/78/80/85 并发执行如下查询 SQL,大查询阈值 5s。
//单条 SQL 执行耗时:约 700ms
SELECT * FROM zengquan_zheng.test_table limit 100000;
场景二
75/78/80/85 并发执行如下查询 SQL,大查询阈值 5s。
//单条 SQL 执行耗时:约 10s
SELECT * FROM test_table limit 5000000;
场景三
100 并发执行如下查询 SQL,大查询阈值 5s。
//单条 SQL 执行耗时:约 10s
SELECT * FROM test_table limit 5000000;
场景四
100 并发执行如下查询 SQL,大查询阈值 50s。
//单条 SQL 执行耗时:约 10s
SELECT * FROM test_table limit 5000000;
场景五
各自 50 并发同时执行如下查询 SQL,大查询阈值 5s。
//单条 SQL 执行耗时:约 10s
SELECT * FROM test_table limit 5000000;
//单条 SQL 执行耗时:约 700ms
SELECT * FROM zengquan_zheng.test_table limit 100000;
7. 结论
场景一&场景二:
parallel_servers_target
等于 80,但在实际应用场景中,达到 80 并发并不一定会产生队列等待;未达到 80 并发也可能产生队列等待,与查询种类(大查询/小查询)密切相关。场景三&场景四:大查询阈值并非越大越好,在 primary_zone 为 zone 相同优先级时,大查询阈值过大可能导致严重的队列积压从而导致 SQL 执行耗时大幅度上升。
场景一&场景五:当单独并发执行小查询时耗时可能很快,但是大查询与小查询同时并发执行时大查询可能会导致小查询的执行耗时也大幅升高。
以上场景的压测结果与机器的 CPU 性能、磁盘性能、内存大小,OB 端 CPU/大查询相关参数等均有关联关系。
参数值设置建议根据实际业务场景压测后调整,无特殊需求则采用默认值即可。
8. 参考资料
《cpu_quota_concurrency》:https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000002015547 《并行查询的参数调优》:https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000002013758 《设置并行执行参数》:https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000002016195 《并发控制与排队》:https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000002016196 《PX 并行度与速度快慢的关系》:https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000000466049?back=kb 《工作线程》:https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000002014039 《多租户线程常见问题》:https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000218492 《后台线程》:https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000002014037
本文关键字:#OceanBase #性能参数


✨ Github:https://github.com/actiontech/sqle
📚 文档:https://actiontech.github.io/sqle-docs/
💻 官网:https://opensource.actionsky.com/sqle/
👥 微信群:请添加小助手加入 ActionOpenSource
🔗 商业支持:https://www.actionsky.com/sqle










