Slik reduserer vi Azure Fabric Spark‑kostnader med vCore‑overvåkning og automatisert right‑sizing

Mange dataprosesser koster mer enn de trenger fordi vCores (virtuelle prosessorkjerner) ofte står ubrukt. Denne guiden viser hvordan vi måler vCore‑sløsing med Azure Fabric Resource Usage API, analyserer idleShare og vCoreHours i Azure Data Explorer (ADX), og automatiserer trygg right‑sizing med Spark Advisor og CI/PR‑workflows for målbare kostbesparelser.
Hvem er dette for?
FinOps‑ledere (Financial Operations) som trenger konkrete kostmål og rapporter
Dataingeniører som ønsker trinnvise tiltak uten å svekke ytelse
Cloud‑arkitekter som trenger repeterbar automatisering, governance og måling
Kort analogi
vCore‑bruk er som tomgangskjøring i en bilflåte. Motorene går, drivstoffet forbrukes, men vi kommer ikke framover. Måling avslører tomgang. Analyse finner årsak. Handling stopper sløsingen.
Hva dekker vi?
Hva er Azure Fabric Spark vCore‑overvåkning og Resource Usage API?
Hvordan samle Resource Usage og sende til ADX (PoC‑skript)?
Hvordan analysere idleShare, vCoreHours og coreEfficiency med KQL?
Hvordan automatisere Spark Advisor‑anbefalinger til PR‑drevet right‑sizing?
KPI‑definisjoner og A/B‑metode

Hva er Azure Fabric Spark vCore‑overvåkning og Resource Usage API?
Azure Fabric gir programmatisk tilgang til Spark‑observability via Spark Monitoring APIs og Resource Usage API. Disse endepunktene leverer tidsserier for allocatedCores, runningCores, idleCores og coreEfficiency. Vi bruker disse dataene for å finne jobber med høy idleShare og lav coreEfficiency, som er de mest direkte kostdriverne for Spark‑workloads.
Steg 1 — Samle Resource Usage fra Spark Monitoring APIs og last til ADX
Hvorfor
Uten telemetry kan vi ikke måle sløsing. Resource Usage API gir grunnlaget for KPI‑beregning og automasjon.
Python‑skript — samle og laste inn i ADX
Bruk SPN (Service Principal) for autentisering og hent Resource Usage for en applicationId/runId. Plasser scriptet som et cron‑kjørende PoC eller i en Azure Function.
Filnavn: collect_resource_usage_to_adx.py
# collect_resource_usage_to_adx.py (for PoC)
# Avhengigheter: requests, azure-identity, azure-kusto-ingest
# pip install requests azure-identity azure-kusto-ingest
import os, json, requests
from azure.identity import ClientSecretCredential
from azure.kusto.ingest import KustoIngestClient, IngestionProperties, FileDescriptor
from azure.kusto.data import KustoConnectionStringBuilder
TENANT_ID = os.environ['AZ_TENANT_ID']
CLIENT_ID = os.environ['AZ_CLIENT_ID']
CLIENT_SECRET = os.environ['AZ_CLIENT_SECRET']
WORKSPACE_ID = os.environ['FABRIC_WORKSPACE_ID']
ITEM_ID = os.environ['FABRIC_ITEM_ID']
RESOURCE_USAGE_API = f"https://api.fabric.microsoft.com/workspaces/{WORKSPACE_ID}/items/{ITEM_ID}/resourceUsage"
KUSTO_CLUSTER = os.environ['KUSTO_CLUSTER']
KUSTO_DATABASE = os.environ['KUSTO_DATABASE']
KUSTO_TABLE = "ResourceUsage"
cred = ClientSecretCredential(TENANT_ID, CLIENT_ID, CLIENT_SECRET)
token = cred.get_token("https://api.fabric.microsoft.com/.default").token
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
def fetch_resource_usage(params=None):
r = requests.get(RESOURCE_USAGE_API, headers=headers, params=params, timeout=60)
r.raise_for_status()
return r.json()
def ingest_json_to_kusto(json_payload, fname="/tmp/resource_usage.json"):
with open(fname, "w") as f:
json.dump(json_payload, f)
kcsb = KustoConnectionStringBuilder.with_aad_application_key_authentication(KUSTO_CLUSTER, CLIENT_ID, CLIENT_SECRET, TENANT_ID)
ingest_client = KustoIngestClient(kcsb)
props = IngestionProperties(database=KUSTO_DATABASE, table=KUSTO_TABLE, dataFormat="json")
file_desc = FileDescriptor(fname, 0)
ingest_client.ingest_from_file(file_desc, ingestion_properties=props)
if __name__ == "__main__":
data = fetch_resource_usage()
ingest_json_to_kusto(data)
print("Innsamling og ingest utført.")
Steg 2 — Analyser: finn sløsing med KQL i Azure Data Explorer
KPI‑beregninger
idleShare = sum(idleCores) / sum(allocatedCores)
vCoreHours = sum(allocatedCores * runtimeHours)
coreEfficiency hentes direkte fra API‑felt ved tilgjengelighet
Ferdige KQL‑paneler for ADX
Importer disse som dashboard‑paneler i ADX:
idleShare trend per applikasjon (30 dager)
ResourceUsage
| where Timestamp between (ago(30d) .. now())
| summarize AllocatedCores=sum(todouble(allocatedCores)), IdleCores=sum(todouble(idleCores)) by ApplicationId, bin(Timestamp, 1d)
| extend IdleShare = IdleCores / AllocatedCores
| order by IdleShare desc
2. Topp 10 jobber etter vCore‑timer (30 dager)
ResourceUsage
| extend durationHours = todouble(durationMs) / 3600000.0
| summarize vCoreHours = sum(todouble(allocatedCores) * durationHours) by ApplicationId
| top 10 by vCoreHours
3. coreEfficiency‑fordeling og laveste jobber
ResourceUsage
| where isnotempty(coreEfficiency)
| summarize meanCoreEff=avg(todouble(coreEfficiency)), p10=percentile(todouble(coreEfficiency),10) by ApplicationId
| order by meanCoreEff asc
Steg 3 — Handle: automatiser Spark Advisor‑anbefalinger med PR‑flow
Hvorfor PR‑drevet endring?
Automatisering uten review er risikofylt. Vi ønsker repeterbarhet og menneskelig veto. PR‑flow gir sporbarhet, reviewers og governance.
GitHub Action — opprett PR når Advisor‑anbefalinger overskrider terskel
Fil: .github/workflows/advisor-pr.yml
name: Advisor PR for right-sizing
on:
schedule:
- cron: '0 2 * * *'
workflow_dispatch:
jobs:
check-advisor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { path: infra }
- uses: actions/setup-python@v4
with: { python-version: '3.10' }
- run: pip install requests PyYAML
- name: Call Advisor and prepare PR
env:
FABRIC_TOKEN: ${{ secrets.FABRIC_TOKEN }}
WORKSPACE_ID: ${{ secrets.FABRIC_WORKSPACE_ID }}
ITEM_ID: ${{ secrets.FABRIC_ITEM_ID }}
run: |
python .github/scripts/check_advisor_and_prepare_patch.py
- name: Create PR
uses: peter-evans/create-pull-request@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "chore(right-size): apply advisor suggestions"
branch: "advisor-rightsize-updates-${{ github.run_id }}"
title: "Advisor: Right‑size suggestions"
body: "Automatisk PR: forslag til right‑sizing fra Spark Advisor API."
KPI‑definisjoner og måling
KPI | Definisjon | Måleenhet | Baseline‑periode | Mål |
---|---|---|---|---|
idleShare | sum(idleCores) / sum(allocatedCores) | andel (0–1) | 14–30 dager | < 0.2 |
vCoreHours | sum(allocatedCores * runtimeHours) | vCore‑timer | 30 dager | redusere 10–30% |
coreEfficiency | nyttig compute / allokert compute (API‑felt) | andel (0–1) | 30 dager | > 0.6 |
costPerVCoreHour | gjeldende pris per vCore‑time inkl. reservering/spot | NOK per vCore‑time | 30 dager | redusere gjennom høyere utnyttelse |
baselinePeriod | perioden brukt som referanse | dager | 14–30 dager | definert per pilot |
costPerJob | vCoreHours * costPerVCoreHour | NOK | måned | redusere totalt kost per job |
PR‑ApprovalTime | tid fra PR opprettet til merge | timer | 30 dager | < 48 t |
For å regne kost bruker vi Azure Pricing Calculator eller relevante produktpriser for vCore‑baserte tjenester; se Azure prisverktøy for nøyaktige satser og scenario‑baserte estimater.
Enkel A/B‑målemetode
Velg to lignende jobber eller to perioder for samme jobb (A=kontroll, B=intervensjon).
Mål baseline i 2–4 uker for begge (idleShare, vCoreHours).
Implementer endring i B; la A være uendret.
Mål i 2–4 uker post‑intervensjon. Beregn relativ endring: (A_post − B_post) / A_post.
Bruk t‑test ved stor nok datamengde; ellers bootstrap‑metode for konfidensintervall.
Dokumenter og beslutning: rull ut ved signifikant forbedring og akseptabel risiko.

