Skip to content

aggregate: 修复聚合缓存隐患并降低内存/CPU 消耗 #186

@songlonqi-java

Description

@songlonqi-java

背景

Dataway 的 /v1/aggregate 功能主要依赖 cliutils aggregate 包。梳理 dataway 接入路径后,cliutils 侧有几处需要优先处理的可靠性和资源消耗问题。

隐患 / Bug

  1. Cache.GetExpWidows() 删除过期 bucket 后,外部会通过 WindowsToData() 无锁遍历 window.cache;同时 GetAndSetBucket() 在释放 Cache.lock 后仍可能拿着旧 *WindowsAddCal()。时间边界上存在旧 bucket 被继续写入、同时被遍历的风险,可能产生 data race 或 concurrent map iteration and map write

  2. WindowsToData() 在某个 window 的所有 calculator Aggr() 都失败时,仍会返回一个 PTS 为空的 PointsData。调用方如果默认非空,容易触发空 batch 下标 panic。stdev 单样本返回错误是一个可复现触发点。

  3. newCalculators() 默认 AggregationBatchbatch.PointsAggregationAlgo 都非 nil。外部收到字段缺失但 protobuf 合法的 payload 时,当前路径容易 nil deref。建议在 cliutils 内部做防御式校验,避免把结构合法性完全交给调用方。

  4. Window 通过 sync.Pool 获取,但过期窗口没有统一 reset/put 的释放路径,pool 当前基本没有复用价值;同时窗口内 map 可能长期保留高水位容量。

内存 / CPU 优化点

  1. quantiles 当前保存全量样本并在每个 percentile 计算时排序,窗口大时内存 O(n),CPU 至少 O(n log n),多个 percentile 还会重复排序。建议改成一次排序后复用,或引入近似分位算法/可配置上限。

  2. stdev 当前保存全量样本,实际可以用 Welford/在线方差算法维护 count、mean、M2,将内存降到 O(1)。

  3. count_distinct 当前使用无界 map[any]struct{},高基数字段下内存不可控。建议提供最大 distinct 数保护,或引入近似 distinct 方案。

  4. Window.Reset() 只清 map,不重置 calculator;如果后续要归还 pool,需要明确 calculator 生命周期,避免保留大 slice/map。

建议优先级

P0:修复过期窗口并发风险、空 PointsData 输出、nil payload 防御。

P1:补齐窗口对象释放/复用策略。

P2:优化 stdevquantilescount_distinct 的内存模型和 CPU 成本。

关联

dataway 侧对应 issue:https://gitlab.jiagouyun.com/cloudcare-tools/dataway/-/issues/71

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions