Hi ha una conversa que AlpinaShop porta set mòduls ajornant, i que la lliçó anterior ha tornat a posar sobre la taula tres vegades: activar els registres d'accés a dades costa, Security Command Center Premium es va descartar per preu, i tres mil euros es van repartir com si fossin molts diners — que per a una empresa de quaranta persones ho són.

Cap d'aquestes decisions no es pot prendre bé sense saber d'on surt cada euro de la factura. I avui ningú a AlpinaShop no ho sap.

La factura de juliol van ser 1.058 €. La de gener van ser 210 €. Ningú no va decidir multiplicar-la per cinc: va anar creixent lliçó a lliçó, servei a servei, sense que cap decisió concreta semblés cara. Quan la Marta va obrir el desglossament per preparar el pressupost de l'any següent, es va trobar amb dues partides que no va saber explicar i que juntes eren el 40 % del total.

Aquesta lliçó obre aquesta factura sencera. En acabar sabràs per què el núvol sorprèn, entendràs què és un SKU i com consultar la facturació a BigQuery per respondre «qui gasta què», muntaràs pressupostos que actuen en lloc de només avisar, coneixeràs les palanques d'estalvi ordenades per retorn real, caçaràs les despeses fantasma amb un script, i veuràs la factura d'AlpinaShop abans i després, desglossada i comentada amb honestedat — inclòs el que no es va poder estalviar i el que es va decidir gastar de més a propòsit.

Contingut

  1. Per què la factura del núvol sorprèn
  2. Entendre la factura: SKU, ús i descomptes
  3. L'exportació de facturació a BigQuery
  4. Les consultes que responen «qui gasta què»
  5. FinOps per a una pime: informar, optimitzar, operar
  6. Pressupostos, alertes i accions automàtiques
  7. Quotes com a límit dur
  8. Palanques d'estalvi ordenades per retorn
  9. El cost ocult del trànsit
  10. Etiquetatge i assignació de costos
  11. Detecció d'anomalies i despeses fantasma
  12. El cas complet d'AlpinaShop: abans i després
  13. Eines: Recommender, Active Assist i la calculadora

  1. Per què la factura del núvol sorprèn

En el model tradicional, la despesa en infraestructura era una decisió anual, visible i negociada: es compraven servidors, algú signava, i durant tres anys el cost era el mateix cada mes. Era car, rígid i ineficient — i predictible.

Al núvol passa el contrari, i la diferència es pot resumir en quatre punts:

Factor Efecte
Cost variable La factura depèn de l'ús, i l'ús depèn del trànsit, dels usuaris i dels errors
Decisions tècniques amb efecte econòmic Un SELECT * de la Lucía pot costar més que el servidor on corre la botiga
Sense fre natural Ningú no signa una ordre de compra per crear un clúster. Es crea en dos clics
Desfasament temporal La despesa d'avui es veu a la factura d'aquí a un mes, quan ja s'ha fet

El tercer punt és el decisiu, i mereix un exemple real. A 04-06, per avaluar Cloud Composer davant de Workflows, la Marta va crear un entorn de Composer. L'avaluació va durar dos dies, la decisió va ser Workflows, i ningú no va esborrar l'entorn. Cloud Composer no escala a zero: manté una infraestructura permanent. Aquest entorn porta quatre mesos funcionant sense que ningú no el faci servir, a uns 280 € al mes.

Ningú no va decidir gastar 1.120 €. Simplement, ningú no va decidir no gastar-los.

La primera regla de la gestió de costos al núvol: el problema gairebé mai no és que una cosa sigui cara. És que ningú no sabia que estava encesa.

  1. Entendre la factura: SKU, ús i descomptes

La factura de Google Cloud té tres nivells d'agregació, i cal saber llegir-los en ordre invers al que apareixen.

Nivell Exemple Utilitat
Servei Compute Engine Massa gruixut: diu què però no per què
SKU "N1 Predefined Instance Core running in EMEA" El nivell útil: unitat facturable concreta
Ús 1.460 hores × 0,0348 $ El detall

Un SKU (Stock Keeping Unit) és la unitat mínima de facturació: una combinació concreta de recurs, regió i modalitat. Cada servei en té desenes o centenars.

Exemple real del desglossament de Compute Engine per al MIG d'AlpinaShop abans de retirar-lo:

SKU Ús Cost
N1 Predefined Instance Core running in EMEA 1.460 vCPU-h 29,50 €
N1 Predefined Instance Ram running in EMEA 5.840 GiB-h 16,20 €
Balanced PD Capacity in EMEA 40 GiB-mes 3,80 €
Network Inter Zone Egress 12 GiB 0,14 €
Network Internet Egress from EMEA to EMEA 85 GiB 10,20 €

Aprenentatge immediat: el cost d'una VM no és «una VM». Són vCPU i memòria i disc i trànsit, cadascun amb el seu SKU i el seu preu. Per això canviar d'e2-medium a e2-small no redueix el cost a la meitat: redueix dos dels cinc SKU.

Els descomptes que s'apliquen sols i els que cal demanar

Descompte Com s'obté Estalvi típic
Per ús sostingut (SUD) Automàtic a Compute Engine si la VM corre bona part del mes Fins a ~30 %
Per ús compromès (CUD) Es contracta: 1 o 3 anys 30-55 %
Nivell gratuït Automàtic, mensual Variable
Spot / preemptible Es tria en crear el recurs 60-91 %
Descomptes per volum Negociats amb Google (empreses grans) Variable

El descompte per ús sostingut és interessant perquè és invisible: s'aplica sol, i explica per què la factura d'una VM encesa tot el mes és menor que hores × preu de llista. I també per què apagar una VM a les nits estalvia menys del que l'aritmètica suggereix: en baixar del llindar, es perd part del descompte automàtic.

Tots els preus d'aquesta lliçó són ordres de magnitud a europe-west1 per raonar. Canvien, varien per regió i depenen del contracte. Verifica'ls sempre a la pàgina de preus oficial i a la calculadora.

  1. L'exportació de facturació a BigQuery

A 01-04 es va activar i es va prometre explotar-la. Ha arribat el moment.

La consola de facturació serveix per veure tendències. Per respondre preguntes concretes —per què va pujar la factura el dimarts 14?, quant costa l'entorn de desenvolupament?— cal SQL.

# 1. Dataset desti a alpinashop-datos
bq --location=EU mk --dataset \
  --description="Exportacio de facturacio" \
  alpinashop-datos:facturacion

# 2. L exportacio es configura a la consola:
#    Facturacio > Exportacio de facturacio > Configuracio de BigQuery
#    Activar "Cost detallat" (nivell de recurs), no nomes "Cost estandard"

Activa sempre l'exportació de cost detallat, encara que generi més files. La diferència:

Exportació Granularitat Respon a
Costos estàndard Servei + SKU + projecte + etiqueta «Quant gasta BigQuery en producció?»
Costos detallats + recurs concret «Quin bucket concret costa 40 €?»
Preus Catàleg de preus Simulacions

Sense el detall per recurs, sabràs que Cloud Storage costa 25 € però no quin bucket. I aquesta és just la pregunta que cal respondre.

Dos avisos pràctics:

  1. Les dades triguen. L'exportació s'omple amb diverses hores de retard i es corregeix durant dies: els costos d'ahir poden canviar demà. No serveix per a alertes en temps real; per a això hi ha els pressupostos.
  2. La taula és enorme i està particionada per _PARTITIONTIME. Consultar-la sense filtre de data processa mesos de dades, i aquesta consulta et costa diners. És irònic i passa constantment.

  1. Les consultes que responen «qui gasta què»

Aquestes sis consultes cobreixen el 95 % de les preguntes reals. Val la pena desar-les com a vistes.

1. Despesa per projecte, últims 30 dies.

SELECT
  project.id                                   AS projecte,
  ROUND(SUM(cost), 2)                          AS cost,
  ROUND(SUM(IFNULL((SELECT SUM(c.amount) FROM UNNEST(credits) c), 0)), 2) AS credits_aplicats,
  ROUND(SUM(cost) + SUM(IFNULL((SELECT SUM(c.amount) FROM UNNEST(credits) c), 0)), 2) AS net
FROM `alpinashop-datos.facturacion.gcp_billing_export_resource_v1_XXXXXX`
WHERE DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
GROUP BY projecte
ORDER BY net DESC

El camp credits és un array imbricat amb descomptes, promocions i nivell gratuït, i sempre són valors negatius. Sumar-lo al cost dona el net real. Oblidar-ho és l'error número u en analitzar facturació a BigQuery: es veuen xifres inflades i ningú no entén per què no quadren amb la consola.

2. Els 20 SKU més cars: on són els diners de debò.

SELECT
  service.description AS servei,
  sku.description     AS sku,
  ROUND(SUM(cost), 2) AS cost,
  ROUND(SUM(usage.amount), 2) AS us,
  ANY_VALUE(usage.unit) AS unitat
FROM `alpinashop-datos.facturacion.gcp_billing_export_resource_v1_XXXXXX`
WHERE DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
GROUP BY servei, sku
ORDER BY cost DESC
LIMIT 20

3. Despesa per etiqueta: la que justifica la disciplina de 01-04.

SELECT
  (SELECT value FROM UNNEST(labels) WHERE key = 'entorno')      AS entorn,
  (SELECT value FROM UNNEST(labels) WHERE key = 'equipo')       AS equip,
  (SELECT value FROM UNNEST(labels) WHERE key = 'centro-coste') AS centre_cost,
  (SELECT value FROM UNNEST(labels) WHERE key = 'aplicacion')   AS aplicacio,
  ROUND(SUM(cost), 2) AS cost
FROM `alpinashop-datos.facturacion.gcp_billing_export_resource_v1_XXXXXX`
WHERE DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
GROUP BY entorn, equip, centre_cost, aplicacio
ORDER BY cost DESC

4. Recursos concrets més cars (requereix exportació detallada).

SELECT
  resource.name       AS recurs,
  service.description AS servei,
  ROUND(SUM(cost), 2) AS cost
FROM `alpinashop-datos.facturacion.gcp_billing_export_resource_v1_XXXXXX`
WHERE DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
  AND resource.name IS NOT NULL
GROUP BY recurs, servei
ORDER BY cost DESC
LIMIT 30

5. Evolució diària: per veure l'esglaó.

SELECT
  DATE(usage_start_time) AS dia,
  service.description    AS servei,
  ROUND(SUM(cost), 2)    AS cost
FROM `alpinashop-datos.facturacion.gcp_billing_export_resource_v1_XXXXXX`
WHERE DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 60 DAY)
GROUP BY dia, servei
HAVING cost > 0.5
ORDER BY dia DESC, cost DESC

6. Recursos SENSE etiquetar: el deute de govern fet número.

SELECT
  project.id          AS projecte,
  service.description AS servei,
  ROUND(SUM(cost), 2) AS cost_sense_atribuir
FROM `alpinashop-datos.facturacion.gcp_billing_export_resource_v1_XXXXXX`
WHERE DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
  AND (SELECT COUNT(*) FROM UNNEST(labels) WHERE key = 'centro-coste') = 0
GROUP BY projecte, servei
HAVING cost_sense_atribuir > 1
ORDER BY cost_sense_atribuir DESC

La consulta 6 és la més incòmoda i la més útil. Tot el que hi apareix és despesa que no es pot atribuir a ningú. A AlpinaShop, la primera vegada que es va executar, en van sortir 380 € de 1.058 €: el 36 % de la factura no tenia amo.

  1. FinOps per a una pime: informar, optimitzar, operar

FinOps és la disciplina de gestionar el cost del núvol com una responsabilitat compartida entre finances, tecnologia i negoci. Té tres fases que es recorren en cicle:

flowchart LR
    I["INFORMAR<br/>visibilitat, assignació,<br/>previsions"] --> O["OPTIMITZAR<br/>dimensionar, descomptes,<br/>eliminar malbaratament"]
    O --> P["OPERAR<br/>polítiques, automatismes,<br/>revisió contínua"]
    P --> I
Fase Què es fa A AlpinaShop
Informar Exportació, etiquetes, taulers, pressupostos Apartats 3, 4, 6, 10
Optimitzar Dimensionar, apagar, descomptes, arquitectura Apartat 8
Operar Polítiques que impedeixen el malbaratament, automatismes Apartats 6, 7, 10, 11

L'error clàssic és començar per optimitzar. Sense visibilitat, s'optimitza el que es veu —que sol ser el menys important— i s'ignora l'entorn de Composer de 280 € que ningú no sabia que existia. Primer es mesura, després es talla.

Qui és l'amo del cost?

En una empresa gran hi ha un equip de FinOps. En una de quaranta persones, la pregunta és real i té una resposta incòmoda:

Model Com funciona Problema
Ningú Es mira la factura quan espanta El d'AlpinaShop fins avui
Finances Comptabilitat vigila el total No entén què és un SKU ni pot actuar
Només infraestructura La Marta ho porta tot No controla el que gasten les consultes de la Lucía
Responsabilitat distribuïda amb un coordinador Cada equip veu i respon de la seva despesa; algú coordina El correcte

Per a AlpinaShop:

  • La Marta coordina: manté el tauler, revisa mensualment i proposa.
  • Cada persona veu la seva despesa: la Lucía la de BigQuery i Dataflow, en Dani la de Cloud Run i Cloud Build.
  • Direcció aprova els compromisos pluriennals.
  • Una reunió de 30 minuts al mes amb el tauler obert.

Aquesta reunió mensual, que sembla burocràcia, és la pràctica de FinOps amb millor relació cost/benefici que existeix. El que es mira en grup un cop al mes no es descontrola.

  1. Pressupostos, alertes i accions automàtiques

Un pressupost a Google Cloud no limita la despesa: avisa. Això sorprèn tothom i cal interioritzar-ho:

No existeix un botó de «no gastis més de X». El pressupost envia notificacions; aturar la despesa ho has d'automatitzar tu.

Pressupost bàsic

gcloud billing budgets create \
  --billing-account=BILLING_ACCOUNT_ID \
  --display-name="AlpinaShop total mensual" \
  --budget-amount=1200EUR \
  --threshold-rule=percent=0.5 \
  --threshold-rule=percent=0.8 \
  --threshold-rule=percent=1.0 \
  --threshold-rule=percent=1.2 \
  --threshold-rule=percent=0.8,basis=forecasted-spend \
  --notifications-rule-monitoring-notification-channels=CHANNEL_ID

L'última regla és la més valuosa i la que menys es fa servir: basis=forecasted-spend avisa quan Google preveu que se superarà el llindar a final de mes. Avisa el dia 8, no el dia 26. És l'única alerta que arriba a temps de fer alguna cosa.

Pressupostos que convé tenir, en lloc d'un de sol:

Pressupost Import Per què
Total de l'organització 1.200 € Visió global
alpinashop-prod 700 € El que importa
alpinashop-dev 100 € Aquí es descontrola tot
alpinashop-datos 250 € BigQuery i Dataflow són variables
Només BigQuery, per etiqueta 150 € Una consulta pot disparar això tota sola

L'acció automàtica

Aquí és on el pressupost deixa de ser un avís i passa a ser un control. El flux:

flowchart LR
    B["Pressupost<br/>llindar superat"] --> PS["Pub/Sub<br/>alertas-presupuesto"]
    PS --> F["Cloud Function<br/>reaccionar-presupuesto"]
    F -->|"100% a dev"| A1["Apagar VM de desenvolupament"]
    F -->|"120% a dev"| A2["Desvincular facturació"]
    F -->|"qualsevol llindar"| A3["Avisar al canal"]
# main.py — funcio reaccionar-presupuesto (Cloud Functions 2a gen, 06-03)
import base64, json, os, logging
from google.cloud import compute_v1
from googleapiclient import discovery

PROJECTE_DEV = "alpinashop-dev"
ZONA = "europe-west1-b"

def reaccionar_pressupost(esdeveniment, context):
    dades = json.loads(base64.b64decode(esdeveniment["data"]).decode("utf-8"))

    nom        = dades.get("budgetDisplayName", "")
    gastat     = float(dades.get("costAmount", 0))
    pressupost = float(dades.get("budgetAmount", 1))
    llindar    = float(dades.get("alertThresholdExceeded", 0))
    ratio      = gastat / pressupost if pressupost else 0

    logging.info(json.dumps({
        "severity": "WARNING", "message": "Llindar de pressupost superat",
        "pressupost": nom, "gastat": gastat, "ratio": round(ratio, 2),
    }))

    # Nomes s actua sobre DESENVOLUPAMENT. Produccio MAI no s apaga sola.
    if "dev" not in nom.lower():
        return

    if ratio >= 1.0:
        apagar_vms_desenvolupament()

    if ratio >= 1.2:
        desvincular_facturacio(PROJECTE_DEV)

def apagar_vms_desenvolupament():
    client = compute_v1.InstancesClient()
    for inst in client.list(project=PROJECTE_DEV, zone=ZONA):
        if inst.status == "RUNNING":
            client.stop(project=PROJECTE_DEV, zone=ZONA, instance=inst.name)
            logging.warning(f"VM aturada per pressupost: {inst.name}")

def desvincular_facturacio(projecte):
    # MESURA EXTREMA: atura practicament tot el projecte
    svc = discovery.build("cloudbilling", "v1")
    svc.projects().updateBillingInfo(
        name=f"projects/{projecte}",
        body={"billingAccountName": ""}
    ).execute()
    logging.critical(f"FACTURACIO DESVINCULADA de {projecte}")

Tres advertiments que cal llegir dues vegades:

  1. No automatitzis mai l'apagada de producció. Un pic de vendes en campanya dispara el pressupost; apagar la botiga el millor dia de l'any és pitjor que qualsevol factura.
  2. Desvincular la facturació és destructiu i en part irreversible. Els recursos s'aturen i alguns s'eliminen passat un termini. Només té sentit en desenvolupament, i tot i així convé pensar-s'ho.
  3. Els missatges de pressupost poden arribar duplicats. La funció ha de ser idempotent (06-03): apagar una VM ja apagada no ha de fallar.

  1. Quotes com a límit dur

On el pressupost avisa, la quota impedeix. És l'únic mecanisme que realment frena la despesa.

Tipus Què limita Ús per al cost
De taxa Peticions per minut a una API Contenir bucles descontrolats
D'assignació Recursos simultanis: vCPU, IP, discos El més eficaç
# Veure les quotes de CPU d una regio
gcloud compute regions describe europe-west1 --format="table(quotas.metric, quotas.limit, quotas.usage)"

Limitar la quota de vCPU en desenvolupament és el fre més eficaç que existeix, perquè és impossible saltar-se'l: si la quota són 8 vCPU, ningú no pot crear una VM de 32 encara que vulgui.

Les quotes de cost de BigQuery

BigQuery sota demanda cobra per bytes llegits, i una sola consulta mal escrita pot costar més que un mes de servidors. Hi ha dos frens, i tots dos haurien d'estar posats sempre:

# 1. Limit de bytes processats per dia i per usuari
gcloud alpha services quota update \
  --service=bigquery.googleapis.com \
  --consumer=projects/alpinashop-datos \
  --metric=bigquery.googleapis.com/quota/query/usage \
  --unit=1/d/{project}/{user} \
  --value=1099511627776        # 1 TiB per usuari i dia
-- 2. Limit per consulta individual, a la sessio o a l script
SET @@maximum_bytes_billed = 107374182400;   -- 100 GiB

I a l'eina de línia de comandes:

bq query --maximum_bytes_billed=107374182400 --use_legacy_sql=false 'SELECT ...'

El missatge que retorna una consulta bloquejada és explícit —"Query exceeded limit for bytes billed"— i produeix l'efecte pedagògic correcte: qui la va escriure aprèn a filtrar per partició abans de reescriure-la.

  1. Palanques d'estalvi ordenades per retorn

Aquesta és la secció pràctica. Ordenades per euros estalviats per hora de feina invertida, que és el criteri que importa quan l'equip és petit.

Palanca 1 — Apagar el que no es fa servir (retorn immediat)

El més rendible no és optimitzar: és eliminar. I sempre hi ha alguna cosa.

# Entorns de desenvolupament fora d horari, amb Cloud Scheduler + Workflows
gcloud scheduler jobs create http apagar-desarrollo \
  --location=europe-west1 \
  --schedule="0 20 * * 1-5" \
  --time-zone="Europe/Madrid" \
  --uri="https://workflowexecutions.googleapis.com/v1/projects/alpinashop-dev/locations/europe-west1/workflows/apagar-entorno/executions" \
  --http-method=POST \
  --oauth-service-account-email=sa-scheduler@alpinashop-dev.iam.gserviceaccount.com

gcloud scheduler jobs create http encender-desarrollo \
  --location=europe-west1 \
  --schedule="0 8 * * 1-5" \
  --time-zone="Europe/Madrid" \
  --uri="https://workflowexecutions.googleapis.com/v1/projects/alpinashop-dev/locations/europe-west1/workflows/encender-entorno/executions" \
  --http-method=POST \
  --oauth-service-account-email=sa-scheduler@alpinashop-dev.iam.gserviceaccount.com

L'aritmètica que convenç qualsevol: un entorn encès de 8:00 a 20:00 de dilluns a divendres són 260 hores de les 730 del mes. Un 64 % d'estalvi per dues feines programades.

Amb dos matisos honestos: els discos es continuen pagant encara que la VM estigui apagada, i es perd part del descompte per ús sostingut. L'estalvi real ronda el 50-55 %, no el 64 %.

Palanca 2 — Dimensionar correctament

Google observa l'ús real durant 8 dies i recomana:

gcloud recommender recommendations list \
  --project=alpinashop-prod --location=europe-west1-b \
  --recommender=google.compute.instance.MachineTypeRecommender \
  --format="table(description, primaryImpact.costProjection.cost.units)"

Existeixen recomanadors per a VM, discos persistents, Cloud SQL, adreces IP i molts més. Aplicar-los és de les coses més rendibles per hora invertida.

L'advertiment: les recomanacions parteixen de la finestra observada. Si aquesta finestra és l'agost i el pic és a l'octubre, dimensionar a la baixa segons l'agost és preparar-se un problema. Contrasta sempre amb el pic anual.

Palanca 3 — Descomptes per compromís

Ús sostingut (SUD) Ús compromès (CUD)
Com Automàtic Es contracta
Compromís Cap 1 o 3 anys, es paga igual
Estalvi Fins a ~30 % 30-55 %
Flexibilitat Total Els basats en despesa són flexibles; els de recursos, no
Risc Cap Pagar pel que ja no fas servir

Hi ha dos tipus de compromís, i triar malament és car:

Tipus Es compromet a Risc
Per recursos X vCPU i Y GiB en una regió i família concretes Alt: si migres o canvies de família, continues pagant
Per despesa (flexible) Gastar almenys X €/hora en un servei Baix: s'aplica al que facis servir

Regla pràctica: compromet-te només amb la part estable del teu consum, típicament el 50-70 % del mínim històric. Mai amb el total.

I la lliçó que AlpinaShop va aprendre a costa seva: si la Marta hagués contractat el gener un compromís a un any sobre les vCPU del MIG, avui —després de migrar a Cloud Run a 07-02— continuaria pagant per unes VM que ja no existeixen. L'optimització arquitectònica invalida els compromisos. Primer s'estabilitza l'arquitectura, després es compromet.

Palanca 4 — VM Spot

Instàncies amb descompte del 60-91 % que Google pot reclamar amb 30 segons d'avís.

Serveixen per a No serveixen per a
Processament per lots amb reintents Bases de dades
Entrenament de models amb punts de control Serveis web de cara al client
Treballadors de Dataflow i Dataproc Res amb estat local
CI/CD Res que no toleri reinicis
gcloud dataproc clusters create cluster-analitica \
  --region=europe-west1 \
  --num-workers=2 \
  --num-secondary-workers=8 \
  --secondary-worker-type=spot          # 8 de 10 treballadors al 30% del preu

El patró correcte és el d'aquesta ordre: nucli estable petit + majoria spot. Si Google reclama els spot, la feina s'alenteix però no mor.

Palanca 5 — Classes d'emmagatzematge i cicle de vida

Classe Cost relatiu Recuperació mínima Ús
Standard 1× — Accés freqüent
Nearline ~0,5× 30 dies Menys d'un cop al mes
Coldline ~0,3× 90 dies Trimestral
Archive ~0,12× 365 dies Còpies legals
resource "google_storage_bucket" "datalake" {
  name     = "alpinashop-datalake"
  location = "EUROPE-WEST1"

  lifecycle_rule {
    condition { age = 30 }
    action { type = "SetStorageClass" storage_class = "NEARLINE" }
  }
  lifecycle_rule {
    condition { age = 90 }
    action { type = "SetStorageClass" storage_class = "COLDLINE" }
  }
  lifecycle_rule {
    condition { age = 365 }
    action { type = "SetStorageClass" storage_class = "ARCHIVE" }
  }
  lifecycle_rule {
    condition { num_newer_versions = 3 }
    action { type = "Delete" }        # limitar versions antigues
  }
}

La trampa de les classes fredes, que cal conèixer abans de configurar-les: tenen càrrecs per recuperació anticipada. Un objecte a Coldline esborrat o llegit abans de 90 dies factura com si hi hagués estat els 90. Posar Archive a dades que es consulten cada dos mesos surt més car que Standard.

L'última regla, sobre versions, resol un problema real: amb versionatge activat (i ha d'estar-hi, per 07-04), cada modificació deixa una còpia. Un bucket amb versionatge i sense límit de versions creix indefinidament i ningú no el mira.

Palanca 6 — Particionat i clustering a BigQuery

BigQuery sota demanda cobra per bytes llegits, no per temps. Una taula de 500 GB sense particionar costa el mateix consultar-ne un dia que un any.

CREATE OR REPLACE TABLE `alpinashop-datos.alpinashop_analitica.pedidos_opt`
PARTITION BY DATE(fecha_pedido)
CLUSTER BY categoria_producto, provincia
OPTIONS (
  partition_expiration_days = 1095,
  require_partition_filter  = TRUE      -- <<< l opcio que salva la factura
)
AS SELECT * FROM `alpinashop-datos.alpinashop_analitica.pedidos`;

require_partition_filter = TRUE és l'opció més rendible de tot BigQuery. Rebutja qualsevol consulta que no filtri per partició:

Cannot query over table 'pedidos_opt' without a filter over column(s)
'fecha_pedido' that can be used for partition elimination

Un missatge d'error a canvi d'evitar escanejos complets de 500 GB.

Efecte mesurat sobre la consulta habitual de la Lucía:

Versió Bytes llegits Cost per execució
Sense particionar, SELECT * 480 GB ~2,70 €
Particionada, filtre de 30 dies 41 GB ~0,23 €
+ clustering per categoria 6 GB ~0,03 €

Noranta vegades més barata. I la mateixa consulta executada 40 vegades al mes en un tauler de control passa de 108 € a 1,20 €.

Palanca 7 — Sota demanda davant de les edicions de BigQuery

Model Com es paga Quan convé
Sota demanda Per TB llegit Ús irregular o baix. AlpinaShop
Standard / Enterprise (slots) Per capacitat de còmput reservada, amb autoescalat Ús alt i sostingut

El punt d'equilibri ronda un consum mensual constant equivalent a diversos centenars d'euros sota demanda. Per sota, sota demanda guanya gairebé sempre. Per sobre, les reserves donen a més cost predictible, que de vegades val més que l'estalvi.

Palanca 8 — CDN i memòria cau

Cada resposta servida des de la memòria cau de Cloud CDN (03-03) és trànsit que no surt de l'origen i còmput que no s'executa.

Mètrica Sense CDN Amb CDN al 85 % d'encerts
Egress des de l'origen 300 GB 45 GB
Cost d'egress ~36 € ~5,40 € + cost de CDN
Instàncies de Cloud Run Més Menys

I la palanca gratuïta que gairebé ningú no activa: comprimir. Amb gzip o brotli, una pàgina HTML de 200 KB viatja en 30 KB. Un 85 % menys de bytes facturats, i a més carrega més ràpid.

Palanca 9 — Escalat a zero

Ja quantificada a 07-02: el catàleg va passar de ~50 € a ~7 € al mes. La regla general:

Tot el que no rebi trànsit constant hauria d'escalar a zero. Cloud Run, Cloud Functions i les feines per lots ho fan; les VM i els clústers, no.

Resum ordenat per retorn

# Palanca Estalvi típic Esforç €/hora invertida
1 Eliminar el que no es fa servir 10-40 % Molt baix Altíssim
2 Apagar desenvolupament fora d'horari 50 % de dev Baix Molt alt
3 require_partition_filter + clustering 50-95 % de BigQuery Baix Molt alt
4 Dimensionar amb Recommender 20-40 % de còmput Baix Alt
5 Cicle de vida d'emmagatzematge 40-70 % de storage Baix Alt
6 CDN i compressió 60-85 % d'egress Mitjà Alt
7 Escalat a zero 60-90 % del servei Mitjà Alt
8 VM Spot en lots 60-90 % d'aquests lots Mitjà Mitjà
9 Compromisos d'ús 30-55 % del que es compromet Baix, amb risc Mitjà
10 Edicions de BigQuery Variable Alt Baix si no hi ha escala

  1. El cost ocult del trànsit

Es va introduir a 07-03 i aquí es tanca amb els quatre amagatalls i el seu remei.

Trajecte Cost orientatiu
Entrada des d'internet Gratis
Dins d'una zona, IP interna Gratis
Entre zones de la mateixa regió ~0,01 $/GB
Entre regions de la UE ~0,02 $/GB
A un altre continent 0,05-0,15 $/GB
Sortida a internet, Premium ~0,12 $/GB
Balancejador: regles + dades processades Càrrec fix + per GB
Amagatall Com apareix Remei
Rèplica HA de Cloud SQL Replicació contínua entre zones És el preu de la disponibilitat. S'accepta i es coneix
Aplicació i BD en zones diferents Cada consulta creua zona Col·locar deliberadament
Registres i còpies cap a una altra regió Per cada línia de registre Buckets de registres a la mateixa regió
Balancejadors oblidats Càrrec fix per regla de reenviament, hi hagi o no trànsit Auditoria periòdica (apartat 11)

  1. Etiquetatge i assignació de costos

La disciplina de 01-04, ara explotada. Les quatre etiquetes d'AlpinaShop:

Etiqueta Valors Respon a
entorno prod, dev, pruebas Quant costa desenvolupament?
equipo infra, desarrollo, datos Qui gasta?
centro-coste tienda, analitica, plataforma A quina línia de negoci s'imputa?
aplicacion catalogo, informes, ml Quin producte costa què?

Regles que les fan útils:

  1. Valors d'un conjunt tancat. equipo: varios destrueix l'anàlisi.
  2. A tots els recursos que facturin. Un recurs sense etiqueta és despesa sense amo.
  3. Aplicades per Terraform, mai a mà.
  4. Compte: no tots els recursos admeten etiquetes. L'egress de xarxa, alguns SKU de balancejador i certs càrrecs de suport no en porten. Sempre hi haurà un residu sense atribuir; l'important és que sigui petit i conegut.

La política que impedeix crear recursos sense etiqueta

S'aplica a Terraform, que és on es crea tot:

variable "etiquetas" {
  type        = map(string)
  description = "Etiquetes obligatories d AlpinaShop"

  validation {
    condition = alltrue([
      for k in ["entorno", "equipo", "centro-coste", "aplicacion"] :
      contains(keys(var.etiquetas), k)
    ])
    error_message = "Falten etiquetes obligatories: entorno, equipo, centro-coste, aplicacion."
  }

  validation {
    condition     = contains(["prod", "dev", "pruebas"], lookup(var.etiquetas, "entorno", ""))
    error_message = "entorno ha de ser prod, dev o pruebas."
  }

  validation {
    condition     = contains(["infra", "desarrollo", "datos"], lookup(var.etiquetas, "equipo", ""))
    error_message = "equipo ha de ser infra, desarrollo o datos."
  }
}

El plan falla si falten etiquetes o si els seus valors no són vàlids. És prevenció al punt de creació, que és infinitament més eficaç que perseguir recursos orfes després. I es complementa amb les etiquetes de recurs (tags) de l'organització i les polítiques de 07-07, que actuen fins i tot sobre el que es creï fora de Terraform.

  1. Detecció d'anomalies i despeses fantasma

Detecció d'anomalies

Google Cloud inclou detecció automàtica d'anomalies de cost a la consola de facturació: compara la despesa amb el patró històric i avisa de desviacions. És gratuïta, no cal configurar-la, i convé revisar-la mensualment.

La versió pròpia, més ajustable:

-- Serveis la despesa dels quals ahir es desvia mes de 3 sigmes de la seva mitjana de 30 dies
WITH diari AS (
  SELECT service.description AS servei, DATE(usage_start_time) AS dia, SUM(cost) AS cost
  FROM `alpinashop-datos.facturacion.gcp_billing_export_resource_v1_XXXXXX`
  WHERE DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 45 DAY)
  GROUP BY servei, dia
),
estad AS (
  SELECT servei,
         AVG(cost)    AS mitjana,
         STDDEV(cost) AS desviacio
  FROM diari
  WHERE dia BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 31 DAY)
                AND DATE_SUB(CURRENT_DATE(), INTERVAL 2 DAY)
  GROUP BY servei
)
SELECT d.servei, d.dia, ROUND(d.cost,2) AS cost_ahir,
       ROUND(e.mitjana,2) AS mitjana_30d,
       ROUND(SAFE_DIVIDE(d.cost - e.mitjana, e.desviacio), 1) AS sigmes
FROM diari d JOIN estad e USING (servei)
WHERE d.dia = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)
  AND e.desviacio > 0
  AND d.cost > e.mitjana + 3 * e.desviacio
  AND d.cost > 2
ORDER BY sigmes DESC

El filtre d.cost > 2 evita el soroll: un servei que passa de 0,02 € a 0,20 € són 9 sigmes i no li importa a ningú.

Les despeses fantasma

Recursos que costen diners i no donen valor a ningú. Sempre n'hi ha. A totes les empreses.

Fantasma Per què apareix Cost típic
IP estàtiques reservades sense fer servir Es reserva, es canvia el disseny, no s'allibera ~7 €/mes cadascuna. Una IP sense fer servir costa més que una en ús
Discos persistents orfes S'esborra la VM sense marcar el disc per esborrar 0,04-0,17 €/GB/mes
Instantànies antigues Es fan i no caduquen Acumulatiu
Imatges de contenidor antigues Cada compilació en deixa una Creix amb el pipeline
Endpoints de Vertex AI oblidats Es desplega un model per provar Alt: la màquina corre 24×7
Clústers de desenvolupament encesos Es creen per a una prova Molt alt
Entorns de Composer No escalen a zero ~280 €/mes
Balancejadors sense backends Es prova i s'abandona ~18 €/mes cadascun
Buckets de dades temporals alpinashop-dataflow acumula fitxers de staging Creix indefinidament
Subscripcions de Pub/Sub sense consumidor Retenen missatges fins a caducar Emmagatzematge

L'script d'auditoria de fantasmes

