Kasus penggunaan pemantauan

Mengumpulkan, mengingesti, merekap, memberi alert, serta titik ketika observability mengambil alih deteksi.

Daftar isi

Pemantauan sistem produksi adalah kasus time-series yang paling lazim dijumpai, sebab telemetri server, kontainer, dan perangkat jaringan mengalir terus setiap menit tanpa henti. Topik ini menjelaskan lima tahap stack pemantauan utuh, yaitu pengumpulan oleh kolektor, ingestion ke basis data time-series, rekap melalui downsampling, alerting atas ambang tertentu, serta penyajian pada dashboard. Setelah membaca topik ini, sebuah alur telemetri dapat dirancang dari kolektor sampai dashboard dengan pemahaman tentang peran setiap tahap serta titik di mana observability mengambil alih pekerjaan deteksi.

Lima tahap stack pemantauan#

Stack pemantauan yang utuh terdiri atas lima tahap yang masing-masing memiliki tanggung jawab berbeda. Tahap pertama adalah pengumpulan, yaitu pembacaan metrik dari sumbernya oleh kolektor seperti node_exporter untuk metrik host dan Telegraf untuk sumber yang beragam. Tahap kedua adalah ingestion, yaitu penulisan metrik ke basis data time-series, baik TimescaleDB melalui INSERT atau COPY, maupun InfluxDB 3.x melalui line protocol. Tahap ketiga adalah rekap, yaitu prakomputasi agregasi pada resolusi yang lebih kasar melalui continuous aggregates TimescaleDB atau downsampling task pada InfluxDB 3.x.

Tahap keempat adalah alerting, yaitu evaluasi metrik terhadap ambang atau anomali yang memicu notifikasi. Tahap kelima adalah penyajian pada dashboard, biasanya melalui Grafana, yang membaca dari tabel mentah maupun continuous aggregate. Kelima tahap ini berurutan secara alur data, tetapi tidak harus berjalan pada proses yang sama, sehingga setiap tahap dapat disesuaikan secara independen.

Pemisahan lima tahap ini bukan sekadar pembagian kerja, melainkan pemisahan tanggung jawab yang menentukan karakteristik stack. Kolektor dipisah dari basis data agar kolektor dapat diatur ulang tanpa memengaruhi data historis. Basis data dipisah dari alerting agar peningkatan beban alert tidak memengaruhi laju ingest. Dashboard dipisah dari basis data agar kegagalan panel tidak menahan query pemantauan kritis. Diagram berikut memperlihatkan alur tersebut secara visual.

Kolektornode_exporterTelegrafIngestionTimescaleDBInfluxDB 3.xRekapcontinuous agg.downsamplingAlertingambang cpunotifikasiDashboardGrafanapanelalur telemetri dari sumber ke panel dashboard
Lima tahap stack pemantauan: kolektor, ingestion, rekap, alerting, dan dashboard

Pengumpulan dan ingestion#

Pengumpulan telemetri dimulai dari kolektor yang berjalan pada setiap host. node_exporter menyajikan metrik CPU, memori, disk, dan jaringan pada endpoint HTTP /metrics dalam format eksposur Prometheus. Telegraf berperilaku ganda, yaitu sebagai kolektor yang membaca sumber beragam dan sebagai agen push yang menulis ke basis data time-series. Pada TimescaleDB, keluaran kolektor biasanya diterjemahkan oleh adapter menjadi baris INSERT, sedangkan pada InfluxDB 3.x, Telegraf menulis langsung melalui line protocol yang ringkas.

Ingestion ke InfluxDB 3.x menggunakan line protocol, yaitu format teks yang merangkum measurement, tag set, field set, dan cap waktu dalam satu baris. Format ini ringkas dan dapat di-stream, sehingga cocok untuk laju tinggi. Contoh berikut tidak dijalankan di sandbox dan hanya menjadi referensi sintaksis.

text Contoh line protocol untuk telemetri CPU
cpu_node,node=node-01,dc=jakarta cpu_persen=24.1,mem_persen=63.4 1730419200000000000
cpu_node,node=node-02,dc=jakarta cpu_persen=22.7,mem_persen=58.1 1730419200060000000
cpu_node,node=node-03,dc=surabaya cpu_persen=31.5,mem_persen=70.9 1730419200120000000
text Keluaran
Valid: 3 baris line protocol (lulus validasi format).

