Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions asap-tools/experiments/datasets/alibaba/ALIBABA_MAPPING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Alibaba trace → random query workloads (handoff)

**Goal:** realistic, strong end-to-end results on Alibaba data for the eval section.

The motivation section (Prometheus, PromSketch, PilotDB; cost vs accuracy) should ideally use the same data, label mapping and similar queries, so the two line up. They don't need to match exactly.

## Data the end-to-end runs feed

**Source:** Alibaba cluster-trace-microservices-v2022, MSMetrics, pod `cpu_utilization` (0–1).
- Columns: `timestamp, msname, msinstanceid, nodeid, cpu_utilization, memory_utilization`.
- 60 s step, about 470k pods per step, 28k distinct msname.
- Only about the first hour is local: `benchmarks/metrics_observability/data/alibaba-cluster-data/cluster-trace-microservices-v2022/0d0_0d1/data/MSMetrics/`.
- That is `MSMetricsUpdate_0.csv` plus `MSMetrics_1.tar.gz`.
- Rows are **not** sorted by time.

**Subset:** fit to our synthetic label shape, so the existing workloads, plans and configs apply unchanged.
- 4 region × 5 service × 10 job × 50 label_0 = 10,000 series.
- `job` = one microservice (msname).
- Seed 862 draws them from the 1,785 msnames with ≥50 pods reporting at all 60 steps.
- `label_0` = one of its pods (msinstanceid; the first 50 by pod number).
- `region` and `service` are synthetic groupings of microservices.
- The trace has neither level.
- `nodeid` cuts across msname, so it doesn't nest.
- Label values: region `r`, service `r.s`, job `r.s.j`, label_0 `r.s.j.k`.

**Values:** real pod CPU.

| Statistic | Value |
|---|---|
| min | 0.003 |
| median | 0.12 |
| p95 | 0.40 |
| p99 | 0.58 |
| max | 0.997 |

- No zeros.
- The busiest microservice is about 5× the median one.
- The top 10 of 200 microservices hold 15% of total CPU.
- Region totals are 20–26k.

**Time mapping:** a quick-result compromise.
- Replayed at 10 samples/s per series, the same as the synthetic base set.
- One trace minute becomes one 100 ms sample, so the 60-step hour loops every 6 s.
- Spread and skew across pods and services are real; each series' pattern over time repeats.
- A realistic run needs more trace (`fetchData.sh`) and a smaller speedup.

**Files** (generated, not tracked):
- `replay.csv`: `offset_ms,region,service,job,label_0,value`; 600k rows, sorted by offset.
- `replay_mapping.csv`: our labels → msname/msinstanceid.
- `replay_table.json`: a paced-feeder workload table with `values.replay`.
- Generator: `asap-tools/experiments/datasets/alibaba/make_replay.py`.

## Query workloads

Seed 862, 10 random workloads; manifests are in `asap-tools/experiments/datasets/fake_metric/random_workloads/seed-862/`.

Each end-to-end run uses a workload's 7 `common-promql` queries:
- **Metric and groupings:** metric `data`, grouped by `(region)`, `(region, service)` or `(region, service, job)`.
- **Sums (2):** `sum by (G) (sum_over_time(data[W]))`.

| Window W | Repeated every |
|---|---|
| 1m | 1–2 s |
| 5m | 5–10 s |
| 10m | 10–20 s |
| 20m | 30–60 s |

