resource_hard_limit=150后,增大max_cpu并进行高负载,租户cpu使用率仍然受到min_cpu的限制

【 使用环境 】生产环境 or 测试环境
【 OB or 其他组件 】
【 使用版本 】
【问题描述】
oceanbase单机体验版4.2.1
节点cpu count = 18, resource_hard_limit=150,sys_cpu = 3, tenant1_max_cpu=12, tenant2_max_cpu=12
执行同样的负载(负载很高确保可以把资源打满)时,租户1 min_cpu = 7.5时,cpu使用率(相比max_cpu)有46%,租户1 min_cpu = 1时,cpu使用率(相比max_cpu)只有8%,这样看超卖机制似乎并没有生效,租户被分配的cpu仍然只收到min_cpu的限制,请问是为什么呢?




有个知识点科普一下

min_cpu/max_cpu

这里并不是指绑定物理核,而是通过cgroup限制cpu的使用率。
min_cpu是提供给租户cpu的最低保证。在创建租户时,会检查所有租户min_cpu之和不能超过cpu_count,后者是配置项,缺省为机器物理cpu数。当所有租户负载占满机器物理cpu时,能保证租户之间不互相挤占。
max_cpu是给租户的最大cpu使用率。创建租户时,会检查所有租户max_cpu之和不能超过cpu_count * resource_hard_limit, 后者是配置项,单位为百分数,缺省值是100%。当机器cpu资源宽裕时,能提供给每个租户一定比例的超卖。

举例

8c机器
cpu_count = 8, resource_hard_limit = 150%
租户a:min_cpu = 3, max_cpu = 5
租户b:min_cpu = 3, max_cpu = 4
租户c:min_cpu = 2, max_cpu = 3
3个租户满载时,租户a,租户b能用3个cpu,租户c能用2个cpu。
租户a满载,租户b、c空闲时,租户a能用5个cpu。

不好意思,我还是有点没理解,我查过cpu_count是15,执行两次负载时都是一个租户满载,一个租户空闲的状态,可是第一次设置min_cpu为7.5后,满载的租户被分配的cpu是不超过7.5的,第二次设置min_cpu为1后,满载的租户被分配的cpu是不超过1的,而且两次都是相同的高负载,请问这样的情况下,两次执行负载租户不应该被分配超过min_cpu的cpu数吗?为什么主机CPU会被打满无富裕呢?

压测的时候实际的cpu使用有从机器上看吗,看表述是相对于max_cpu的百分比?

是从grafana上看到的变化,压测的时候是实时变化的,cpu使用率=当前被分配的线程数/最大可被分配的线程数,分母是根据man_cpu定的(已查看过具体数值,随max_cpu变化)。

min_cpu/max_cpu

并不决定租户物理cpu的使用率,而是反映到租户工作线程数上。工作线程是指处理sql/rpc的线程。

一方面,租户运行时要维持恒定量的活跃工作线程,这个数量是min_cpu * cpu_quota_concurrency,后者是一个配置项。

另一方面,租户层有时会挂起一些处理慢查询的线程,同时要分配新的线程以维持活跃线程数恒定,这时用max_cpu * workers_per_cpu_quota限制租户总共持有的线程数上限。

别纠结于grafana上的图,直接从机器上看看是不是cpu打满了。

当负载很高把机器cpu打满时,租户之间cpu比例按照min cpu分配


谢谢!那请问在什么情况下可以出现您说的这个租户a用5个cpu的情况呢?如果负载不够高就没办法分配到更多的cpu,如果负载太高又把cpu打满的话?

看得出来楼主很纠结这个 资源隔离 和 超卖 的概念,下面是个人观点仅供参考。

1. 资源隔离 首先不是个技术问题,而是需求问题。

你想要的资源隔离效果是什么?

数据库的资源隔离国内最早是在云数据库 RDS MySQL 里用到,使用的是 Linux 的 cgroup 资源隔离技术。云厂商单机起多个 MySQL 实例,然后将前端实例里的资源配置跟主机上的 cgroup 联动配置实现这种效果。
当这种云数据库型态出现后,作为云数据库的用户,有些人会非常在意自己的实例的资源是否得到足额保证 或者被“侵占”(因为花钱了)。也尝试用各种方法压测数据库去证明自己的“怀疑”。现在的云数据库资源隔离技术虽然有了一些变化,最底层的技术依然是 cgroup 。如今由于云的普及,应该没有哪个客户会去纠结这个“资源隔离”的公平性。毕竟用户选择多了。可以选择不买,或者买别的家的。不过大家技术都差不多,资源隔离效果也差不多。