Pada TimescaleDB, ingestion menggunakan INSERT biasa atau COPY untuk batch besar. Karena TimescaleDB adalah ekstensi Postgres, driver standar seperti psycopg2 atau pgx dapat digunakan apa adanya. Batch INSERT dengan beberapa ratus baris per transaksi menjadi pilihan lazim, sebab kompromi antara throughput dan kompleksitas aplikasi cukup seimbang. Pemilihan jalur ingestion menentukan laju data yang dapat dipertahankan oleh stack, sehingga keputusan ini diambil sejak desain skema.

Rekap melalui downsampling#

Setelah telemetri tersimpan, query yang membaca seluruh baris mentah menjadi tidak praktis. Pada dashboard mingguan, memindai satu minggu data menitan pada tiga node berarti memindai sekitar 30.000 baris setiap kali panel dimuat. Downsampling mengecilkan jumlah itu melalui prakomputasi agregasi pada resolusi yang lebih kasar. Pada TimescaleDB, prakomputasi ini dilakukan oleh continuous aggregate yang menyimpan hasil time_bucket secara fisik dan disegarkan oleh kebijakan refresh. Pada InfluxDB 3.x, padanannya adalah downsampling task yang menulis hasil agregasi ke measurement baru.

Pemilihan resolusi rekap menentukan biaya penyimpanan dan keterbacaan dashboard. Bucket per jam mengurangi jumlah baris sekitar 60 kali pada data menitan, sedangkan bucket per hari mengurangi sekitar 1.440 kali. Bucket yang terlalu kasar menyembunyikan puncak singkat, sedangkan bucket yang terlalu halus membuat dashboard tetap berat. Praktik lazim adalah mempertahankan data mentah selama beberapa hari, lalu mengandalkan rekap per jam untuk dashboard mingguan dan rekap per hari untuk dashboard bulanan. Kebijakan retensi TimescaleDB kemudian menghapus chunk mentah yang sudah lebih tua dari ambang tertentu, sementara continuous aggregate tetap dipertahankan lebih lama.

Simulasi alur dengan pandas#

Karena continuous aggregate dan ingestion sebenarnya memerlukan server TimescaleDB atau InfluxDB yang tidak tersedia di sandbox, padanan yang paling dekat adalah simulasi dengan pandas. Skrip berikut membangkitkan satu hari telemetri CPU pada tiga node dengan dua lonjakan yang sengaja dimasukkan, lalu menjalankan kelima tahap secara in-process. Skrip tidak menjalankan SQL atau perintah kolektor apa pun.

python simulasi_alur_pemantauan.py
"""Simulasi alur pemantauan ujung ke ujung dengan pandas.

Skrip ini TIDAK menjalankan SQL atau perintah kolektor. Tujuannya
memperlihatkan alur lima tahap stack pemantauan, yaitu pengumpulan
telemetri oleh kolektor, ingestion ke basis data time-series, rekap
melalui downsampling, deteksi anomali yang memicu alert, dan ringkasan
yang lazim disajikan pada dashboard. Semua tahap dijalankan secara
in-process dengan pandas sebagai padanan basis data time-series.
"""
from __future__ import annotations

import pandas as pd

AWAL = "2026-11-01 00:00:00"
HARI = 1
SENSOR = ["node-01", "node-02", "node-03"]
AMBANG_CPU = 85.0  # ambang alert CPU, persen


def bangun_telemetri() -> pd.DataFrame:
    """Kolektor: bangkitkan satu titik per menit per node selama satu hari."""
    ts = pd.date_range(AWAL, periods=HARI * 1_440, freq="1min", tz="UTC")
    baris = []
    for node in SENSOR:
        dasar = 30.0 + (ts.hour.to_series().reset_index(drop=True) - 12).abs() * 1.4
        for i, t in enumerate(ts):
            # dua lonjakan CPU yang menyimpang pada node-01 dan node-02
            lonjakan = 0.0
            if node == "node-01" and 8 * 60 <= i <= 8 * 60 + 5:
                lonjakan = 60.0
            if node == "node-02" and 14 * 60 <= i <= 14 * 60 + 3:
                lonjakan = 70.0
            cpu = dasar.iloc[i] + lonjakan
            baris.append({"ts": t, "node": node, "cpu_persen": round(float(cpu), 2)})
    return pd.DataFrame(baris)