#!/usr/bin/env bash
# auditoria-fantasmas.sh — busca recursos que costen i no serveixen
set -uo pipefail
PROYECTOS=(alpinashop-prod alpinashop-dev alpinashop-datos alpinashop-cicd alpinashop-red)

for P in "${PROYECTOS[@]}"; do
  echo "############ $P ############"

  echo "--- IP estatiques reservades i NO usades (~7 EUR/mes cadascuna) ---"
  gcloud compute addresses list --project="$P" \
    --filter="status:RESERVED" --format="table(name, region, address)"

  echo "--- Discos persistents sense adjuntar ---"
  gcloud compute disks list --project="$P" \
    --filter="-users:*" --format="table(name, zone, sizeGb, type)"

  echo "--- Instantanies de mes de 180 dies ---"
  gcloud compute snapshots list --project="$P" \
    --filter="creationTimestamp<$(date -u -d '180 days ago' +%Y-%m-%d)" \
    --format="table(name, diskSizeGb, creationTimestamp)"

  echo "--- Endpoints de Vertex AI (comprovar si es fan servir) ---"
  gcloud ai endpoints list --project="$P" --region=europe-west1 \
    --format="table(displayName, createTime)" 2>/dev/null

  echo "--- Regles de reenviament: balancejadors, ~18 EUR/mes cadascun ---"
  gcloud compute forwarding-rules list --project="$P" \
    --format="table(name, region, IPAddress, target)"

  echo "--- Clusters de GKE ---"
  gcloud container clusters list --project="$P" \
    --format="table(name, location, status, currentNodeCount)" 2>/dev/null

  echo "--- Entorns de Cloud Composer (~280 EUR/mes cadascun) ---"
  gcloud composer environments list --project="$P" --locations=europe-west1 \
    --format="table(name, state)" 2>/dev/null

  echo "--- Instancies de Cloud SQL aturades (continuen pagant disc) ---"
  gcloud sql instances list --project="$P" \
    --filter="state!=RUNNABLE" --format="table(name, state, settings.tier)"

  echo "--- Imatges de contenidor de mes de 90 dies ---"
  gcloud artifacts docker images list \
    "europe-west1-docker.pkg.dev/$P/alpinashop" --include-tags \
    --filter="createTime<$(date -u -d '90 days ago' +%Y-%m-%d)" \
    --format="table(package, version, createTime)" 2>/dev/null
  echo
done

Executa'l el primer dilluns de cada mes. És mitja hora que a AlpinaShop va trobar, la primera vegada, 430 € mensuals.

I perquè els fantasmes no tornin, polítiques automàtiques:

# Caducitat automatica d imatges antigues a Artifact Registry
gcloud artifacts repositories update alpinashop \
  --location=europe-west1 \
  --update-labels=limpieza=activa

# Politica de neteja: esborrar sense etiqueta i amb mes de 30 dies,
# conservant sempre les 10 versions mes recents
gcloud artifacts repositories set-cleanup-policies alpinashop \
  --location=europe-west1 --policy=politica-limpieza.json
[
  {
    "name": "borrar-antiguas-sin-etiqueta",
    "action": {"type": "Delete"},
    "condition": {"tagState": "UNTAGGED", "olderThan": "30d"}
  },
  {
    "name": "conservar-recientes",
    "action": {"type": "Keep"},
    "mostRecentVersions": {"keepCount": 10}
  }
]

  1. El cas complet d'AlpinaShop: abans i després

La factura de juliol: 1.058 €

Servei € Comentari
Cloud Composer 280 🔴 Entorn d'avaluació de 04-06, mai esborrat
Cloud SQL (alpinashop-pedidos HA + rèplica) 150 HA regional + rèplica d'informes
Vertex AI (endpoint) 140 🔴 Endpoint del recomanador desplegat «per provar»
GKE Autopilot 120 Clúster del catàleg
Dataflow 90 Feina de comandes en streaming
BigQuery 75 15 emmagatzematge + 60 consultes
Compute Engine (MIG) 50 2 × e2-medium 24×7
Cloud Logging / Monitoring 45 Retenció per defecte, sense exclusions
Egress de xarxa 35 Sortida a internet i entre zones
Cloud Storage 25 4 buckets, sense cicle de vida
Balancejador + IP 20
Cloud Build 15
Pub/Sub 5
Secret Manager + KMS 5
Cloud Functions 3 procesar-imagen-producto
Total 1.058 €

Les dues troballes que la Marta no va saber explicar són les dues primeres files en vermell: 420 € al mes, el 40 % de la factura, en dos recursos que no donaven valor a ningú. El de Composer portava quatre mesos; l'endpoint de Vertex AI, tres. Cost acumulat del despistament: més de 1.500 €.

I el detall que ho fa dolorós: DA-002 va decidir expressament que les recomanacions es farien per lots i no amb un endpoint 24×7. La decisió estava escrita i era correcta. El que va faltar va ser esborrar l'endpoint de la prova.

Una decisió d'arquitectura només estalvia diners si algú executa la part de «i ara apaga l'altre».

La factura després: 425 €

Servei Abans Després Què s'ha fet
Cloud Composer 280 0 🗑️ Esborrat. Es fa servir Workflows (04-06)
Vertex AI 140 8 🗑️ Endpoint eliminat; prediccions per lots (DA-002)
GKE Autopilot 120 0 🗑️ Retirat després de 07-02
Cloud SQL 150 105 Dimensionat + compromís a 1 any sobre la part estable
Dataflow 90 55 Treballadors secundaris spot + dimensionat
BigQuery 75 38 Particionat + clustering + require_partition_filter
Compute Engine 50 0 🗑️ MIG apagat (07-02)
Cloud Run 0 7 ✨ Substitueix el MIG
Logging / Monitoring 45 28 Exclusions de soroll i retenció ajustada (06-06)
Egress 35 22 CDN + compressió
Cloud Storage 25 14 Cicle de vida i límit de versions
Balancejador + IP 20 20 Sense canvi
Cloud Build 15 12 Neteja d'imatges antigues
Pub/Sub 5 5
Secret Manager + KMS 5 5
Cloud Functions 3 3
Cloud VPN HA (2 túnels) 0 60 ✨ Nou: enllaç a Sabadell (07-03)
VPC Flow Logs 0 8 ✨ Nou: visibilitat de xarxa
Registres d'accés a dades 0 35 ✨ Nou: requisit de 07-04
Total 1.058 € 425 € −60 %

La lectura honesta

El que es va estalviar de debò, per ordre d'impacte:

  1. Esborrar dos recursos oblidats: 412 €. El 65 % de l'estalvi total va sortir de mitja hora executant un script d'auditoria. Cap optimització tècnica no s'acosta a aquest retorn.
  2. Decisions d'arquitectura: 163 €. GKE i el MIG retirats a favor de Cloud Run. Però compte a atribuir-ho tot aquí: Cloud Run no es va triar per estalviar, es va triar per feina operativa i portabilitat (DA-001). L'estalvi va ser una conseqüència agradable, no l'objectiu.
  3. Optimitzacions de configuració: 76 €. Particionat, cicle de vida, spot, exclusions de registres. Feina real d'enginyeria per a un terç de l'estalvi que va donar esborrar dues coses.
  4. Compromís d'ús: 20 €. Modest a propòsit. Només sobre Cloud SQL, que és l'única cosa que no canviarà d'arquitectura en un any.

El que NO es va estalviar, i per què:

Concepte € Per què es manté
Balancejador global + IP 20 És el preu de tenir CDN, WAF, TLS gestionat i IP anycast. Ara és el 5 % de la factura i el 74 % del cost del catàleg: no es toca
Cloud SQL HA 105 L'alta disponibilitat costa el doble. Es paga a propòsit (07-06)
Rèplica d'informes Inclosa Evita que les consultes de la Lucía afectin les comandes. Val el seu preu
Egress 22 Servir la botiga té un cost. Ja està optimitzat amb CDN

El que es va decidir gastar de MÉS, a propòsit — i aquesta és la part que gairebé mai no apareix en un cas d'estudi:

Concepte € Per què
Cloud VPN HA, dos túnels 60 Un de sol costaria la meitat i seria un punt únic de fallada. Es paga la redundància
VPC Flow Logs 8 Sense ells no es pot investigar un incident de xarxa
Registres d'accés a dades 35 Deute #5 de 07-04. És un requisit legal de facto: sense ells no es pot acotar una bretxa

103 € al mes de despesa nova i deliberada en fiabilitat i seguretat. Sense aquest matís, el titular «hem baixat un 60 % la factura» seria una mitja veritat. La veritat completa és: es van eliminar 736 € de malbaratament, es van optimitzar 260 € i es van reinvertir 103 € en coses que calien.

Optimitzar cost no és retallar. És deixar de pagar el que no aporta per poder pagar el que sí.

Cost unitari: la mètrica que de debò importa

El número absolut enganya. El que cal seguir és el cost per unitat de negoci:

