26Y19x3

Young-Kyoo Kim·약 19시간 전

네, 100% 즉시 반영 가능합니다!

제공해 주신 step2_pipeline.py 스크립트는 이미 df_slice.group_by(...).agg(...)df_pod.with_columns(...) 파이프라인 구조를 완벽히 갖추고 있으므로, 해당 지수 연산 수식들을 그대로 이식할 수 있습니다.

다만, 수식에서 참조하는 변수 중 cpu_usage_maxmem_usage_max 두 개가 현재 .agg() 집계 목록에 누락되어 있으므로, 1) .agg() 블록에 2개 컬럼을 추가하고 2) df_pod.with_columns() 연산부에 수식을 결합해 주시면 됩니다.


🛠️ step2_pipeline.py 반영 코드

1단계: .agg() 집계 블록에 Max 컬럼 2개 추가

cpu_usage_max(CPU 순간 피크)와 mem_usage_max(메모리 순간 피크)를 추가 수집합니다.

# [테이블 1] 상세 메트릭 원부 집계
df_pod = df_slice.group_by([
    "date", "cluster_type", "workload_domain", "namespace", "workload_type", "node", "pod", "container"
]).agg([
    pl.len().alias("minutes_running"),
    pl.col("cpu_request").max().alias("cpu_request_max"),
    pl.col("cpu_limit").max().alias("cpu_limit_max"),
    pl.col("cpu_usage").max().alias("cpu_usage_max"),              # 💡 [신규 추가] Burstiness 계산용
    pl.col("cpu_usage").quantile(0.95).alias("cpu_usage_p95"),
    pl.col("cpu_throttled").max().alias("cpu_throttled_max"),
    (pl.col("mem_request").max() / GB_DIV).alias("mem_request_max"),
    (pl.col("mem_limit").max() / GB_DIV).alias("mem_limit_max"),
    (pl.col("mem_usage").max() / GB_DIV).alias("mem_usage_max"),    # 💡 [신규 추가] OOM Proximity 계산용
    (pl.col("mem_usage").quantile(0.95) / GB_DIV).alias("mem_usage_p95"),
    (pl.col("mem_rss").quantile(0.95) / GB_DIV).alias("mem_rss_p95"),
    pl.col("oom_event").sum().alias("oom_strike_sum"),
    (pl.col("pv_capacity").max() / GB_DIV).alias("pv_capacity_max"),
    (pl.col("pv_usage_p95") / GB_DIV).alias("pv_usage_p95")
]).fill_null(0.0)

2단계: df_pod.with_columns() 블록에 행동 계수(Behavioral Coefficients) 통합

기존 FinOps 사칙연산 수식 바로 아래에 행동 계수 지수 5종을 병렬 배치합니다.

# FinOps 사칙연산 수식 결착 및 행동 계수 지수 반영
df_pod = df_pod.with_columns([
    (pl.col("cpu_request_max") * (pl.col("minutes_running") / 60.0)).alias("cpu_allocated_core_hours"),
    (pl.col("cpu_usage_p95") * (pl.col("minutes_running") / 60.0)).alias("cpu_usage_core_hours"),
    (pl.col("mem_request_max") * (pl.col("minutes_running") / 60.0)).alias("mem_allocated_gb_hours"),
    (pl.col("mem_usage_p95") * (pl.col("minutes_running") / 60.0)).alias("mem_usage_gb_hours"),
    (pl.col("pv_capacity_max") * (pl.col("minutes_running") / 60.0)).alias("pv_allocated_gb_hours"),
    (pl.col("pv_usage_p95") * (pl.col("minutes_running") / 60.0)).alias("pv_usage_gb_hours"),
    (pl.col("oom_strike_sum") > 0).alias("is_oom_killed"),
    (pl.col("cpu_request_max") == 0).alias("has_no_request"),
    (pl.col("cpu_limit_max") == 0).alias("has_no_limit"),
    ((pl.col("cpu_usage_p95") - pl.col("cpu_request_max")).clip(lower_bound=0)).alias("cpu_shortage_cores"),

    # ─────────────────────────────────────────────────────────────────
    # 💡 [신규 추가] Polars 고속 행동 계수(Behavioral Coefficients) 5종
    # ─────────────────────────────────────────────────────────────────
    # 1. CPU Burstiness 지수
    (pl.col("cpu_usage_max") / pl.col("cpu_usage_p95").clip(lower_bound=0.001))
    .round(2).alias("feat_cpu_burstiness_ratio"),
    
    # 2. CPU 스로틀링 밀도
    (pl.col("cpu_throttled_max") / pl.col("cpu_usage_p95").clip(lower_bound=0.001))
    .round(2).alias("feat_cpu_throttle_density"),
    
    # 3. Memory OOM 위험 근접도
    (pl.col("mem_usage_max") / pl.col("mem_limit_max").clip(lower_bound=0.001))
    .round(2).alias("feat_mem_oom_proximity"),
    
    # 4. Memory 자원 매몰(Slack) 계수
    ((pl.col("mem_request_max") - pl.col("mem_usage_p95")) / pl.col("mem_request_max").clip(lower_bound=0.001))
    .round(2).alias("feat_mem_slack_ratio"),
    
    # 5. 컴퓨트 vs 메모리 바운드 성향 프로필 지수
    (
        (pl.col("cpu_usage_p95") / pl.col("cpu_request_max").clip(lower_bound=0.001)) /
        (pl.col("mem_usage_p95") / pl.col("mem_request_max").clip(lower_bound=0.001)).clip(lower_bound=0.001)
    )
    .round(2).alias("feat_resource_bound_ratio")
]).with_columns([
    ((pl.col("cpu_allocated_core_hours") - pl.col("cpu_usage_core_hours")).clip(lower_bound=0)).alias("cpu_waste_core_hours"),
    ((pl.col("mem_allocated_gb_hours") - pl.col("mem_usage_gb_hours")).clip(lower_bound=0)).alias("mem_waste_gb_hours"),
    ((pl.col("pv_allocated_gb_hours") - pl.col("pv_usage_gb_hours")).clip(lower_bound=0)).alias("pv_waste_gb_hours"),
])

🔍 이식 시 호환성 및 안정성 검증 결과

  1. 단위 표준화 완비: mem_usage_max, mem_limit_max, mem_request_max 모두 .agg() 단계에서 GB_DIV로 나뉘어 GB 단위로 통일된 상태에서 비율 연산이 수행되므로 단위 불일치가 없습니다.
  2. Division by Zero 방어: 모든 분모 항목에 .clip(lower_bound=0.001) 가드레일이 씌워져 있어 Limit/Request가 0이거나 미설정된 Pod에서도 NaN 또는 Inf 에러 없이 안전하게 정산 파일(daily_enriched_*.parquet)로 추출됩니다.

0개의 댓글