首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >如何计算 OceanBase 最大/最小工作线程数?

如何计算 OceanBase 最大/最小工作线程数?

作者头像
爱可生开源社区
发布2025-07-10 10:41:15
发布2025-07-10 10:41:15
1560
举报

1. 背景

书接上文多场景 OceanBase 并发参数调整方案引发的疑问。

当基于 observer.log 查看 1008 租户(租户名:mysql_ob)队列积压情况时看到如下 2 个值,疑惑的是 unit_min_cpuunit_max_cpu 都等于 8 ,如下 2 个值又是如何计算出来的?

代码语言:javascript
复制
min_worker_cnt:34 //最小工作线程数
max_worker_cnt:150 //最大工作线程数

参考《租户资源管理》[1]

2. 前文相关参数一览

2.1 租户配置

代码语言:javascript
复制
+-------------+-------------------+---------------+---------+---------+
| 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 |
+-------------+-------------------+---------------+---------+---------+

2.2 相关参数或变量

代码语言:javascript
复制
workers_per_cpu_quota = 10
px_workers_per_cpu_quota = 10
cpu_quota_concurrency = 4
parallel_servers_target = 80

3. 源码探究计算逻辑

我们将对 OceanBase 企业版解析为反汇编代码,再通过社区版开源的源码[2]进行逻辑对应验证。

3.1 min_worker_cnt 计算逻辑

查看 OceanBase 社区版代码。

代码语言:javascript
复制
int64_t ObTenant::min_worker_cnt() const
{
  ObTenantConfigGuard tenant_config(TENANT_CONF(id_));
  return 2 + std::max(1L, static_cast<int64_t>(unit_min_cpu() * (tenant_config.is_valid() ? tenant_config->cpu_quota_concurrency : 4)));
}
  • cpu_quota_concurrency:配置有效时使用赋予的值,否则默认值为 4。
  • min_worker_cnt = 2 + max(1, unit_min_cpu() * cpu_quota_concurrency)
  • unit_min_cpu * cpu_quota_concurrency > 1 时,将此值 + 2,否则等于 3 。

OceanBase 企业版反汇编代码(对比查看,确认与社区版的逻辑基本是一致的)。

代码语言:javascript
复制
589b54e: movsd 0x328(%r15) //%xmm0 从 ObTenant 对象偏移 0x328 读取双精度浮点数,存入 %xmm0,可能是线程需求的比例或权重。
589b557: test %rax //%rax 检查配置对象是否有效。
589b55a: je 589b599 //如果无效,跳转到默认值处理逻辑。
589b55c: movsd 0x40858(%rax) //%xmm1 从配置对象偏移 0x40858 读取双精度值,可能是基础线程数或配置参数。
589b564: cvttpd2dq %xmm1 //%xmm1 将浮点数截断为整数。
589b568: cvtdq2pd %xmm1 //%xmm1 转换回浮点数,可能为确保精度。
589b56c: mulsd %xmm1 //%xmm0 将租户因子(%xmm0)与配置值(%xmm1)相乘,得到初步线程数。
589b570: cvttsd2si %xmm0 //%rdx 将乘法结果转换为整数,存入 %rdx。
589b575: test %rdx //%rdx 和 589b578: mov $0x1 //%ecx 确保结果不小于 1。
589b57d: cmovg %rdx //%rcx 如果 %rdx 大于 0,取 %rdx,否则取 1。
589b581: lock decq 0x2f0(%rax) //原子操作,可能减少配置对象的引用计数。
589b589: add $0x2 //%rcx 将结果加 2,可能为确保线程数有冗余。
589b58d: mov %rcx //%rax 将最终结果存入 %rax,准备返回。

再将参数代入公式计算。

代码语言:javascript
复制
min_worker_cnt = 2 + max(1, unit_min_cpu * cpu_quota_concurrency) 
               = 2 + max(1, 8*4)
               = 34