Mètrica Juliol Després
Factura mensual 1.058 € 425 €
Comandes al mes 1.200 1.200
Cost per comanda 0,88 € 0,35 €
Cost com a % de l'ingrés (tiquet ~65 €) 1,4 % 0,55 %

Aquesta mètrica és la que cal presentar a direcció, per dos motius. Primer, perquè fa comparables mesos diferents: si a l'octubre la factura puja a 600 € però es processen 3.000 comandes, el cost per comanda baixa a 0,20 € i la pujada és una bona notícia. I segon, perquè converteix la infraestructura de «una despesa que cal retallar» en «un cost variable del negoci», que és el que realment és.

  1. Eines: Recommender, Active Assist i la calculadora

Eina Per a què
Recommender Recomanacions per tipus de recurs: màquines, discos, IP, IAM, Cloud SQL
Active Assist El paraigua que agrupa Recommender, Insights i les prediccions
Pricing Calculator Estimar abans de crear
Detecció d'anomalies Inclosa a la consola de facturació, gratuïta
Informes de facturació Agrupació i filtratge sense SQL
Cloud Billing API Automatitzar consultes i preus
# Totes les recomanacions de cost d un projecte, d un cop d ull
for R in google.compute.instance.MachineTypeRecommender \
         google.compute.disk.IdleResourceRecommender \
         google.compute.address.IdleResourceRecommender \
         google.compute.image.IdleResourceRecommender \
         google.cloudsql.instance.IdleRecommender \
         google.cloudsql.instance.OverprovisionedRecommender; do
  echo "=== $R ==="
  gcloud recommender recommendations list \
    --project=alpinashop-prod --location=europe-west1-b --recommender="$R" \
    --format="table(description, primaryImpact.costProjection.cost.units)" 2>/dev/null
done

Consell sobre la calculadora: fes-la servir abans de crear, no després de la factura. Deu minuts estimant el cost d'una arquitectura eviten la sorpresa del mes següent, i sobretot permeten comparar dos dissenys en euros i no en intuïcions.

Errors Habituals i Consells

  • Optimitzar abans de mesurar. S'acaba afinant el visible mentre 280 € al mes se'n van en una cosa que ningú no sabia que existia.
  • Oblidar l'array credits a les consultes de facturació. Les xifres surten inflades i ningú no entén per què no quadren amb la consola.
  • Consultar la taula de facturació sense filtre de partició. La consulta que analitza el teu cost et costa diners.
  • Creure que un pressupost limita la despesa. Només avisa. Frenar cal automatitzar-ho, i amb compte.
  • Automatitzar l'apagada de producció per pressupost. Un pic de vendes apagaria la botiga el millor dia de l'any.
  • Comprometre's a 1 o 3 anys abans d'estabilitzar l'arquitectura. Si migres després, pagues pel que ja no fas servir.
  • Comprometre el 100 % del consum. Només la part estable, un 50-70 % del mínim històric.
  • Posar Archive a dades que es consulten cada dos mesos. Els càrrecs per recuperació anticipada ho fan més car que Standard.
  • Taules de BigQuery sense require_partition_filter. Un SELECT * sense filtre pot costar més que un mes de servidors.
  • Versionatge de buckets sense límit de versions. El bucket creix indefinidament i ningú no el mira.
  • Etiquetes amb valors lliures. equipo: varios destrueix l'anàlisi. Conjunt tancat i validació a Terraform.
  • Reservar IP estàtiques «per si de cas». Una IP reservada sense fer servir costa més que una en ús.
  • Esborrar una VM sense marcar el disc per a esborrat automàtic. El disc orfe continua facturant.
  • Consell: executa l'script de fantasmes el primer dilluns de cada mes. És l'activitat de més retorn per hora de tota la lliçó.
  • Consell: segueix el cost per unitat de negoci, no l'absolut. És l'única cosa que fa comparables mesos diferents.
  • Consell: la reunió mensual de 30 minuts amb el tauler obert és la pràctica de FinOps més rendible que existeix.
  • Consell: posa --max-instances a tot el que escali. És un tallafoc de cost (07-02).
  • Consell: fes servir la calculadora abans de crear. Comparar dos dissenys en euros és millor que discutir-los en intuïcions.

Exercicis

Exercici 1 — Investigar una pujada de factura

La factura d'AlpinaShop ha passat de 425 € a 690 € d'un mes a un altre. No hi ha hagut campanya ni desplegaments grans. Direcció pregunta què ha passat.

Escriu la seqüència completa de consultes SQL sobre l'exportació de facturació que faries servir per arribar a la causa arrel, explicant què busques a cada pas i com interpretes el resultat. Indica almenys quatre causes plausibles i com distingiries entre elles amb dades.

Exercici 2 — Optimitzar l'entorn de dades

El projecte alpinashop-datos costa 250 € al mes:

  • BigQuery consultes: 95 € (sota demanda)
  • BigQuery emmagatzematge: 40 €
  • Dataflow: 70 €
  • Cloud Storage (alpinashop-datalake): 45 €

Dades addicionals: la taula eventos_web té 1,2 TB, no està particionada i es consulta unes 200 vegades al dia des d'un tauler de control. La feina de Dataflow processa comandes en streaming les 24 hores, tot i que les comandes arriben gairebé totes entre les 9:00 i les 23:00. El data lake té 3 TB, dels quals el 80 % són fitxers de més d'un any que només es consulten per a auditories anuals.

Proposa un pla d'optimització amb l'estalvi estimat de cada mesura, l'esforç, i el risc associat. Ordena'l per retorn.

Exercici 3 — Presentar el cas a direcció

Prepara la presentació de la Marta al consell d'AlpinaShop sobre la gestió de costos de l'últim trimestre. Ha d'incloure: què s'ha aconseguit, com s'ha aconseguit, què es gasta de més a propòsit, quina és la mètrica que se seguirà a partir d'ara, i què es demana per al trimestre següent.

Escriu-ho com li ho diria a un consell que no és tècnic. Màxim una pàgina. I explica després quines tres decisions de comunicació has pres i per què.

Solucions

Solució 1 — Investigar una pujada de factura

Pas 1 — Localitzar el servei i el moment. Mai no es comença pel detall: primer s'acota.

SELECT
  service.description AS servei,
  ROUND(SUM(CASE WHEN DATE(usage_start_time) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
                 THEN cost END), 2) AS mes_actual,
  ROUND(SUM(CASE WHEN DATE(usage_start_time) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 60 DAY)
                                                 AND DATE_SUB(CURRENT_DATE(), INTERVAL 31 DAY)
                 THEN cost END), 2) AS mes_anterior
FROM `alpinashop-datos.facturacion.gcp_billing_export_resource_v1_XXXXXX`
WHERE DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 60 DAY)
GROUP BY servei
HAVING mes_actual > 1
ORDER BY (mes_actual - IFNULL(mes_anterior, 0)) DESC

La primera fila dona el servei responsable de la major part dels 265 €.

Pas 2 — Esbrinar la forma temporal. És el pas que més informació aporta i el que gairebé ningú no fa:

SELECT
  DATE(usage_start_time) AS dia,
  ROUND(SUM(cost), 2)    AS cost
FROM `alpinashop-datos.facturacion.gcp_billing_export_resource_v1_XXXXXX`
WHERE DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 60 DAY)
  AND service.description = 'SERVICIO_SOSPECHOSO'
GROUP BY dia
ORDER BY dia

La forma de la corba és el diagnòstic:

Forma Significat
Esglaó que comença un dia i es manté S'ha creat un recurs permanent. Fantasma o desplegament
Pic d'un o dos dies Una feina puntual, una consulta, una prova
Rampa creixent Alguna cosa que acumula: emmagatzematge, registres, instantànies
Dents de serra més altes Augment de trànsit o de freqüència d'un procés

Pas 3 — Baixar a SKU i a recurs.

SELECT
  sku.description     AS sku,
  resource.name       AS recurs,
  ROUND(SUM(cost), 2) AS cost,
  ROUND(SUM(usage.amount), 2) AS us,
  ANY_VALUE(usage.unit) AS unitat
FROM `alpinashop-datos.facturacion.gcp_billing_export_resource_v1_XXXXXX`
WHERE DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
  AND service.description = 'SERVICIO_SOSPECHOSO'
GROUP BY sku, recurs
ORDER BY cost DESC LIMIT 20

Pas 4 — Correlacionar amb els canvis. Amb la data de l'esglaó:

FECHA="2026-09-14"
gcloud logging read "
  protoPayload.methodName=~'(create|insert|Create|Insert)'
  AND timestamp>=\"${FECHA}T00:00:00Z\"
  AND timestamp<=\"${FECHA}T23:59:59Z\"" \
  --project=alpinashop-datos --limit=100 \
  --format="table(timestamp, protoPayload.methodName,
                  protoPayload.authenticationInfo.principalEmail,
                  protoPayload.resourceName)"

