Closed
Description
现有的 cpu 配额和绑定的 runtime 实现是:
- cpu-bind=true: 使用
cpuset.cpus
+cpu.cfs_quota_us
. 比方说请求 cpu=1.2, bind={1,2}, 落实到 OS 层面就cpuset.cpus=1,2
,cpu.cfs_quota_us=120000
; - cpu-bind=false: 使用
cpu.cfs_quota_us
. 比方请求 cpu=1.2, 落实到 OS 层面就是cpu.cfs_quota_us=120000
这造成了几个问题:
cpuset.cpus
+cpu.cfs_quota_us
的方案对性能影响非常大. 我做的简单测试, 三进程用这种方案分别绑定 1.2, 1.3, 1.5 cpu, 理论上希望能跑出 4 个 100% 的 cpu, 然而结果是 4 个 cpu 利用率波动在 85%~97%, 而且 cpu throttle 非常频繁.- cpu unbind 的进程没有限制 cpuset.cpus, 可能会影响绑核的进程. Kubernetes 的做法是做一个动态的 share cpu pool, 比如初始时是
0-7
, 后来若有进程绑定了 cpu 2, 那么 share pool 变成0-1,3-7
, 并更新到已有的非绑定容器上. - shopee SRE 的需求, 希望 redis 进程能被分配两个 cpu, 一个专属一个共享, 平时 redis 只用专属, bgsave 的时候才使用共享; 同一个 host 上的所有 redis 进程们可以共享同一个 cpu.
因此新的方案是:
- 照抄 Kubernetes 的 share pool 方案, 动态把已绑定的 cpu 从里面摘除.
- cpu-bind=false 时,
cpuset.cpus
指定 share pool, 同时设置cpu.cfs_quota_us
; share pool 更新的时候需要对已有进程的cpuset.cpus
更新一遍 - cpu-bind=true 时,
cpuset.cpus
正常设置, 不再限制cpu.cfs_quota_us
, 而是根据碎片核的占比设置cpu.shares
比如以下是连续请求:
- 请求 cpu=1, bind=false, 最终
cpuset.cpus=0-7
,cpu.cfs_quota_us=100000
- 请求 cpu=1, bind=true, 最终
cpuset.cpus=0
,cpu.shares=1024
(1024 是默认 share, 相当于没有修改); 之后请求1创建的进程的cpuset.cpus
被调整为1-7
. - 请求 cpu=1.2, bind=true, 最终
cpuset.cpus=1,3
,cpu.shares=20
; 之后请求 1 创建的进程cpuset.cpus
再次被调整为2,4-7
. - 请求 cpu=1.2, bind=false, 最终
cpuset.cpus=2,4-7
,cpu.cfs_quota_us=120000
那么对于 Shopee SRE 的需求, 可以在 redis-zero 保证:
- 用户在 web 请求 cpu=1, bind=true
- redis-zero 发送给 eru-core 的请求里修改为 cpu=1.01, bind=true
- redis 容器被绑上两核, 一个完整核一个碎片核, 对应需求“一个专属核一个共享核”
Metadata
Metadata
Assignees
Labels
No labels