3.2 max_worker_cnt 计算逻辑

查看 OceanBase 社区版代码。

代码语言:javascript
复制
int64_t ObTenant::max_worker_cnt() const
{
  return std::max(tenant_meta_.unit_.config_.memory_size() / 20 / (GCONF.stack_size + (3 << 20) + (512 << 10)),
                  150L);
}
  • 单线程内存开销:stack_size + 3MB + 512KB
  • 租户内存大小除以 20 再除以单线程内存开销与 150 进行比较,取较大者。

OceanBase 企业版反汇编代码(对比查看,确认与社区版的逻辑基本是一致的)。

代码语言:javascript
复制
a815cc6:   48 3d 95 00 00 00       cmp    $0x95,%raxa815ccc:   b9 96 00 00 00          mov    $0x96,%ecx
a815cd1:   48 0f 4e c1             cmovle %rcx,%rax

%rax(动态计算的 max_worker_cnt 值) 与 0x95(149) 进行比较,若 %rax ≤ 0x95(149),则将 %rax 设为 0x96 (150)。

确认 stack_size 的值。

代码语言:javascript
复制
+-------+----------+--------------+----------+------------+-----------+-------+-------------------------------------------------------+----------+---------+---------+------------------+
| zone  | svr_type | svr_ip       | svr_port | name       | data_type | value | info                                                  | section  | scope   | source  | edit_level       |
+-------+----------+--------------+----------+------------+-----------+-------+-------------------------------------------------------+----------+---------+---------+------------------+
| zone1 | observer | 10.186.64.61 |     2882 | stack_size | NULL      | 512K  | the size of routine execution stackRange: [512K, 20M] | OBSERVER | CLUSTER | DEFAULT | STATIC_EFFECTIVE |
| zone3 | observer | 10.186.64.62 |     2882 | stack_size | NULL      | 512K  | the size of routine execution stackRange: [512K, 20M] | OBSERVER | CLUSTER | DEFAULT | STATIC_EFFECTIVE |
| zone2 | observer | 10.186.64.10 |     2882 | stack_size | NULL      | 512K  | the size of routine execution stackRange: [512K, 20M] | OBSERVER | CLUSTER | DEFAULT | STATIC_EFFECTIVE |
+-------+----------+--------------+----------+------------+-----------+-------+-------------------------------------------------------+----------+---------+---------+------------------+
3 rows in set (0.027 sec)

最后将参数代入公式计算(以 MB 为单位计算)。

代码语言:javascript
复制
max_worker_cnt = max(memory_size / 20 / (stack_size + 3MB + 512KB), 150)
               = max(6*1024/20/4, 150)
               = 150

4. 调整参数验证

4.1 min_worker_cnt

4.1.1 预期值

根据源码计算公式:当 unit_min_cpu * cpu_quota_concurrency > 1 时,将此值 + 2,否则等于 3。

我们将 unit_min_cpucpu_quota_concurrency 均调整为 1 ,预期 min_worker_cnt 等于 3。

4.1.2 调整参数

租户 mysql_ob 对执行参数调整并确认生效。