Les quatre causes plausibles i com distingir-les:

Causa Signatura a les dades Confirmació
Recurs nou oblidat Esglaó net, mateix import cada dia, un sol resource.name Registres d'auditoria del dia de l'esglaó; script de fantasmes
Consulta de BigQuery desbocada Pic al SKU "Analysis"; usage.amount en TB desigual INFORMATION_SCHEMA.JOBS_BY_PROJECT ordenat per total_bytes_billed
Creixement d'emmagatzematge o registres Rampa suau, sense esglaó; SKU de "Storage" Mida del bucket o volum d'ingesta de Logging
Augment de trànsit real Puja egress i Cloud Run i peticions del balancejador alhora Mètriques de negoci: si pugen les comandes, és bona notícia

La quarta mereix el matís que dona criteri: una pujada proporcional a l'activitat de negoci no és un problema de cost. Es verifica amb la mètrica unitària de l'apartat 12: si el cost per comanda es manté, el negoci ha crescut; si es dispara, hi ha ineficiència.

Per al cas de BigQuery, la consulta definitiva:

SELECT
  user_email,
  DATE(creation_time) AS dia,
  COUNT(*) AS consultes,
  ROUND(SUM(total_bytes_billed)/POW(1024,4), 2) AS tib_facturats,
  ROUND(SUM(total_bytes_billed)/POW(1024,4) * 5.5, 2) AS cost_estimat_eur
FROM `alpinashop-datos.region-eu.INFORMATION_SCHEMA.JOBS_BY_PROJECT`
WHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  AND job_type = 'QUERY' AND state = 'DONE'
GROUP BY user_email, dia
ORDER BY tib_facturats DESC LIMIT 20

I així que s'identifiqui la causa, l'acció no és només corregir: és posar el control que impedeix que es repeteixi — require_partition_filter si va ser una consulta, l'script mensual si va ser un fantasma, una alerta d'anomalia si va ser una rampa.

Solució 2 — Optimitzar l'entorn de dades

Anàlisi prèvia. Els quatre conceptes tenen causes molt diferents i l'ordre d'atac no és l'ordre de la llista.


Mesura 1 — Particionar i agrupar eventos_web. (Estalvi: ~75 €/mes · Esforç: 4 h · Risc: baix)

Una taula d'1,2 TB sense particionar, consultada 200 vegades al dia, és la definició del problema. Cada consulta llegeix 1,2 TB llevat que BigQuery pugui podar, i sense partició no pot.

CREATE OR REPLACE TABLE `alpinashop-datos.alpinashop_analitica.eventos_web_opt`
PARTITION BY DATE(momento)
CLUSTER BY tipo_evento, pagina
OPTIONS (
  partition_expiration_days = 400,
  require_partition_filter  = TRUE
)
AS SELECT * FROM `alpinashop-datos.alpinashop_analitica.eventos_web`;

Estimació: el tauler de control consulta típicament els últims 30 dies → d'1,2 TB a uns 30 GB per consulta, i el clustering retalla més. Reducció realista del 80-85 % del cost de consultes: 95 € → ~20 €.

Risc i mitigació: require_partition_filter trencarà les consultes existents sense filtre. Es desplega en dues fases: crear la taula optimitzada, migrar el tauler de control i les consultes desades, verificar, i només llavors substituir l'original. Mai a l'inrevés.

Bonus gratuït: partition_expiration_days = 400 elimina sol els esdeveniments de més de 400 dies, cosa que a més redueix l'emmagatzematge amb el temps.


Mesura 2 — Cicle de vida del data lake. (Estalvi: ~28 €/mes · Esforç: 1 h · Risc: molt baix)

2,4 TB (el 80 % de 3 TB) són de més d'un any i només es llegeixen en auditories anuals. Estan a Standard.

lifecycle_rule {
  condition { age = 90 }
  action { type = "SetStorageClass" storage_class = "NEARLINE" }
}
lifecycle_rule {
  condition { age = 365 }
  action { type = "SetStorageClass" storage_class = "COLDLINE" }
}
lifecycle_rule {
  condition { age = 1095 }
  action { type = "SetStorageClass" storage_class = "ARCHIVE" }
}

Càlcul: 2,4 TB passant de Standard a Coldline (~0,3×) estalvia al voltant del 70 % de la seva part. 45 € → ~17 €.

Per què Coldline i no Archive per al tram d'un any: amb recuperació mínima de 365 dies, Archive castiga qualsevol lectura anticipada. Una auditoria anual és just al límit i el càrrec es podria disparar. Coldline (90 dies) és el punt segur; Archive es reserva per al de més de tres anys, que ja ningú no tocarà.


Mesura 3 — Dataflow: repensar el streaming. (Estalvi: ~35 €/mes · Esforç: 1-2 dies · Risc: mitjà)

Una feina de streaming 24×7 quan les comandes arriben entre les 9:00 i les 23:00. Tres opcions, i l'elecció depèn d'un requisit de negoci, no tècnic:

Opció Estalvi Impacte
(a) Treballadors secundaris spot + dimensionar ~25 € Cap. Començar per aquí
(b) Streaming només de 8:00 a 24:00; Pub/Sub reté a la nit ~25 € Les comandes nocturnes apareixen al matí
(c) Substituir per procés per lots cada 15 min ~50 € Latència de 15 min a l'analítica

La pregunta que decideix: algú mira les dades de comandes en temps real? A AlpinaShop, la resposta honesta és no: la Lucía mira el tauler de control al matí. L'opció (c) és la correcta i és la que més estalvia, però exigeix reescriure el pipeline i per això es planteja després de (a), que és gratis.

Pla realista: aplicar (a) aquesta setmana (~25 €), i avaluar (c) el trimestre següent.


Mesura 4 — Emmagatzematge de BigQuery a llarg termini. (Estalvi: ~8 €/mes · Esforç: 30 min · Risc: nul)

BigQuery aplica automàticament un preu d'emmagatzematge a llarg termini (~50 % menys) a les particions no modificades en 90 dies. La trampa: qualsevol UPDATE sobre una partició reinicia el comptador.

SELECT table_name, partition_id,
       ROUND(total_logical_bytes/POW(1024,3), 2) AS gib,
       last_modified_time
FROM `alpinashop-datos.alpinashop_analitica.INFORMATION_SCHEMA.PARTITIONS`
WHERE total_logical_bytes > 0
ORDER BY total_logical_bytes DESC

Si apareixen particions antigues amb last_modified_time recent, hi ha un procés que les reescriu innecessàriament. Corregir-ho és gratis i el descompte s'aplica sol.

També convé avaluar el model de facturació físic davant del lògic: amb dades molt comprimibles pot sortir més barat, encara que el descompte a llarg termini funciona diferent. Es compara amb INFORMATION_SCHEMA abans de canviar.


Pla ordenat per retorn:

Ordre Mesura Estalvi Esforç €/hora
1 Cicle de vida del data lake 28 € 1 h 28
2 Particionar i agrupar 75 € 4 h 19
3 Emmagatzematge a llarg termini 8 € 0,5 h 16
4 Dataflow spot (a) 25 € 4 h 6
5 Dataflow a lots (c) +25 € 12 h 2

Resultat: 250 € → ~115 €, un 54 % menys, amb les quatre primeres mesures en unes dues jornades de feina.

I la mesura que no costa res i que cal aplicar el primer dia, abans que cap de les anteriors:

gcloud alpha services quota update \
  --service=bigquery.googleapis.com \
  --consumer=projects/alpinashop-datos \
  --metric=bigquery.googleapis.com/quota/query/usage \
  --unit=1/d/{project}/{user} --value=549755813888     # 512 GiB/usuari/dia

Perquè tot l'anterior optimitza el consum actual, però res no impedeix que demà algú escrigui una consulta que costi 300 € en una tarda. La quota és l'únic control que ho impedeix.

Solució 3 — Presentar el cas a direcció


Gestió del cost de la plataforma tecnològica — Informe del tercer trimestre Marta Ruiz, responsable d'infraestructura

Resum. El cost mensual de la nostra plataforma tecnològica ha passat de 1.058 € a 425 €, un 60 % menys, sense reduir cap capacitat i havent afegit mesures de seguretat i de continuïtat que abans no teníem. En termes de negoci, el cost tecnològic per comanda ha baixat de 0,88 € a 0,35 €: d'un 1,4 % a un 0,55 % de l'import mitjà d'una comanda.

D'on ve l'estalvi. Dues terceres parts no vénen de negociar millor ni de retallar: vénen d'haver trobat dos serveis encesos que ningú no feia servir —una eina que vam avaluar a la primavera i un model de recomanacions que vam provar a l'estiu— i que junts costaven 420 € al mes. Cap persona no va decidir gastar-ho; simplement ningú no va decidir apagar-ho. Ja està corregit, i des d'aquest mes executem una revisió automàtica el primer dilluns de cada mes perquè no torni a passar. La lliçó és que al núvol la despesa creix per omissió, no per decisió, i això exigeix una rutina.