def rekap_harian(df: pd.DataFrame) -> pd.DataFrame:
    """Rekap: downsampling ke bucket per jam (min, max, avg, count)."""
    return (
        df.set_index("ts")
        .groupby("node")
        .resample("1h")["cpu_persen"]
        .agg(["min", "max", "mean", "count"])
        .reset_index()
        .rename(columns={"level_1": "ts"})
    )


def deteksi_alert(df: pd.DataFrame) -> pd.DataFrame:
    """Alert: tandai baris mentah yang melebihi ambang CPU."""
    out = df.copy()
    out["alert"] = out["cpu_persen"] > AMBANG_CPU
    return out


def main() -> None:
    # Tahap 1: pengumpulan
    telemetri = bangun_telemetri()
    print("=== Tahap 1: pengumpulan oleh kolektor ===")
    print(f"titik telemetri: {len(telemetri)} baris, sensor: {len(SENSOR)}")
    print(f"rentang: {telemetri['ts'].min()} -> {telemetri['ts'].max()}")
    print()

    # Tahap 2: ingestion (simulasi write ke TSDB)
    print("=== Tahap 2: ingestion ke basis data time-series ===")
    print(f"padanan: INSERT ke hypertable 'cpu_node' ({len(telemetri)} baris)")
    print(f"laju rata-rata: {len(telemetri) / (HARI * 1_440):.1f} baris/menit")
    print()

    # Tahap 3: rekap
    rekap = rekap_harian(telemetri)
    print("=== Tahap 3: rekap downsampling (1 jam) ===")
    print(f"baris mentah: {len(telemetri)} -> baris rekap: {len(rekap)} "
          f"(rasio {len(telemetri) / len(rekap):.1f}x lebih sedikit)")
    print(rekap.head(6).to_string(index=False))
    print()

    # Tahap 4: alerting
    bertanda = deteksi_alert(telemetri)
    picu = bertanda[bertanda["alert"]]
    print("=== Tahap 4: alerting atas ambang CPU ===")
    print(f"ambang: cpu_persen > {AMBANG_CPU}")
    print(f"baris picu: {len(picu)} dari {len(bertanda)} "
          f"({len(picu) / len(bertanda) * 100:.2f}%)")
    if not picu.empty:
        ringkas = (
            picu.groupby("node")
            .agg(jumlah=("alert", "sum"), maks=("cpu_persen", "max"))
            .reset_index()
        )
        print(ringkas.to_string(index=False))
    print()

    # Tahap 5: ringkasan dashboard
    print("=== Tahap 5: ringkasan untuk dashboard ===")
    terakhir = telemetri.sort_values("ts").groupby("node").tail(1)
    print(terakhir[["ts", "node", "cpu_persen"]].to_string(index=False))
    print()
    print("padanan SQL TimescaleDB:")
    print("  SELECT time_bucket('1 hour', ts) AS bucket, node,")
    print("         min(cpu_persen), max(cpu_persen), avg(cpu_persen), count(*)")
    print("  FROM cpu_node GROUP BY bucket, node;")
    print()
    print("padanan InfluxDB 3.x (line protocol):")
    print("  cpu_node,node=node-01 cpu_persen=24.1 1730419200000000000")


if __name__ == "__main__":
    main()
text Keluaran
=== Tahap 1: pengumpulan oleh kolektor ===
titik telemetri: 4320 baris, sensor: 3
rentang: 2026-11-01 00:00:00+00:00 -> 2026-11-01 23:59:00+00:00

=== Tahap 2: ingestion ke basis data time-series ===
padanan: INSERT ke hypertable 'cpu_node' (4320 baris)
laju rata-rata: 3.0 baris/menit

=== Tahap 3: rekap downsampling (1 jam) ===
baris mentah: 4320 -> baris rekap: 72 (rasio 60.0x lebih sedikit)
   node                        ts  min  max  mean  count