代码语言:javascript
复制
obclient [oceanbase]> alter systemset cpu_quota_concurrency = 1;
Query OK, 0 rows affected (0.698 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      | 1     | 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      | 1     | 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      | 1     | max allowed concurrency for 1 CPU quota. Range: [1,20] | TENANT  | TENANT | DEFAULT | DYNAMIC_EFFECTIVE |
+-------+----------+--------------+----------+-----------------------+-----------+-------+--------------------------------------------------------+---------+--------+---------+-------------------+
3 rows in set (0.015 sec)

obclient [oceanbase]> ALTERRESOURCE unit config_mysql_ob_zone1_u1c6g_qfu MIN_CPU 1, MAX_CPU 8;
Query OK, 0 rows affected (0.019 sec)

obclient [oceanbase]> ALTERRESOURCE unit config_mysql_ob_zone3_u1c6g_uyr MIN_CPU 1, MAX_CPU 8;
Query OK, 0 rows affected (0.031 sec)

obclient [oceanbase]> ALTERRESOURCE unit config_mysql_ob_zone2_u1c6g_lli MIN_CPU 1, MAX_CPU 8;
Query OK, 0 rows affected (0.014 sec)

obclient [oceanbase]> SELECT a.tenant_name, a.tenant_id, b.name unit_config, c.name pool_name, b.min_cpu, b.max_cpu, MEMORY_SIZE/1024/1024/1024as MEMORY_SIZE 
    -> FROM OCEANBASE.DBA_OB_TENANTS a, OCEANBASE.DBA_OB_UNIT_CONFIGS b, OCEANBASE.DBA_OB_RESOURCE_POOLS c 
    -> WHERE a.tenant_id = c.tenant_id 
    -> AND b.unit_config_id = c.unit_config_id 
    -> AND a.tenant_name = 'mysql_ob'
    -> ORDERBY a.tenant_id DESC;
+-------------+-----------+---------------------------------+-------------------------+---------+---------+----------------+
| tenant_name | tenant_id | unit_config                     | pool_name               | min_cpu | max_cpu | MEMORY_SIZE    |
+-------------+-----------+---------------------------------+-------------------------+---------+---------+----------------+
| mysql_ob    |      1008 | config_mysql_ob_zone1_u1c6g_qfu | pool_mysql_ob_zone1_rhp |       1 |       8 | 6.000000000000 |
| mysql_ob    |      1008 | config_mysql_ob_zone3_u1c6g_uyr | pool_mysql_ob_zone3_brf |       1 |       8 | 6.000000000000 |
| mysql_ob    |      1008 | config_mysql_ob_zone2_u1c6g_lli | pool_mysql_ob_zone2_aii |       1 |       8 | 6.000000000000 |
+-------------+-----------+---------------------------------+-------------------------+---------+---------+----------------+
3 rows in set (0.041 sec)
4.1.3 查看调整后的值

可以看到 observer.logmin_worker_cnt 的值已经变成 3 了,符合预期。

代码语言:javascript
复制
[root@10-186-64-61 log]$ grep "dump tenant info" observer.log | grep "tenant_id:1008" | tail -1 | grep min_worker_cnt | awk -F'min_worker_cnt:' '{print "min_worker_cnt:" $2}' | awk -F',' '{print $1}'
min_worker_cnt:3 

4.2 max_worker_cnt

4.2.1 预期值

公式:租户内存大小除以 20 再除以单线程内存开销(stack_size(512KB)+ 3MB + 512KB)与 150 进行比较,取较大者。

代入公式,统一以 MB 为单位进行计算,推算租户的 memory_size 大于多少 GB 时,max_worker_cnt 超出 150 。

  1. 20*4*150/1024=11.7GB
  2. 当租户内存大于 11.7GB 时,max_worker_cntmemory_size / 20 / (stack_size + 3MB + 512KB) 的结果值。
  3. 以租户内存为 12GB 计算,则 max_worker_cnt = 153
4.2.2 调整参数
代码语言:javascript
复制
obclient [oceanbase]> ALTER RESOURCE unit config_mysql_ob_zone1_u8c12g_jzi MEMORY_SIZE '12G';
Query OK, 0 rows affected (0.027 sec)

obclient [oceanbase]> ALTERRESOURCE unit config_mysql_ob_zone2_u8c13g_prk MEMORY_SIZE '12G';
Query OK, 0 rows affected (0.018 sec)

obclient [oceanbase]> ALTERRESOURCE unit config_mysql_ob_zone3_u8c12g_vke MEMORY_SIZE '12G'; 
Query OK, 0 rows affected (0.022 sec)

obclient [oceanbase]> SELECT a.tenant_name, a.tenant_id, b.name unit_config, c.name pool_name, b.min_cpu, b.max_cpu, MEMORY_SIZE/1024/1024/1024as MEMORY_SIZE 
    -> FROM OCEANBASE.DBA_OB_TENANTS a, OCEANBASE.DBA_OB_UNIT_CONFIGS b, OCEANBASE.DBA_OB_RESOURCE_POOLS c 
    -> WHERE a.tenant_id = c.tenant_id 
    -> AND b.unit_config_id = c.unit_config_id 
    -> AND a.tenant_name = 'mysql_ob'
    -> ORDERBY a.tenant_id DESC;
+-------------+-----------+----------------------------------+-------------------------+---------+---------+-----------------+
| tenant_name | tenant_id | unit_config                      | pool_name               | min_cpu | max_cpu | MEMORY_SIZE     |
+-------------+-----------+----------------------------------+-------------------------+---------+---------+-----------------+
| mysql_ob    |      1008 | config_mysql_ob_zone1_u8c12g_jzi | pool_mysql_ob_zone1_rhp |       8 |       8 | 12.000000000000 |
| mysql_ob    |      1008 | config_mysql_ob_zone2_u8c13g_prk | pool_mysql_ob_zone2_aii |       8 |       8 | 12.000000000000 |
| mysql_ob    |      1008 | config_mysql_ob_zone3_u8c12g_vke | pool_mysql_ob_zone3_vke |       8 |       8 | 12.000000000000 |
+-------------+-----------+----------------------------------+-------------------------+---------+---------+-----------------+
3 rows in set (0.065 sec)
4.2.3 查看调整后的值

可以看到 observer.logmax_worker_cnt 的值为 150,而不是 153,不符合预期。

代码语言:javascript
复制
[root@10-186-64-61 log]$ grep "dump tenant info" observer.log | grep "tenant_id:1008" | tail -1 | grep max_worker_cnt | awk -F'max_worker_cnt:' '{print "max_worker_cnt:" $2}' | awk -F',' '{print $1}'
max_worker_cnt:150

查看 observer.log 中的 memory_size 大小。

代码语言:javascript
复制
[root@10-186-64-61 log]$ grep "dump tenant info" observer.log | grep "tenant_id:1008" | tail -1 | grep memory_size | awk -F'memory_size:' '{print "memory_size:" $2}' | awk -F',' '{print $1}'
memory_size:"10.8GB"

可以看到 memory_size 是 10.8GB ,而不是 12GB,原因是什么呢?

  • 系统在创建租户时默认为 Meta 租户预留资源,各项资源从用户租户的资源中扣除。
  • Meta 租户内存分配规则如下: MEMORY 资源:内存资源不支持共享,Meta 租户和用户租户的内存资源需要隔离。默认 Meta 租户占整体租户规格的 10%。为了保证 Meta 租户正常运行,Meta 租户内存资源规格最小为 512M,不设最大值。整体租户内存规格减去 Meta 租户内存规格即为用户租户的内存规格。整体租户规格最小值调整为 1G。下面举例说明:
    • 租户规格大于等于 10G 时,Meta 租户和用户租户内存规格比例为 1:9。
    • 租户规格大于等于 2G 时,Meta 租户的内存规格固定为 1G,剩余资源给用户租户。
    • 租户规格小于 2G 时,Meta 租户固定分配 512M,剩余资源给用户租户。
    • 租户规格最小 1G,Meta 租户占用 512M,用户租户占用 512M。

4.2.4 再次调整参数验证

4.2.4.1 预期值

将租户内存调整为 14GB。

代码语言:javascript
复制
max_worker_cnt = 14 * 0.9 * 1024 / 20 / 4
   =161 
4.2.4.2 再次调整参数
代码语言:javascript
复制
obclient [oceanbase]> ALTER RESOURCE unit config_mysql_ob_zone1_u8c12g_jzi MEMORY_SIZE '14G';
Query OK, 0 rows affected (0.027 sec)

obclient [oceanbase]> ALTERRESOURCE unit config_mysql_ob_zone2_u8c13g_prk MEMORY_SIZE '14G';
Query OK, 0 rows affected (0.018 sec)

obclient [oceanbase]> ALTERRESOURCE unit config_mysql_ob_zone3_u8c12g_vke MEMORY_SIZE '14G'; 
Query OK, 0 rows affected (0.022 sec)

obclient [oceanbase]> SELECT a.tenant_name, a.tenant_id, b.name unit_config, c.name pool_name, b.min_cpu, b.max_cpu, MEMORY_SIZE/1024/1024/1024as MEMORY_SIZE 
    -> FROM OCEANBASE.DBA_OB_TENANTS a, OCEANBASE.DBA_OB_UNIT_CONFIGS b, OCEANBASE.DBA_OB_RESOURCE_POOLS c 
    -> WHERE a.tenant_id = c.tenant_id 
    -> AND b.unit_config_id = c.unit_config_id 
    -> AND a.tenant_name = 'mysql_ob'
    -> ORDERBY a.tenant_id DESC;
+-------------+-----------+----------------------------------+-------------------------+---------+---------+-----------------+
| tenant_name | tenant_id | unit_config                      | pool_name               | min_cpu | max_cpu | MEMORY_SIZE     |
+-------------+-----------+----------------------------------+-------------------------+---------+---------+-----------------+
| mysql_ob    |      1008 | config_mysql_ob_zone1_u8c12g_jzi | pool_mysql_ob_zone1_rhp |       8 |       8 | 14.000000000000 |
| mysql_ob    |      1008 | config_mysql_ob_zone2_u8c13g_prk | pool_mysql_ob_zone2_aii |       8 |       8 | 14.000000000000 |
| mysql_ob    |      1008 | config_mysql_ob_zone3_u8c12g_vke | pool_mysql_ob_zone3_vke |       8 |       8 | 14.000000000000 |
+-------------+-----------+----------------------------------+-------------------------+---------+---------+-----------------+
3 rows in set (0.065 sec)

注意:基于 OCP 新建了租户规格并进行调整,故 unit_config 名称发生变化。

4.2.4.3 再次查看调整后的值

可以看到 observer.logmin_worker_cnt 的值已经变成 161 了,符合预期。

代码语言:javascript
复制
[root@10-186-64-61 log]$ grep "dump tenant info" observer.log | grep "tenant_id:1008" | tail -1 | grep max_worker_cnt | awk -F'max_worker_cnt:' '{print "max_worker_cnt:" $2}' | awk -F',' '{print $1}'
max_worker_cnt:161

5. 结论

OceanBase 数据库 V4 版本对 min_worker_cnt (最小工作线程数)和 max_worker_cnt (最大工作线程数)的下限作了限制,前者最小值是 3 ,后者最小值是 150, 以保障租户有足够的资源正常运行。

参考资料

[1]

租户资源管理: https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000002013998

[2]

OceanBase 社区版源码: https://github.com/oceanbase/oceanbase/tree/develop

本文关键字:#OceanBase #性能参数


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-07-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 爱可生开源社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 背景
  • 2. 前文相关参数一览
    • 2.1 租户配置
    • 2.2 相关参数或变量
  • 3. 源码探究计算逻辑
    • 3.1 min_worker_cnt 计算逻辑
    • 3.2 max_worker_cnt 计算逻辑
  • 4. 调整参数验证
    • 4.1 min_worker_cnt
      • 4.1.1 预期值
      • 4.1.2 调整参数
      • 4.1.3 查看调整后的值
    • 4.2 max_worker_cnt
      • 4.2.1 预期值
      • 4.2.2 调整参数
      • 4.2.3 查看调整后的值
    • 4.2.4 再次调整参数验证
      • 4.2.4.1 预期值
      • 4.2.4.2 再次调整参数
      • 4.2.4.3 再次查看调整后的值
  • 5. 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档