资源隔离的需求是容易存在一些矛盾。比如说两个租户共享 8个 CPU,配额是每个租户 4个。当有 A 租户空闲,另外 B 租户繁忙的时候,到底允不允许 B 租户多用 4个 CPU(先不管具体怎么衡量这个值,就说协议上的)。如果给 A B 发问卷,A 的答案可能是不在意或者反对,B的答案可能是赞成或者不在意。 不过风水轮流转。也有的时间段 A 繁忙 B 空闲。A 和 B 的选择无论是什么最终还是会影响彼此。作为云厂商(提供资源隔离的一方)如果目标是最大化利用服务器资源,答案是赞成;如果要考虑所有客户的利益以及反馈,可能就采取“采取严格限制”(先不说技术上能不能做到)。这个选择的结果究竟是不是最好的,看占谁的立场定,不好说。

OB 数据库跟其他分布式数据库不一样的地方就是有多租户能力。所以借助 OB 在企业内部可以实现类似云数据库一样的体验。区别只是自己给自己分配租户不用花钱。作为 DBA 是希望严格限制每个租户的资源利用率 还是想最大化 服务器资源利用率。也看租户实例代表的业务方。如果企业内部业务方很多,DBA HOLD 不住业务方,那可能也会走向云厂商那个选择。不过如果倒这个地步,不如部署两套 OB 集群,将不可调和的两个业务租户分配到不通的 OB 集群。物理隔离,彻底消停 。 :slight_smile:

OB 的租户隔离 CPU 提出 min_cpu 和 max_cpu 两个设置(4.0 版本之前内存也是两个参数),其本意就是 如果 A 租户和 B 租户都繁忙,那么最基本的 CPU 都保障到,每个租户有 4个 CPU。如果有一方不繁忙,那么允许另外一个租户能用到 8个 CPU(依然先不论技术细节)。OB 把这个称为“超卖”。这个好意只是在有一方租户空闲的时候才能发挥。如果大家都忙,这个好意就实现不了。

就是这个“超卖” 设计让使用的人总是有些困惑。
我个人的喜好是所有租户规格 min_cpu 跟 max_cpu 都拉平,也不超卖。

2. 资源隔离技术方案

云厂商数据库资源隔离底层使用的是 cgroup 技术,CPU 隔离效果就看 cgroup 效果。cgroup 对 CPU 隔离方案有两个。一是物理核绑定,这个用的少;另外一个就是 时间片分时控制,大部分都是用这个方案。具体又分为两种,可以网上查询,介绍原理的很多。cgroup 出现的历史更早,我猜测早期也会有人去测试 cgroup 对进程或线程 的 cpu 隔离效果好不好。

OB 是单进程软件,OB 的租户资源隔离 在 4.0 以前是内部调度的,在4.0以后默认通过 cgroup 调度。租户的 CPU个数对应内部的线程数(1个 CPU 对应 N个工作线程,N是参数workers_per_cpu_quota 定义,默认值是 10,不建议修改)。

OB 服务器上不建议跑其他耗资源的应用,独占服务器是最好的。OB 的进程基本上能获得主机 CPU 的大部分资源(跟 cpu_count 多少无关)。这个服务器上就 observer 能够最忙,CPU 利用率自然大部分都是它的(但不可能到100%,甚至 99%。毕竟 OS 也是公平的,其他进程的工作也要照顾到)。一个进程如果想占用99% 的CPU时间,也是可以的。写个死循环的程序,耗死 CPU 。但是 observer 进程是个数据库系统,其内部是多线程架构,很复杂。不可能表现的像 死循环的程序那么单纯 或者说是 LOW。 一个 observer 进程是很难将主机 CPU USR 利用率干到 100% (IOWAIT 那个不算) (也可能有人有些业务场景能碰到,很少见)。

4.0 以前 ,OB 的进程在内部给各个租户分配 CPU,原理就是分配线程数。工作线程就是打工的。一个拥有 40 个打工线程的租户 跟一个拥有 80 个打工线程的租户 其最大化的工作能力肯定是有差距的。空闲的时候,一个租户繁忙的时候可以占一点便宜,但是当两个租户都繁忙的时候,二者的工作能力设计目标近似是 1:2 的关系才合理。
4.0 以后, OB 将这个租户之间的CPU 隔离交给了 cgroup 去做,将租户的所有子线程写入到cgroup 对用的配置文件(tasks)中(cgroup 机制,如果一个线程在 tasks里,其子线程会自动进入)。参考: 开启基于 cgroups 的租户工作线程的 CPU 隔离-OceanBase 数据库 -OceanBase文档中心-分布式数据库使用文档

当 OB 使用 cgroup 去做资源隔离的时候,CPU 隔离效果就跟 cgroup 的能力相关了。OS 层面统计多个线程CPU利用率比较困难,可以通过 cgroup 输出的 stats 去统计这个租户的线程组在主机层面的 CPU 利用率。另外衡量这个就靠 OB 自身的租户 CPU 利用率指标数据。所以个人建议不用花太多精力去测试 OB 租户的 CPU 隔离是否精确。这个测试难点就是如何真正将租户的CPU 利用率最大化(这不像写个死循环那么简单)。原厂会做这个测试。推测是用 sysbench(模型简单,并发可控)。用户不用测试这个(除非用户也是用OB提供云服务),因为依赖的是 cgroup 。除非 OB 自身在这块没做好。即使有没做好,这个功能也是4.0 才推出,成熟也需要时间。

