La lezione 65 ha inquadrato la bolletta del cloud come un iceberg, con lo storage come una delle voci più grandi sotto la linea di galleggiamento. Questa lezione prende quella voce dello storage e ci scava dentro. Tre leve portano a casa la maggior parte dei risparmi: distribuire i dati su storage class diverse in base alla frequenza d’accesso (tiering), automatizzare il movimento con lifecycle policy, e compattare i piccoli file in file più grandi così che il numero di file smetta di trainare i costi di richieste e metadata. Una quarta leva, semplicemente cancellare ciò che non serve, è quella che viene trascurata perché nessuno è pagato per cancellare cose.
La lezione si appoggia a S3 perché S3 è l’object store dominante e perché AWS ha il pricing pubblico più dettagliato. Le stesse forme valgono per i tier di Azure Blob Storage (Hot, Cool, Cold, Archive) e per le storage class di Google Cloud Storage (Standard, Nearline, Coldline, Archive). I nomi delle classi cambiano; il modello è identico.
La realtà del 90/10
Una costante nei workload analitici è che circa il 10 percento dei dati raccoglie il 90 percento degli accessi. La settimana più fresca di eventi guida la maggior parte delle dashboard. L’ultimo artefatto del modello prende tutto il traffico di inference. Le fatture dello scorso trimestre vengono interrogate per la reportistica di fine trimestre e poi tacciono. I dati dell’anno precedente sono per lo più dormienti, interrogati solo per confronti annuali o estrazioni di compliance.
Questa è la base del tiering. Tenere il 90 percento dormiente sulla stessa storage class del 10 percento hot significa pagare tariffe premium per dati cold. L’argomento economico per il tiering è semplice: le storage class cold sono dal 50 al 90 percento più economiche dello standard tier, i dati dormienti non hanno bisogno di accesso in millisecondi, e la piccola tassa d’accesso per il recupero raro viene schiacciata dai risparmi sullo storage del grosso dei dati.
La trappola è che i risparmi dipendono dal pattern d’accesso effettivo che combacia con l’assunzione. Un workload che si rivela scansionare tutti i dati dell’anno scorso una volta al mese per un report regolatorio può finire per pagare di più sotto una policy cold-tier di quanto pagherebbe su Standard, perché le retrieval charge e i costi di richiesta divorano i risparmi sullo storage. Il primo lavoro di una strategia di tiering è misurare gli accessi, non assumerli.
Le storage class di S3
AWS espone un reticolo di storage class ottimizzate per pattern d’accesso diversi. Il pricing è approssimativo e varia per region; i numeri qui sotto usano i list price di US East 1 a metà 2026 (https://aws.amazon.com/s3/pricing/, consultato 2026-05-01) per un confronto relativo, non per fare budget assoluti.
Standard. Circa 2,3 centesimi per gigabyte al mese. Il default. Accesso in millisecondi, SLA di disponibilità al 99,99 percento, durabilità multi-AZ. Il tier giusto per i dati hot.
Intelligent-Tiering. Stesso costo per gigabyte di Standard per il tier ad accesso frequente, con movimento automatico verso tier meno costosi (Infrequent Access, Archive Instant Access, Archive Access, Deep Archive Access) in base agli accessi osservati. Si applica un piccolo monitoring charge per oggetto. Il tier giusto quando i pattern d’accesso sono imprevedibili o variano tra oggetti, perché S3 fa il lavoro di tiering al posto tuo.
Standard-IA. Circa 1,25 centesimi per gigabyte al mese, con una retrieval charge per GB di circa 1 centesimo e una durata minima di storage di 30 giorni. Buono per dati interrogati mensilmente ma che hanno ancora bisogno di accesso in millisecondi.
One Zone-IA. Circa 1 centesimo per gigabyte al mese. Stesso modello di retrieval e minimum-duration di Standard-IA, ma i dati vivono in una singola AZ. Accettabile per dati ricreabili (output analitici intermedi, copie secondarie di media) dove il rischio di perdita di una AZ è tollerabile.
Glacier Instant Retrieval. Circa 0,4 centesimi per gigabyte al mese. Recupero in millisecondi, ma con una retrieval charge per GB più alta (circa 3 centesimi per GB) e una durata minima di 90 giorni. Il tier giusto per dati di archivio che devono comunque essere interrogabili a richiesta, come gli archivi di compliance che un auditor potrebbe tirare giù.
Glacier Flexible Retrieval. Circa 0,36 centesimi per gigabyte al mese. Il recupero richiede minuti o ore, con retrieval charge che scalano con la velocità (Expedited, Standard, Bulk). Utile per backup e dati di long tail dove aspettare un’ora per il recupero è accettabile.
Glacier Deep Archive. Circa 0,099 centesimi per gigabyte al mese, il tier più economico su AWS. Il recupero richiede 12 ore o più nel tier standard, più veloce con Bulk Expedited. Il tier giusto per dati tenuti unicamente per compliance, dove la domanda “ce l’hai” conta e “quanto velocemente lo recuperiamo” non conta.
La struttura del pricing è intenzionale: più la tariffa mensile è bassa, più alto è il costo di retrieval e più lunga la durata minima. L’aritmetica che determina il tier giusto per un dato dataset è “qual è la frequenza di retrieval attesa, e a che frequenza il costo di retrieval supera i risparmi sullo storage”.
Lifecycle policy
Le S3 lifecycle policy sono l’automazione che rende il tiering pratico. Una lifecycle rule dice, in forma dichiarativa, “sposta gli oggetti in questo prefix da Standard a Standard-IA dopo 30 giorni, a Glacier Instant Retrieval dopo 90 giorni, a Deep Archive dopo 365 giorni, e cancella dopo 7 anni”. La regola gira da sola con il suo schedule; il team non deve scrivere codice per migrare oggetti tra tier.
flowchart LR
Hot["Hot data<br/>0-30 days<br/>Standard"] --> Warm["Warm data<br/>30-90 days<br/>Standard-IA"]
Warm --> Cold["Cold data<br/>90-365 days<br/>Glacier IR"]
Cold --> Frozen["Archive<br/>1-7 years<br/>Glacier Deep"]
Frozen --> Deleted["Deleted<br/>after 7 years"]
La lifecycle policy è l’intervento sui costi a più alto ROI disponibile su una tipica bolletta S3, perché non richiede modifiche applicative e gira per sempre una volta configurata. La maggior parte dei team che non sono passati da un engagement FinOps non hanno lifecycle policy oppure ne hanno di default che spostano gli oggetti su IA dopo 30 giorni e mai oltre. La versione disciplinata fa camminare i dati attraverso tre o quattro tier in base alle misure d’accesso, e cancella i dati che hanno superato il loro requisito di retention.
Una configurazione comune che cattura la maggior parte dei risparmi su un bucket di analytics:
- Giorni da 0 a 30: Standard. Hot, accesso frequente, interrogato dalle dashboard più recenti.
- Giorni da 30 a 90: Standard-IA. Warm, interrogato occasionalmente per confronti mese su mese.
- Giorni da 90 a 365: Glacier Instant Retrieval. Cold, interrogato per la rara estrazione trimestrale o di compliance.
- Dal giorno 365 in poi: Glacier Deep Archive. Frozen, tenuto per il periodo di retention legale e improbabile da recuperare.
- Dopo il periodo di retention: cancellato.
Le soglie esatte dipendono dal workload. Un team con SLA giornalieri sulla freschezza dei dati probabilmente estende la finestra Standard. Un team con cicli di reporting trimestrali probabilmente estende la finestra Standard-IA così che la query trimestrale colpisca ancora il tier ad accesso in millisecondi. Il pattern è misurare prima, fissare le soglie, e rivisitare ogni anno.
La trappola del costo di retrieval di Glacier
Il modo più comune in cui una strategia di tiering va male è spostare dati in Glacier e poi doverli recuperare. Glacier Flexible Retrieval e Deep Archive hanno entrambi retrieval charge per GB e request charge sostanziali, oltre alla durata minima di storage di 90 o 180 giorni. Un team che sposta un terabyte in Deep Archive e ne recupera la metà una settimana dopo paga lo storage alla tariffa Deep Archive, la early-deletion fee per aver recuperato prima della durata minima, la retrieval charge per GB, e l’egress charge per GB se i dati lasciano AWS. Il totale può superare quello che i dati sarebbero costati su Standard per lo stesso periodo.
Il pattern che innesca questa situazione: arriva un requisito regolatorio, il team si rende conto che i dati archiviati devono essere prodotti per un audit, e il costo di retrieval viene scoperto a posteriori. Il rimedio è modellare il costo di retrieval dentro la decisione di tiering prima di configurare la policy. Una regola pratica utile: se un dataset ha più del 5 percento di probabilità di essere recuperato in un anno, Glacier Instant Retrieval o Standard-IA sono di solito una scelta migliore di Deep Archive.
Parquet compaction
Il tiering delle storage class attacca il lato per-gigabyte della bolletta. Il file count attacca il lato per-request. Le due cose sono correlate: un dataset hot-tier di un milione di Parquet minuscoli costa quasi quanto pochi grossi in storage, ma il numero di richieste, il tempo di listing e l’overhead delle query rendono la versione small-files drasticamente più costosa da usare.
Il “small files problem” emerge in modo naturale nell’ingestion in streaming e nell’ETL incrementale. Ogni micro-batch scrive il proprio file Parquet. Dopo un anno, la tabella consiste di milioni di file mediamente di poche centinaia di kilobyte ciascuno. Ogni query deve listare e aprire ogni file, fare il parsing dei suoi metadata, e fondere i risultati. Spark e Trino hanno entrambi curve di degrado ben documentate una volta che il numero di file supera qualche centinaio di migliaia. Oltre il milione, i tempi di query diventano imprevedibili e le request charge diventano una voce notevole sulla bolletta.
Il rimedio è la compaction: un job periodico che legge molti file piccoli, ordina e raggruppa le righe in modo opportuno, e li riscrive come un numero minore di file più grandi. La dimensione target del file per workload analitici è tipicamente da 256 MB a 1 GB per file Parquet. La compaction bilancia il costo di far girare il job contro i risparmi dovuti alla riduzione del file count e dell’overhead di metadata, e per qualsiasi dataset interrogato quotidianamente i risparmi dominano nel giro di settimane.
flowchart LR
Tiny["10,000 small Parquet files<br/>~100 KB each<br/>1 GB total"] --> Compact["Compaction job<br/>read, merge, rewrite"]
Compact --> Large["4 large Parquet files<br/>~256 MB each<br/>1 GB total"]
Il job di compaction in sé può essere costoso, perché legge e riscrive gli stessi dati. L’economia funziona perché i risparmi sono su ogni query successiva, non solo sulla prossima. Un job di compaction giornaliero che gira per un’ora risparmia secondi su ogni query per il prossimo anno, oltre a ridurre il costo per-request su ogni read.
Ottimizzazione automatica in Iceberg e Delta
La lezione 37 ha introdotto i lakehouse table format. Le loro feature di ottimizzazione automatica sono la risposta moderna al problema dei small file, e incorporano la compaction nel formato stesso invece di lasciarla all’utente.
Iceberg. La specifica Iceberg supporta operazioni di rewrite come concetti di prima classe, e motori come Spark e Trino possono lanciare operazioni OPTIMIZE o rewrite_data_files su una tabella Iceberg per compattare i file piccoli, ordinare per clustering key, e potare le righe cancellate. Snowflake e Databricks espongono entrambi Iceberg gestito con ottimizzazione automatica come feature di servizio.
Delta Lake. Delta ha il comando OPTIMIZE, con clausole opzionali ZORDER BY per il clustering multi-dimensionale. Il runtime Databricks offre auto-compaction e dimensionamento adattivo dei file, dove il motore stesso decide quando compattare in base alla distribuzione delle dimensioni dei file che osserva. La feature di auto-compaction è documentata nei docs di Databricks (https://docs.databricks.com/en/delta/optimizations/auto-optimize.html, consultato 2026-05-01).
Hudi. Hudi ha operazioni di clustering e compaction, con modalità sia inline (durante le scritture) sia offline (schedulate). Hudi era il formato più esplicito nel trattare la compaction come una preoccupazione di prima classe, perché il modello merge-on-read di fatto la richiede.
Per un team che usa uno di questi formati, l’ottimizzazione automatica andrebbe accesa, non spenta. Il costo di far girare la compaction su uno schedule è piccolo rispetto al costo di interrogare un milione di file minuscoli per un anno, e il tempo di engineering risparmiato non costruendo una compaction su misura è significativo.
Cancella ciò che non ti serve
Il gigabyte più economico è quello non immagazzinato. Ogni discussione sullo storage prima o poi torna alla pratica disciplinata di cancellare i dati che hanno superato il loro requisito di retention, sono stati generati da esperimenti che non hanno portato a nulla, vivono in ambienti di sviluppo che nessuno usa, oppure sono stati copiati “giusto in caso” e mai più letti.
Le ragioni per cui questa pratica viene trascurata sono prevedibili. Cancellare sembra rischioso: qualcuno potrebbe avere bisogno dei dati domani, e spiegare un file mancante è più difficile che assorbire una piccola voce in bolletta. La cancellazione non è una feature che qualche team viene pagato per spedire. Il costo dei dati conservati è distribuito sulla voce dello storage, dove nessun gigabyte singolo è visibile. E un team che non è passato da un cost engagement non ha la muscle memory per chiedere “questo dovrebbe ancora esistere”.
La disciplina matura include:
- Retention policy su ogni dataset, fissate dal data owner, espresse come lifecycle rule con un’azione finale di delete.
- Una passata di pulizia su dev e staging, dove snapshot, EBS volume, S3 bucket e backup di database si accumulano fino a quando qualcuno fa un audit.
- Revisioni a livello di bucket con cadenza trimestrale, cercando bucket che nessuno possiede e prefix su cui non si scrive da anni.
- Igiene del versioning: i bucket S3 con versioning abilitato accumulano ogni versione precedente di ogni oggetto, e una lifecycle rule mancante sulle noncurrent version può raddoppiare o triplicare la bolletta in silenzio. Il rimedio è una policy che fa scadere le noncurrent version dopo una finestra definita.
Il costo dello storage è il raro problema di engineering dove non fare nulla ha un costo che si compone. Il bucket cresce, la bolletta cresce, e il costo dell’audit che sarebbe dovuto avvenire l’anno scorso si accumula come l’anno seguente di spesa inutile.
Cosa copre la prossima lezione
La lezione 67 prende l’asse compute. Spot e preemptible instance per i workload che tollerano l’interruzione, autoscaling fatto bene contro le insidie dell’autoscaling che producono thrash e picchi mancati, right-sizing come disciplina di base che la maggior parte dei team non ha fatto da un anno, e capacity riservata per la baseline prevedibile che giustifica un commitment pluriennale. Compute è la voce di spesa con più folklore intorno, e la lezione taglia attraverso fino alle leve che muovono davvero la bolletta.
Riferimenti e approfondimenti
- AWS, S3 pricing,
https://aws.amazon.com/s3/pricing/(consultato 2026-05-01). Il riferimento canonico di pricing per tutte le storage class citate sopra. - AWS, S3 storage classes,
https://aws.amazon.com/s3/storage-classes/(consultato 2026-05-01). Il riassunto da pagina marketing delle classi, utile per la guida sui pattern d’accesso. - AWS, S3 lifecycle configuration,
https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html(consultato 2026-05-01). Il riferimento per la sintassi e il comportamento delle lifecycle policy. - Databricks, Auto-optimize on Delta Lake,
https://docs.databricks.com/en/delta/optimizations/auto-optimize.html(consultato 2026-05-01). La documentazione per auto-compaction e optimised write in Delta. - Apache Iceberg, table maintenance documentation,
https://iceberg.apache.org/docs/latest/maintenance/(consultato 2026-05-01). Il riferimento perrewrite_data_files, snapshot expiration, e altre operazioni di manutenzione. - Apache Hudi, compaction documentation,
https://hudi.apache.org/docs/compaction/(consultato 2026-05-01). Riferimento per la compaction inline e schedulata in Hudi. - FinOps Foundation, “Storage cost optimization”,
https://www.finops.org/wg/storage-cost-optimization/(consultato 2026-05-01). Risorse del working group sulle pratiche di tiering dello storage nella community FinOps.