Data time-series memiliki siklus hidup yang khas, yaitu nilai dan frekuensi aksesnya meluruh seiring usia. Topik ini membedah empat tahap siklus hidup, yaitu panas, hangat, dingin, dan hilang, beserta keputusan penyimpanan dan retensi yang menyertai tiap tahap. Setelah membaca topik ini, kebijakan retensi dan kompresi tidak lagi menjadi pertanyaan optimasi yang ditunda, melainkan keputusan skema yang ditetapkan bersamaan dengan pemilihan tipe data.
Nilai yang meluruh seiring usia#
Pada data operasional biasa, nilai sebuah baris cenderung konstan sepanjang waktu. Sebuah baris pengguna tetap penting baik berusia satu hari maupun satu tahun, sebab masih mungkin dibaca ketika pengguna melakukan login. Pada data time-series, nilai sebuah titik menurun tajam seiring bertambahnya usia. Titik suhu satu menit yang berusia lima menit kemungkinan besar akan dibaca kembali untuk dashboard, sedangkan titik yang sama pada usia satu tahun hanya akan dibaca bila terjadi analisis retrospektif, yang jarang dilakukan.
Penurunan nilai ini bersifat eksponensial, bukan linier. Pada dashboard pemantauan, sebagian besar query menyentuh data berusia kurang dari satu jam, sebagian kecil menyentuh data berusia satu hari, dan nyaris tidak ada yang menyentuh data berusia lebih dari satu bulan. Pola akses ini disebut time-decay access pattern, dan konsekuensinya adalah struktur penyimpanan sebaiknya dibedakan berdasarkan usia. Menyimpan seluruh data pada media yang sama berarti membayar harga media cepat untuk data yang nyaris tidak pernah dibaca, sekaligus membebani media lambat dengan data yang sering dibaca.
Tahap panas#
Tahap panas adalah periode ketika data paling sering dibaca dan ditulis. Pada dashboard pemantauan, tahap ini biasanya mencakup satu hingga tujuh hari terakhir, yaitu rentang yang digunakan untuk grafik real-time, deteksi anomali, dan alerting. Penyimpanan pada tahap ini sebaiknya berada di media tercepat yang tersedia, yaitu memori, SSD NVMe, atau setidaknya SSD biasa. Indeks B-tree masih berbentuk baris dan belum dikompresi, sehingga latensi query berada di bawah 100 milidetik.
Tahap panas juga adalah tahap di mana late arrival paling mungkin terjadi, sebab data masih aktif mengalir. Chunk pada tahap ini biasanya belum dikompresi, sebab kompresi memerlukan data yang sudah final. Karena itu, ruang penyimpanan pada tahap panas relatif besar per titik, tetapi jumlah titik pada tahap ini kecil dibandingkan total. Pada kebijakan siklus hidup yang sehat, tahap panas hanya menyimpan sekitar satu sampai lima persen dari total volume, tetapi menerima lebih dari sembilan puluh persen dari total beban query.
Tahap hangat dan dingin#
Tahap hangat adalah periode ketika data masih dibaca secara berkala, tetapi tidak lagi setiap menit. Pada pemantauan, tahap ini biasanya mencakup minggu kedua hingga akhir bulan, yaitu rentang yang digunakan untuk laporan mingguan dan perbandingan periode. Pada tahap ini, data sebaiknya dikompresi ke format kolumnar, sebab nilai historis tidak lagi berubah dan pola nilainya membeku. Kompresi kolumnar dapat mengecilkan ukuran penyimpanan hingga empat hingga sepuluh kali, tanpa kehilangan kemampuan query.
Tahap dingin adalah periode ketika data jarang dibaca, tetapi tetap disimpan untuk keperluan audit atau analisis retrospektif. Pada tahap ini, data dipindahkan ke media yang lebih murah, yaitu HDD, object storage, atau bahkan tape. Query pada tahap dingin menerima latensi yang lebih tinggi, yaitu hitungan detik hingga menit, dan biasanya dijalankan sebagai batch alih-alih interaktif. Banyak mesin time-series menyediakan mekanisme pemindahan otomatis, misalnya tiered storage pada InfluxDB 3 atau kompresi chunk otomatis pada TimescaleDB.
Tahap hilang dan retensi#
Tahap terakhir adalah hilang, yaitu ketika data dihapus dari penyimpanan utama. Penghapusan ini bukan kegagalan, melainkan keputusan eksplisit yang disebut kebijakan retensi. Retensi ditentukan oleh kebutuhan domain, bukan oleh kapasitas disk. Pemantauan infrastruktur biasanya menyimpan data 30 hingga 90 hari, sedangkan audit keuangan dapat menuntut penyimpanan lima tahun atau lebih. Tanpa kebijakan retensi yang eksplisit, data time-series tumbuh tanpa batas, dan pada akhirnya menenggelamkan kapasitas disk maupun kemampuan query.
Cara penghapusan menentukan biaya. Menghapus baris demi baris dengan DELETE ... WHERE ts < ... pada tabel raksasa memerlukan pemindaian dan vacuum, yang sangat mahal. Karena itu, mesin time-series menggunakan partisi waktu sebagai unit retensi: penghapusan chunk lama hanya berarti melepaskan seluruh berkas partisi, bukan memindai baris. Mekanisme ini membuat retensi harian atau mingguan dapat berjalan dalam hitungan detik, bahkan pada tabel berisi miliaran baris.
Simulasi siklus hidup#
Skrip Python berikut membangkitkan satu tahun telemetri (365 hari, satu titik per hari), lalu mengklasifikasikan setiap hari ke salah satu dari empat tahap, yaitu panas, hangat, dingin, dan arsip. Skrip menghitung ukuran penyimpanan mentah dan terkompresi per tahap, serta frekuensi query hipotetis yang meluruh dari tahap panas ke arsip. Tujuannya menunjukkan bahwa volume data terbesar berada pada tahap paling jarang diakses, sehingga pemisahan penyimpanan berdasarkan tahap menjadi keputusan yang membayar dirinya sendiri.
"""Simulasi siklus hidup data time-series.
Skrip membangkitkan satu tahun telemetri (365 hari, satu titik per hari),
lalu menghitung frekuensi query hipotetis per kelompok usia, ukuran
penyimpanan mentah vs terkompresi, serta nilai bisnis yang meluruh seiring
usia. Tujuannya menunjukkan bahwa data time-series memiliki siklus hidup
panas-hangat-dingin-hilang yang alami, dan kebijakan retensi yang menentukan
titik perpindahan tiap tahap.
"""
from __future__ import annotations
from datetime import date, timedelta
import pandas as pd
AWAL = date(2026, 1, 1)
JUMLAH_HARI = 365
def bangun_telemetri() -> pd.DataFrame:
hari = [AWAL + timedelta(days=i) for i in range(JUMLAH_HARI)]
return pd.DataFrame({
"hari": pd.to_datetime(hari),
"titik_per_hari": 1_440,
"ukuran_kb_mentah": 1_440 * 0.040,
"ukuran_kb_kompres": 1_440 * 0.010,
})
def klasifikasi_usia(df: pd.DataFrame, hari_ini: pd.Timestamp) -> pd.DataFrame:
usia_hari = (hari_ini - df["hari"]).dt.days
tahap = pd.cut(
usia_hari,
bins=[-1, 7, 30, 90, 365],
labels=["panas", "hangat", "dingin", "arsip"],
)
df = df.assign(usia_hari=usia_hari, tahap=tahap)
return df
def ringkas_per_tahap(df: pd.DataFrame) -> pd.DataFrame:
return (
df.groupby("tahap", observed=True)
.agg(
hari=("hari", "count"),
total_titik=("titik_per_hari", "sum"),
ukuran_kb_mentah=("ukuran_kb_mentah", "sum"),
ukuran_kb_kompres=("ukuran_kb_kompres", "sum"),
)
.round(2)
)
def frekuensi_query_hipotetis() -> pd.DataFrame:
return pd.DataFrame({
"tahap": ["panas", "hangat", "dingin", "arsip"],
"query_per_hari": [10_000, 500, 20, 1],
"sumber_penyimpanan": ["memori atau SSD cepat", "SSD terkompres", "object storage", "object storage"],
})
def main() -> None:
df = bangun_telemetri()
hari_ini = pd.Timestamp("2027-01-01")
df = klasifikasi_usia(df, hari_ini)
print("ringkasan per tahap siklus hidup:")
ringkas = ringkas_per_tahap(df)
print(ringkas.to_string())
print()
print("frekuensi query dan sumber penyimpanan hipotetis:")
fq = frekuensi_query_hipotetis()
print(fq.to_string(index=False))
print()
total_mentah = ringkas["ukuran_kb_mentah"].sum()
total_kompres = ringkas["ukuran_kb_kompres"].sum()
print(f"total ukuran mentah: {total_mentah:.2f} KB")
print(f"total ukuran terkompres: {total_kompres:.2f} KB")
print(f"rasio kompresi: {total_mentah / total_kompres:.1f}x")
if __name__ == "__main__":
main()ringkasan per tahap siklus hidup:
hari total_titik ukuran_kb_mentah ukuran_kb_kompres
tahap
panas 7 10080 403.2 100.8
hangat 23 33120 1324.8 331.2
dingin 60 86400 3456.0 864.0
arsip 275 396000 15840.0 3960.0
frekuensi query dan sumber penyimpanan hipotetis:
tahap query_per_hari sumber_penyimpanan
panas 10000 memori atau SSD cepat
hangat 500 SSD terkompres
dingin 20 object storage
arsip 1 object storage
total ukuran mentah: 21024.00 KB
total ukuran terkompres: 5256.00 KB
rasio kompresi: 4.0xKeluaran di atas memperlihatkan dua hal penting. Pertama, distribusi volume terbalik dengan distribusi akses: tahap arsip menyimpan 275 hari atau sekitar 75 persen dari total volume, tetapi hanya menerima satu query per hari. Sebaliknya, tahap panas hanya menyimpan 7 hari atau sekitar 2 persen dari total volume, tetapi menerima 10.000 query per hari. Kedua, rasio kompresi 4 kali yang diasumsikan pada contoh mengubah total ukuran dari 21.024 KB menjadi 5.256 KB, dan penghematan ini menjadi semakin besar seiring pertumbuhan data. Tanpa pemisahan tahap, 275 hari data arsip akan menempati media cepat tanpa perlu, sementara 7 hari data panas akan bersaing ruang dengan data yang nyaris tidak pernah dibaca.
Kesalahan umum#
- Menyatukan seluruh data pada satu media tanpa pemisahan tahap. Akibatnya, data panas tidak mendapatkan media tercepat yang dibutuhkannya, dan data arsip membebani biaya media cepat tanpa manfaat.
- Memilih kebijakan retensi berdasarkan kapasitas disk, bukan kebutuhan domain. Retensi yang terlalu panjang karena disk masih ada ruang akan menyulitkan query, sebab indeks tumbuh tanpa hingga.
- Menghapus data dengan
DELETEbaris-per-baris pada tabel raksasa. Operasi ini memicu pemindaian penuh, vacuum berat, dan keterlambatan retensi harian. Penghapusan sebaiknya dilakukan pada level partisi waktu.
Ringkasan#
- Data time-series memiliki siklus hidup dengan nilai dan frekuensi akses yang meluruh seiring usia.
- Empat tahap khas adalah panas, hangat, dingin, dan hilang, masing-masing dengan media penyimpanan yang berbeda.
- Volume data terbesar berada pada tahap paling jarang diakses, sehingga pemisahan penyimpanan berdasarkan tahap membayar dirinya sendiri.
- Retensi sebaiknya berbasis partisi waktu, bukan baris-per-baris, agar penghapusan berlangsung dalam hitungan detik.
Referensi#
- Data retention — Timescale — Penjelasan resmi kebijakan retensi TimescaleDB berbasis penghapusan chunk berdasarkan usia.
- Compression methods — Tiger Data — Mekanisme kompresi kolumnar pada TimescaleDB, termasuk transisi dari baris ke kolumnar untuk chunk lama.
- Storage — Prometheus — Detail penyimpanan lokal Prometheus dan alasan retensi jangka pendek menjadi default.