Sjekkliste før produksjon
SPN (Service Principal) med minst privilegium
ADX‑tabell ResourceUsage med korrekt schemadefinisjon (timestamp, applicationId, allocatedCores, idleCores, coreEfficiency, durationMs)
Dashboards og alerting i ADX + Azure Monitor (action groups)
PR‑gates og eierskap til jobdefinitions.
Dokumentert baseline i 14–30 dager før endringer
Ofte stilte spørsmål
Hva er idleShare og hvorfor er det viktig? IdleShare er andelen av allokerte vCores som står inaktive i en kjøring (sum(idleCores) / sum(allocatedCores)). Den identifiserer direkte sløsing; høy idleShare betyr at vi betaler for CPU‑kapasitet som ikke brukes, og er dermed et nøkkel‑FinOps‑mål for å finne kostdrivere.
Hvordan får vi dataene fra Azure Fabric for analyser? Vi henter data via Fabric Spark Monitoring APIs og Resource Usage API ved å autentisere med en Service Principal (SPN). Resource Usage‑endepunktene returnerer tidsserier for allocatedCores, idleCores, runningCores, coreEfficiency og runtime‑felt som vi persisterer i ADX for videre KQL‑analyse.
Hvordan sikrer vi at automatiske endringer ikke bryter jobber eller SLA? Bruk PR‑drevet automatisering: opprett forslag automatisk fra Spark Advisor, la reviewers godkjenne endringer, og deploy først til en staging‑jobb. Sett terskler for automatisk direkteoppdatering kun for lavrisiko‑tilfeller, og overvåk coreEfficiency/idleShare etter endring for rask rollback ved avvik.
Hvordan kan vi bevise effekten av en right‑size‑pilot teknisk? Kjør en A/B‑måling: velg liknende jobber eller perioder, mål baseline i 2–4 uker (idleShare og vCoreHours), implementer endring i B‑gruppen, mål 2–4 uker etter og beregn relativ endring. Bruk enkel statistikk (t‑test eller bootstrap) for å vurdere signifikans før bred utrulling.
Vil du vite mer?
Vil du gå videre med en uforpliktende prat om hvordan vi kan måle, optimalisere og automatisere vCore‑bruk i deres Azure‑miljø? Ta gjerne kontakt for en kort gjennomgang av deres nåværende oppsett, en vurdering av en pilot og en skreddersydd handlingsplan. Svar på dette innlegget eller bruk kontaktlenken i forfatterprofilen, så følger jeg opp raskt og fleksibelt for å finne et tidspunkt som passer.
Forfatteren påtar seg intet ansvar for uforutsette feil, tap av data, driftsavbrudd eller andre konsekvenser som måtte oppstå ved bruk av eksempelkoden. Leseren bruker den på egen risiko.