- **Quantiles (3):** 100 s lookback, repeated every 1 s.
- PromQL can't express a pooled quantile, so it uses `avg by (G) (quantile_over_time(phi, data[100s]))`.
- Every system, ClickHouse and LiteOlly included, currently computes this same `avg` of per-series quantiles, so all answers agree.
- The intended pooled `quantile by (G)` over 100 s is being added (LiteOlly support merged in #887–890).
- **Top-k (2):** `topk(k, …)` over counts, with K capped at 1,000 keys.

On Alibaba data these read naturally: "a quantile of pod CPU per microservice or region over the last 100 s", and "total CPU per service over 5–20 min".

## End-to-end status (2026-10-15)

- **Synthetic base:** 5 systems × 10 workloads, all valid.
- LiteOlly vs worst baseline: 6.2× less CPU than raw ClickHouse, and 11.6× lower p95 than Prometheus.
- **Alibaba:** pilot w01 × 5 systems is finishing. The full 10 workloads follow if it is valid.
26 changes: 19 additions & 7 deletions asap-tools/experiments/datasets/alibaba/make_replay.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
"""A replay table for paced-feeder from Alibaba v2022 MSMetrics: pod CPU
utilization in the random workloads' label shape (4 region x 5 service x 10
"""A replay table for paced-feeder from Alibaba v2022 per-pod metrics (MSMetrics
CPU by default, or an MSRTMCR call rate with --column) in the random workloads'
label shape (4 region x 5 service x 10
job x 50 label_0), so their plans apply unchanged.

Each job is one microservice and each label_0 one of its pods; region and
Expand All @@ -17,29 +18,40 @@

Usage: python3 make_replay.py MSMetricsUpdate_0.csv MSMetricsUpdate_1.csv \
--out replay [--table eval_table.json]
python3 make_replay.py MSRTMCR_*.tar.gz --column providerrpc_mcr --out calls
"""

import argparse
import csv
import io
import json
import random
import tarfile
from collections import defaultdict

REGIONS, SERVICES, JOBS, PODS = 4, 5, 10, 50


def rows(paths):
"""The CSV rows of `paths`: plain CSVs, or tarballs of them."""
for path in paths:
with open(path, newline="") as f:
for r in csv.DictReader(f):
yield r
if path.endswith(".tar.gz"):
with tarfile.open(path) as tar:
for member in tar:
if member.isfile():
text = io.TextIOWrapper(tar.extractfile(member), newline="")
yield from csv.DictReader(text)
else:
with open(path, newline="") as f:
yield from csv.DictReader(f)


def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("csv", nargs="+")
parser.add_argument("--out", required=True)
parser.add_argument("--seed", type=int, default=862)
parser.add_argument("--column", default="cpu_utilization", help="the value column")
parser.add_argument("--table", help="workload table whose `data` gets the replay")
args = parser.parse_args()

Expand Down Expand Up @@ -72,7 +84,7 @@ def main():

start = min(int(s) for s in steps)
out = sorted(
(int(r["timestamp"]) - start, *labels[r["msinstanceid"]], r["cpu_utilization"])
(int(r["timestamp"]) - start, *labels[r["msinstanceid"]], r[args.column])
for r in rows(args.csv)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing values are handled inconsistently. <out>.csv keeps the raw empty string from r[args.column], while write_table (line 105) turns it into 0, so the CSV and the JSON table no longer agree. Also, seen (line 62) counts a step even when the value is empty, so a pod with gaps still passes the "reports at every step" filter and its gaps are replayed as made-up zeros. Earlier this input crashed on float(''); now it silently corrupts the data. Consider skipping empty values when building seen, or filling them in one place before both outputs are written.

if r["msinstanceid"] in labels
)
Expand All @@ -90,7 +102,7 @@ def write_table(table_path, out_path, rows, steps):
paced-feeder's series order (mixed radix, label_0 fastest)."""
by_series = {}
for offset, *_, label_0, value in rows: # sorted by offset
by_series.setdefault(label_0, []).append(round(float(value), 6))
by_series.setdefault(label_0, []).append(round(float(value or 0), 6))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description says Alibaba values are scaled ×10⁴ because Count-Min top-k rounds weights to integers (#916), but nothing here scales them, and there's no --scale option like the Google builder has. cpu_utilization runs from about 0.003 to 0.997 and paced-feeder replays with scale 1.0, so value.round() as i64 turns nearly every sample into 0 or 1, which makes top-k on this replay meaningless.

values = []
for r in range(REGIONS):
for s in range(SERVICES):
Expand Down
Loading
Loading