OB 在 cgroup 对各个租户 CPU 隔离限制比例方法之一是根据 租户的 max_cpu 设置 cgroup 的 cpu.cfs_period_us 和 cpu.cfs_quota_us 。这种隔离效果也是 限高。

[root@server063 oceanbase]# grep 0 tenant_*/cpu.cfs_*_us
tenant_0001/cpu.cfs_period_us:100000
tenant_0508/cpu.cfs_period_us:100000
tenant_0508/cpu.cfs_quota_us:500000
tenant_0509/cpu.cfs_period_us:100000
tenant_0509/cpu.cfs_quota_us:250000
tenant_1002/cpu.cfs_period_us:100000
tenant_1002/cpu.cfs_quota_us:800000
tenant_1004/cpu.cfs_period_us:100000
tenant_1004/cpu.cfs_quota_us:900000
[root@server063 oceanbase]# pwd
/sys/fs/cgroup/cpu/oceanbase

此外 租户间 min_cpu 对应的是工作线程数,多租户同时满负荷时彼此之间的最大工作能力的差异体现在彼此的 min_cpu 上,具体是通过 cgroup 的 cpu.shares 这个控制CPU 利用率相对比例 的参数实现。所以 这种隔离效果是 保底。

[root@server063 oceanbase]# grep [0-9] tenant_*/cpu.shares                                                                                                                                                                                                                
tenant_0001/cpu.shares:4096
tenant_0508/cpu.shares:5120
tenant_0509/cpu.shares:2560
tenant_1002/cpu.shares:1024
tenant_1004/cpu.shares:2048

从上面输出也看出,对于 sys 租户 OB 并没有用 cgroup 去做 限高 限制,但有保底设置。 sys 租户是 OB 集群的核心,限制 sys 租户的 CPU 利用率 对集群毫无益处(无异于掐自己喉咙)。当然 sys租户如果有 bug 自然是无法接受的,那个另当别论。 也不用担心 sys 租户会过分的消耗资源。毕竟 sys 租户默认的 max_cpu=5 (不同版本可能会有点区别),就这么点 CPU(对应50个线程),也翻不起大浪(sys租户本身也没有非常耗时的 sql 和请求。) sys租户性能最大的威胁是 OCP 以及第三方类似 OCP 这样的监控平台。如果引入了第三方监控平台增加了 sys租户的访问压力,建议调大 sys 租户的 min_cpu 。

3. OB 的超卖问题

resource_hard_limit 提出的超卖总是能打动一些人,其风险也是有的。CPU 由于底层是共享的,即使上了 cgroup,线程之间也是竞争关系(cgroup 只是给某些线程上了加锁)。但是 内存资源的分配是实打实的。
在 4.0 之前的版本里,如果调大 resource_hard_limit ,并且当所有租户的 max_memory 之和比实际物理内存要大的时候,在租户读写数据真实需要内存的时候,OB 找 OS 申请内存就会分配不出来 兑现不了资源承诺,OB 集群会各种异常。 所以这么做好处不大问题却多,4.0 版本之后终于将 memory 统一为一个参数 memory_size 了。
对于 4.0之前的版本,个人建议 将 max_memory 跟 min_memory 拉平,这样手动计算剩余内存资源的时候更精确。问题简化处理。

4.0 后的版本 resource_hard_limit 生产环境估计建议就默认值 100% 。也可以关闭 enable_cgroup 让 OB 自己调度(需要原厂确认)。个人觉得 cgroup 的 CPU 隔离控制力度很可能比 OB 自己的 CPU 隔离更绝对一些。选择哪种看需求定(其实就是看自己立场在哪)。新上线的 OB 服务器 CPU 很多,租户很少用的 CPU 个数很低的时候,用 cgroup 机制容易导致服务器 CPU 利用率很低。

4. CPU_COUNT

有一种调大 resource_hard_limit 的原因可能是 测试环境 ,服务器都是虚拟机提供的,CPU 个数不多。
如果是这种场景,建议调大 CPU_COUNT ,而不是 调大 resource_hard_limit 。因为测试环境是生产环境之前的一道屏障,尽可能配置保持一致。如果有什么bug 也许可以在测试环境复现。而 OB进程拿到的资源(名义上的 cpu_count)只要足够不影响其运行即可。
调大 CPU_COUNT 效果举例就是 虚拟机 CPU 是8个 ,OB 可以声称自己拿到 16个(cpu_count=16),然后在内部租户间分配。这个效果类似于 金本位下的货币超发,无非就是 OB 分配给租户的一个 CPU 能力贬值了。这个做法同样能解决测试环境 CPU 资源不足问题。


个人观点,如有不当,欢迎指出。

1 个赞

十分感谢您的回复!