Skip to content

gc tuner

基本总结和目标

目标:为公司内部cpu quota较大的服务节省CPU使用量。

统计口径:在12.12 campaign开始后的1h。

服务数量:67 实例总数量116k:,gc tuner影响数目:49k, 覆盖率42%。未完全覆盖原因:为了完成精确的收益计算,去除系统级别的噪音。42%是因为组件内部的runtime toggle依赖容器部署设置的参数来做分片。

总配置CPU quota:682K Core 总配置内存量:1.11PB

Memory和CPU

内存和CPU分布图(TODO: 由于baseline缺乏metrics所以暂时只有deviation版本的图):

baseline和feature

alt text

alt text

GC调优通过提高实例内存利用率,更少的触发GC,通过减少GC cpu使用率降低app CPU使用率。 在GC调优中,绝大部分容器内存使用符合预期,保持稳定。

feature的内存变化状况

All images are put in ID region.

  • campaign前

alt text

  • campaign中

FEATURE的变化图campaign期间内存牢牢的锁定在预设的界限处,整套方案的稳定性较高。

alt text

  • campaign后

alt text

alt text alt text

  • 整体的内存变化图

alt text

alt text

alt text

alt text

alt text

feature的内存变化总体状况

alt text

alt text

alt text

STW和App Latency

  • TODO: 省了多少cpu,省了多少钱。 这个写出来的时候要重点强调如何把GC和json优化的cpu节省给分开,并且能够解释json对gc的影响是什么样的。
  • TODO: P99变化 无事故,且基于我们SOP修改业务端修改告警后,无任何告警,平稳完成campaign。

服务选择

目前有6700+服务(286k instances)在我们框架上,我在可行性分析阶段对所有适用服务进行分析,基于以下标准进行服务选择:

  • 较大CPU quota和充裕的内存,忽略70+%内存使用不适用于gc tuner的服务
  • 选择top 100服务,确保rollout进度不会因为大规模数量拖累,同时可以按时在p0级别的campaign中计算收益。

通过选取满足以上条件的服务,我们在尽可能覆盖大比例cpu和rollout工作量中找到了平衡。

如何观察

gc tuner的影响数目通过我们的动态开关打开,完成特定比例线上业务的服务打开gc tuner开关,通过gc tuner暴露的metrics了解受影响的 instances。gc tuner由动态开关分发的配置作为输入,检查当前live heap,memory usage来决定是否要调,有一个专门的gc_tuner_status来标识目前gc tuner的状态。 除此之外,会使用go runtime metrics附加检查gogc值和target heap是否符合预期。 安全保护我们额外暴露了容器内的rss,主要目的是因为集群暴露的ip是容器级别的,和我们业务暴露metrics里记录的是instance级别的ip,方便查询。gc tuner自适应所以除了手动变更config关闭之外其他安全保护全部都是gc tuner自动完成并变更metrics的。

top5 CPU qupta service.

ID Memory CPU Cores Instance Count
product_price.business 99.1 TiB 50.7 K 6.36 K
bass.promotion_bass_item 96.8 TiB 49.5 K 6.22 K
price_bound.corecritical 93.2 TiB 47.7 K 5.97 K
listing_aggregation.bassiteminfo 74.4 TiB 39.1 K 4.91 K
mp_usage.api 71.6 TiB 36.5 K 9.18 K

核心需求是降低CPU使用量.

数据采集

  • TODO: 容器cpu使用量如何拿到的,需要复习
  • TODO: cpu trottling? 我们没这个东西
  • P99 + 错误率 + OOM/重启次数

Latency Collecting

查询:拉 10min 窗口内的 p50/p95/p99 时间序列点

对每个服务、每个指标(API latency、STW)、每个分位(50/95/99),拉回 10min 的点序列 x(t)(15s 间隔大约 40 个点)。

窗口内加工:对每条点序列提取“窗口特征”

主代表值:

repr = median(x(t)) (推荐默认主口径)

窗口内偏坏水平(你说的 p95-of-time):

hi = quantile(x(t), 0.95)

含义:这 10min 里 最差的 5% 时间 大概有多差(比 max 稳得多)。

稳定性/抖动(非常有用,帮你识别“p99 长尾抖动”):

instability = hi / repr (或 hi - repr 也行)

baseline vs feature:开始做比较

3.1 对每个服务、每个分位(p50/p95/p99)计算:

绝对变化:Δ = after_repr - before_repr

相对变化:r = (after_repr - before_repr) / before_repr(before 太小用 eps 截断)

然后定义 变差条件(deadband,避免噪声):

变差 = (r > r0) AND (Δ > Δ0)

或更宽松:变差 = (r > r0) OR (Δ > Δ0)

阈值怎么来?先给一个可用默认值(你后续可从数据反推校准):

p50:r0=3%,Δ0=0.2ms

p95:r0=5%,Δ0=1ms

p99:r0=8~10%,Δ0=2ms(按你们量级调)

3.1 用ln(after/before)(log ratio)来跨服务理解?

不同服务基线差异巨大(p99 可能从 5ms 到 500ms),直接平均相对变化 r 往往会被极端值拖偏,而且“+100%/-50%”不对称。

ℓ=ln( before/ after )

3.2 分解与稳健化p99 长尾效应

输出“尾巴是否更重”的形态指标,对每个服务算:

tail_ratio = repr_p99 / repr_p50(或 repr_p99 / repr_p95)

执行步骤:

查询,获得原始的[p50], [p95], [p99]数据

加工:median函数和hi95函

进行比较即可