El terç restant són millores tècniques: hem traslladat la botiga a una tecnologia que només cobra quan hi ha visites —de matinada no paguem res—, hem reorganitzat les dades perquè les consultes del tauler de control llegeixin el just, i hem mogut els fitxers antics a un emmagatzematge més barat.

El que gastem de més, a propòsit. Vull que consti explícitament que 103 € al mes són despesa nova i deliberada: la connexió amb la botiga de Sabadell està duplicada perquè un tall no ens deixi sense inventari, i hem activat el registre de qui accedeix a les dades de clients, que és el que ens permetria respondre davant de l'Agència de Protecció de Dades si algun dia hi hagués un incident. Sense aquest registre no podríem acotar què va passar, i això és una exposició legal, no només tècnica. Optimitzar el cost no significa retallar en fiabilitat ni en compliment normatiu: significa deixar de pagar el que no aporta per poder pagar el que sí.

La mètrica que seguirem. A partir d'ara informarem del cost per comanda, no del total. És important entendre per què: a la campanya de tardor la factura pujarà, i això serà una bona notícia. Si venem el triple, el cost per comanda baixarà encara que l'import total creixi. El número absolut no diu res per si sol; l'unitari sí.

El que demanem per al pròxim trimestre. Gens de pressupost addicional. Només dues decisions:

  1. Autorització per a un compromís a un any sobre la base de dades, que és l'única cosa que sabem del cert que no canviarà. Estalvia al voltant d'un 30 % d'aquesta partida a canvi de comprometre'ns.
  2. Mitja hora al mes de direcció per revisar el tauler de costos amb nosaltres. És la mesura més barata i més eficaç de totes: el que es mira en grup no es descontrola.

Les tres decisions de comunicació, i per què:

1. Començar pel número de negoci, no pel tècnic. El titular no és «hem migrat a Cloud Run»: és «el cost per comanda ha baixat de 0,88 € a 0,35 €». Un consell no pot avaluar una decisió d'arquitectura, però sí que sap perfectament què significa que cada comanda costi la meitat. Traduir a la unitat del negoci no és simplificar: és parlar en la moneda en què ells decideixen.

2. Explicar la fallada abans que la preguntin. Es podria haver presentat l'estalvi com a mèrit tècnic i callar que 420 € se n'anaven en dos recursos oblidats. Dir-ho té tres efectes que compensen de sobres la incomoditat: dona credibilitat a tota la resta de l'informe, justifica la rutina mensual —que sense l'anècdota semblaria burocràcia innecessària— i protegeix de la pregunta incòmoda d'aquí a sis mesos. Un informe que només explica encerts es creu a mitges.

3. Anticipar la mala notícia i reenquadrar-la. La factura pujarà en campanya. Si això s'explica després, sembla una excusa; explicat abans, és previsió — i a més ensenya el consell a llegir la mètrica correcta. És la mateixa raó per la qual la despesa nova de 103 € es declara de manera destacada en lloc d'amagar-la en el net: si direcció descobreix pel seu compte una despesa que no se li va explicar, perd la confiança en tot l'informe, per molt bo que sigui el resultat.

I una quarta que no es veu però hi és: no es demanen diners, es demanen decisions. Un informe que acaba demanant pressupost es llegeix amb desconfiança; un que acaba demanant mitja hora al mes i una autorització que estalvia, es llegeix com a gestió.

Conclusió

La factura d'AlpinaShop ha deixat de ser una sorpresa mensual per convertir-se en una dada que s'entén, s'atribueix i es governa.

Saps per què el núvol sorprèn: cost variable, decisions tècniques amb efecte econòmic, absència de fre natural i desfasament temporal — amb la primera regla gravada: el problema gairebé mai no és que una cosa sigui cara, sinó que ningú no sabia que estava encesa.

Saps llegir una factura: servei, SKU i ús, amb la constatació que una VM no és un cost sinó cinc SKU diferents. Distingeixes els descomptes que s'apliquen sols —ús sostingut— dels que cal contractar, i saps que el sostingut explica per què apagar a les nits estalvia menys del que l'aritmètica promet.

Tens l'exportació a BigQuery configurada amb cost detallat —sense el qual saps que Storage costa 25 € però no quin bucket— i les sis consultes que responen les preguntes reals, amb els dos errors clàssics evitats: oblidar l'array credits i consultar sense filtre de partició. Inclosa la consulta més incòmoda, la de la despesa sense etiquetar, que a AlpinaShop va revelar que el 36 % de la factura no tenia amo.

Entens FinOps —informar, optimitzar, operar— amb l'ordre que importa: primer mesurar, després tallar. I el model de responsabilitat per a una empresa petita, amb la pràctica de més retorn de tota la disciplina: una reunió de trenta minuts al mes amb el tauler obert.

Saps muntar pressupostos amb la regla de previsió que avisa el dia 8 i no el 26, uns quants en lloc d'un de sol, i l'acció automàtica per Pub/Sub i funció — amb els tres advertiments: no apagar mai producció, desvincular la facturació és destructiu, i els missatges arriben duplicats. I saps que l'únic fre dur són les quotes, incloses les de bytes de BigQuery, que cal posar sempre.

Tens les nou palanques ordenades per retorn, amb la primera molt per davant de totes: eliminar el que no es fa servir. I les altres amb les seves trampes dites — dimensionar segons l'agost quan el pic és a l'octubre, comprometre's abans d'estabilitzar l'arquitectura, posar Archive a dades que es llegeixen cada dos mesos, versionatge sense límit de versions. Amb require_partition_filter assenyalada com l'opció més rendible de tot BigQuery: noranta vegades més barata la mateixa consulta.

Saps on s'amaga el cost del trànsit i tens la disciplina d'etiquetatge convertida en control real, amb validacions de Terraform que fan fallar el plan si falta una etiqueta o el seu valor no és dins del conjunt tancat — prevenció al punt de creació, que venç sempre a perseguir orfes després.

Caces anomalies amb estadística i fantasmes amb un script que cal executar el primer dilluns de cada mes: IP reservades que costen més que les usades, discos orfes, instantànies eternes, endpoints de Vertex AI, clústers de proves, entorns de Composer i balancejadors sense backends.

I tens el cas complet: 1.058 € desglossats amb dues partides en vermell que sumaven el 40 % de la factura i portaven mesos allà, davant de 425 € després. Amb la lectura honesta que és el més valuós de l'apartat: el 65 % de l'estalvi va sortir de mitja hora executant un script, l'arquitectura va aportar menys del que sembla —i a més Cloud Run no es va triar per estalviar—, les optimitzacions tècniques van donar un terç del que va donar esborrar dues coses, i 103 € al mes són despesa nova i deliberada en redundància, visibilitat de xarxa i registres d'accés a dades. Més la mètrica que cal presentar d'ara endavant: el cost per comanda, que converteix la infraestructura de despesa a retallar en cost variable del negoci.

De tot això queda una frase que resumeix la lliçó sencera i que enllaça amb el que ve:

Optimitzar cost no és retallar. És deixar de pagar el que no aporta per poder pagar el que sí.

I aquesta frase té una contrapartida que cal dir amb la mateixa claredat. En aquesta lliçó s'ha decidit pagar l'alta disponibilitat de Cloud SQL sense discutir-la, s'han duplicat els túnels VPN sabent que un costaria la meitat, i s'ha acceptat que el balancejador global —que ara és el 74 % del cost del catàleg— no es toca. Tres decisions de fiabilitat preses per intuïció, sense un objectiu que les justifiqui amb números.

Perquè AlpinaShop encara no ha respost la pregunta més bàsica de totes: què significa exactament que la botiga «funcioni bé»? Hi ha alertes des de 06-04, però una alerta diu que alguna cosa ha passat, no si el servei està complint el que promet. No hi ha un objectiu declarat, no hi ha manera de saber si 43 minuts de caiguda al mes són acceptables o inadmissibles, no hi ha criteri per decidir si es pot desplegar un divendres, i —el més greu, assenyalat ja com a deute crític a 07-04— ningú no ha comprovat mai que les còpies de seguretat es puguin restaurar.

La lliçó següent respon a tot això amb números: SLI, SLO, pressupost d'error, arquitectures d'alta disponibilitat per nivells, modes de fallada i la seva mitigació, i un pla de recuperació de desastres amb RTO i RPO — inclòs l'assaig de restauració d'alpinashop-pedidos que porta massa temps pendent.

Curs de Google Cloud Platform (GCP)

Mòdul 1: Introducció a Google Cloud Platform

Mòdul 2: Serveis principals de GCP

Mòdul 3: Xarxes i seguretat

Mòdul 4: Dades i anàlisi

Mòdul 5: Aprenentatge automàtic i IA

Mòdul 6: DevOps i monitoratge

Mòdul 7: Temes avançats de GCP

Mòdul 8: Projecte final

© Copyright 2026. Tots els drets reservats