node-01 2026-11-01 00:00:00+00:00 46.8 46.8  46.8     60
node-01 2026-11-01 01:00:00+00:00 45.4 45.4  45.4     60
node-01 2026-11-01 02:00:00+00:00 44.0 44.0  44.0     60
node-01 2026-11-01 03:00:00+00:00 42.6 42.6  42.6     60
node-01 2026-11-01 04:00:00+00:00 41.2 41.2  41.2     60
node-01 2026-11-01 05:00:00+00:00 39.8 39.8  39.8     60

=== Tahap 4: alerting atas ambang CPU ===
ambang: cpu_persen > 85.0
baris picu: 10 dari 4320 (0.23%)
   node  jumlah  maks
node-01       6  95.6
node-02       4 102.8

=== Tahap 5: ringkasan untuk dashboard ===
                       ts    node  cpu_persen
2026-11-01 23:59:00+00:00 node-02        45.4
2026-11-01 23:59:00+00:00 node-01        45.4
2026-11-01 23:59:00+00:00 node-03        45.4

padanan SQL TimescaleDB:
  SELECT time_bucket('1 hour', ts) AS bucket, node,
         min(cpu_persen), max(cpu_persen), avg(cpu_persen), count(*)
  FROM cpu_node GROUP BY bucket, node;

padanan InfluxDB 3.x (line protocol):
  cpu_node,node=node-01 cpu_persen=24.1 1730419200000000000

Keluaran di atas memperlihatkan dua hal. Pertama, rekap per jam mengurangi 4.320 baris mentah menjadi 72 baris, rasio 60 kali lebih sedikit, sehingga dashboard harian menjadi murah. Kedua, alert yang dipicu menunjukkan node-01 menyumbang enam titik lonjakan dan node-02 menyumbang empat, sehingga investigasi dapat diarahkan ke dua node tersebut tanpa memeriksa seluruh data mentah.

Titik observability mengambil alih#

Alerting atas ambang merupakan bentuk deteksi termuda. Pada ambang statis, sebuah metrik dipicu menjadi alert bila melampaui nilai tetap, misalnya cpu_persen > 85. Pendekatan ini cukup untuk masalah yang sudah dikenal, tetapi lemah terhadap pergeseran pola harian, musiman, atau anomali halus yang tidak melampaui ambang. Observability mengambil alih deteksi ketika pertanyaannya bergeser dari “apakah melebihi ambang” menjadi “apakah berperilaku seperti biasa”. Pada titik ini, alerting berbasis anomali, korelasi silang metrik, dan tracing terdistribusi menjadi lebih relevan daripada ambang tunggal.

Basis data time-series tetap menjadi tulang punggung observability, sebab data historis menjadi referensi untuk perilaku biasa. Pelatihan model deteksi anomali memerlukan mingguan hingga bulanan data bersih, sehingga retensi panjang menjadi syarat. InfluxDB dan TimescaleDB melayani kebutuhan ini, sedangkan Prometheus yang berfokus pada retensi jangka pendek biasanya diiringi oleh basis data jangka panjang seperti Mimir atau bahkan TimescaleDB sendiri melalui remote write.

Kesalahan umum#

  • Menulis alert langsung pada data mentah tanpa rekap. Akibatnya, setiap lonjakan singkat memicu notifikasi, sehingga tim menerima terlalu banyak alert dan mulai mengabaikannya.
  • Menggunakan kolektor sebagai sumber kebenaran historis. Kolektor hanya menyimpan telemetri sementara, sehingga kehilangan data terjadi bila basis data time-series tidak menerima tulisan.
  • Membaca dashboard dari tabel mentah pada rentang panjang. Akibatnya, panel menjadi lambat dan beban basis data meningkat setiap kali dashboard dimuat.

Ringkasan#

  • Stack pemantauan utuh terdiri atas lima tahap, yaitu pengumpulan, ingestion, rekap, alerting, dan dashboard, yang masing-masing dipisahkan berdasarkan tanggung jawab.
  • Ingestion ke InfluxDB 3.x menggunakan line protocol, sedangkan ingestion ke TimescaleDB menggunakan INSERT atau COPY standar Postgres.
  • Continuous aggregate pada TimescaleDB dan downsampling task pada InfluxDB 3.x melayani rekap, sehingga dashboard membaca jauh lebih sedikit baris dibanding tabel mentah.
  • Alerting atas ambang adalah bentuk deteksi termuda, sedangkan observability mengambil alih ketika anomali dan korelasi silang menjadi pusat perhatian.

Referensi#