Deployment bertahap untuk migrasi analytics tanpa ganggu produksi berarti memindahkan jalur ingest, query, dan dashboard ke sistem baru secara terukur, sambil menjaga jalur lama tetap menjadi sumber kebenaran sampai bukti operasional cukup kuat. Untuk beban analytics atau observability yang pindah ke database kolom seperti ClickHouse, pendekatan aman biasanya bukan cutover sekali jalan, melainkan serangkaian tahap: shadow traffic, dual-write terbatas, verifikasi hasil query, aktivasi pembaca bertahap, dan rollback yang bisa dilakukan dalam hitungan menit.

Masalah utama dalam migrasi seperti ini jarang hanya soal apakah sistem baru bisa menyimpan data. Tantangan sebenarnya adalah memastikan data tiba tepat waktu, hasil agregasi tetap konsisten, query dashboard tidak melonjak liar, dan biaya storage tidak meledak akibat skema atau retensi yang salah. Artikel ini merangkum pola implementasi yang praktis dan operasional untuk memigrasikan beban analytics secara aman.

Mengapa migrasi analytics perlu deployment bertahap

Beban analytics berbeda dari database transaksional. Pola tulisnya bisa sangat besar, pola bacanya sering berupa agregasi berat, dan kesalahan kecil pada skema atau partisi bisa menimbulkan dampak besar pada performa dan biaya. Karena itu, migrasi ke sistem kolom seperti ClickHouse sebaiknya memperlakukan produksi sebagai lingkungan yang harus dilindungi, bukan tempat eksperimen.

  • Ingest sensitif terhadap lonjakan: burst log, event tracing, atau metrics dapat memicu antrean dan keterlambatan.
  • Query analytics sulit diprediksi: dashboard, ad-hoc query, dan eksplorasi insiden dapat memicu scan besar.
  • Perbedaan semantik query: fungsi waktu, pembulatan, null handling, dan deduplikasi dapat menghasilkan angka yang sedikit berbeda.
  • Blast radius luas: kegagalan pada pipeline observability sering membuat tim kehilangan visibilitas saat justru dibutuhkan.

Deployment bertahap bekerja karena setiap tahap menguji satu risiko utama dengan paparan yang dibatasi. Anda tidak langsung memindahkan semua write dan read sekaligus; Anda menambah kepercayaan sistem baru sedikit demi sedikit.

Arsitektur rollout yang aman

1. Pisahkan jalur ingest, storage, dan query

Jangan memperlakukan migrasi sebagai satu tombol. Minimal, pecah menjadi tiga komponen yang bisa diaktifkan atau dimatikan secara independen:

  • Producer / collector: aplikasi, agent, atau pipeline yang mengirim event.
  • Writer: layanan yang melakukan buffering, transformasi ringan, dan menulis ke storage lama maupun baru.
  • Reader: service query, API dashboard, atau adapter BI yang membaca dari storage target.

Pemisahan ini penting agar Anda bisa melakukan shadow write tanpa mengubah pembaca, atau mengaktifkan pembaca baru hanya untuk sebagian dashboard tanpa mengganggu ingest.

2. Tambahkan feature flag pada write dan read path

Feature flag memberi kendali granular saat rollout dan rollback. Hindari flag tunggal seperti USE_CLICKHOUSE=true. Lebih aman menggunakan flag terpisah:

  • shadow_write_enabled
  • dual_write_enabled
  • clickhouse_read_enabled
  • clickhouse_read_percentage
  • high_cost_queries_enabled

Dengan pemisahan ini, Anda bisa tetap mengirim data ke sistem baru untuk validasi, sambil menjaga semua dashboard tetap membaca dari sistem lama.

3. Batasi blast radius sejak desain awal

Pembatasan blast radius bukan langkah opsional. Beberapa teknik yang praktis:

  • Aktifkan rollout per tenant, per environment, per tipe event, atau per dashboard.
  • Mulai dari event non-kritis atau dataset retensi pendek.
  • Gunakan kuota query, batas concurrency, dan timeout konservatif pada pembaca baru.
  • Pisahkan cluster atau resource pool untuk workload ad-hoc dan dashboard produksi jika memungkinkan.
  • Pastikan jalur lama tetap aktif sampai SLO sistem baru stabil dalam periode observasi yang cukup.

Tahap deployment bertahap yang direkomendasikan

Tahap 0: Baseline dan kriteria sukses

Sebelum menulis satu event pun ke sistem baru, definisikan apa yang dianggap berhasil. Minimal tetapkan SLI dan SLO untuk ingest dan query:

  • SLI ingest freshness: selisih waktu antara event dibuat dan event dapat di-query.
  • SLI ingest success rate: persentase batch/event yang berhasil ditulis.
  • SLI query latency: p95 atau p99 latency untuk dashboard penting.
  • SLI query correctness: deviasi hasil query antara sistem lama dan baru untuk sampel query acuan.
  • SLI resource efficiency: pertumbuhan storage, partisi, dan antrean write.

SLO perlu realistis dan terkait risiko bisnis. Contoh yang aman secara generik: freshness harus berada dalam batas yang diterima operasional tim, dan dashboard prioritas tidak boleh melambat secara signifikan dibanding baseline lama. Hindari menetapkan angka tanpa data historis.

Tahap 1: Shadow traffic untuk ingest

Pada tahap ini, event tetap diproses penuh oleh sistem lama. Writer baru menerima salinan event yang sama, tetapi hasilnya belum dipakai oleh pengguna. Tujuannya untuk menguji throughput, skema, batching, retry, dan tekanan storage tanpa memengaruhi read path produksi.

Pola implementasi umum:

  1. Producer mengirim event ke broker atau endpoint write yang sama seperti sebelumnya.
  2. Writer utama tetap menulis ke storage lama.
  3. Writer tambahan atau cabang pipeline melakukan write ke ClickHouse.
  4. Semua error di jalur shadow dicatat, tetapi tidak memblokir jalur utama.

Hal yang perlu diperhatikan:

  • Jangan biarkan shadow write mengambil resource tanpa batas dari jalur utama.
  • Gunakan rate limit jika cluster baru masih dipanaskan.
  • Amati ukuran batch, kompresi, dan pola partisi agar tidak menciptakan terlalu banyak part kecil.
# pseudo-config rollout write path
analytics:
  primary_sink: legacy
  shadow_sink:
    enabled: true
    target: clickhouse
    sample_rate: 0.10
    fail_open: true
    max_concurrency: 4
    batch_size: 5000

Fail-open di sini berarti kegagalan shadow sink tidak boleh memblokir sink utama. Ini penting untuk menjaga produksi tetap aman.

Tahap 2: Dual-write terukur

Setelah shadow traffic stabil, lanjutkan ke dual-write terukur. Bedanya, jalur write ke sistem baru kini dianggap bagian resmi rollout, tetapi tetap dibatasi. Anda dapat memulai dari sebagian tenant, sebagian tipe event, atau persentase kecil trafik.

Dual-write berguna untuk menguji ketahanan operasional jangka lebih panjang, namun juga menambah kompleksitas:

  • Potensi ketidakkonsistenan antar sink.
  • Biaya write ganda.
  • Retry yang bisa menimbulkan duplikasi jika idempotensi tidak dirancang.

Karena itu, dual-write harus terukur, bukan langsung 100%. Pastikan ada strategi identitas event atau deduplikasi yang cukup. Jika event memiliki event_id, gunakan itu untuk validasi dan korelasi. Jika tidak ada, buat kunci deterministik dari atribut penting yang stabil.

// pseudocode writer dengan dual-write non-blocking
func handleBatch(batch []Event) error {
    if err := writeLegacy(batch); err != nil {
        return err // jalur utama tetap menentukan sukses request
    }

    if flags.DualWriteEnabled(batchTenant(batch)) {
        go func(copy []Event) {
            err := writeClickHouse(copy)
            metrics.Count("analytics.dual_write.error", err != nil)
            if err != nil {
                log.Error("dual write failed", "err", err, "batch_size", len(copy))
            }
        }(clone(batch))
    }

    return nil
}

Contoh di atas menunjukkan prinsip umum: jangan membuat latensi write utama tergantung langsung pada sink sekunder jika tujuan tahap ini adalah pengurangan risiko. Pada tahap lanjut, Anda bisa memperketat validasi, tetapi di awal rollout keselamatan produksi lebih penting.

Tahap 3: Verifikasi hasil query

Migration dianggap gagal jika data masuk, tetapi hasil dashboard salah. Karena itu, verifikasi query harus menjadi tahap tersendiri. Caranya bukan membandingkan semua query acak, melainkan memilih query canary yang mewakili beban nyata:

  • Total event per menit per layanan.
  • Error rate per endpoint.
  • Latency percentiles untuk dashboard prioritas.
  • Top N host, service, atau tenant.
  • Retensi harian dan volume ingest.

Bandingkan hasil query lama dan baru dalam jendela waktu yang sama. Toleransi deviasi harus ditentukan per metrik. Misalnya, hitungan total bisa menuntut deviasi sangat kecil, sementara agregasi latency atau event sampling mungkin butuh toleransi berbeda.

Penyebab umum perbedaan hasil:

  • Perbedaan zona waktu atau pembulatan bucket waktu.
  • Record terlambat yang masuk ke window berbeda.
  • Deduplikasi berbeda antara storage lama dan baru.
  • Perbedaan definisi null, empty string, atau field yang hilang.
  • Transformasi ingest yang tidak identik.
-- contoh query verifikasi sederhana per menit
SELECT
  toStartOfMinute(timestamp) AS minute,
  service,
  count() AS total_events
FROM events
WHERE timestamp >= now() - INTERVAL 1 HOUR
GROUP BY minute, service
ORDER BY minute, service;

Jangan hanya memeriksa satu kali. Jalankan pembandingan berkala dan simpan hasil deviasi agar tren masalah bisa terlihat, misalnya apakah selisih membesar saat traffic puncak.

Tahap 4: Aktivasi read path secara bertahap

Setelah ingest dan verifikasi query stabil, aktifkan pembaca baru sedikit demi sedikit. Mulai dari:

  1. Dashboard internal tim platform.
  2. Dashboard observability non-kritis.
  3. Tenant kecil atau subset layanan.
  4. Dashboard prioritas tinggi terakhir.

Gunakan routing berbasis persentase atau allowlist. Jika ada query yang biayanya tinggi, tahan dulu di jalur lama sampai pattern dan indeks di sistem baru benar-benar dipahami.

# pseudo-config read rollout
read_path:
  clickhouse_enabled: true
  rollout:
    mode: allowlist
    dashboards:
      - platform-ingest-overview
      - internal-error-trends
  safeguards:
    max_query_duration_seconds: 15
    max_concurrent_queries: 20
    fallback_to_legacy_on_error: true

Fallback otomatis ke sistem lama sering layak untuk dashboard interaktif, tetapi jangan menyamarkan kegagalan total. Tetap kirim alarm saat fallback aktif agar tim tahu ada degradasi tersembunyi.

SLI/SLO yang relevan untuk migrasi analytics

SLI ingest

  • Freshness lag: umur data saat pertama kali tersedia untuk query.
  • Write success rate: keberhasilan batch atau insert.
  • Retry volume: lonjakan retry sering menandakan bottleneck atau timeout.
  • Backlog queue: ukuran antrean sebelum writer.

SLI query dan dashboard

  • Latency p95/p99 untuk query dashboard prioritas.
  • Error rate query: timeout, memory limit, syntax mismatch dari adapter.
  • Result divergence rate: persentase query canary yang keluar dari toleransi.
  • Fallback rate jika read path punya mekanisme fallback ke legacy.

SLO yang masuk akal secara operasional

SLO sebaiknya menyatakan batas layanan minimum yang dibutuhkan untuk tetap bisa mengoperasikan sistem. Contoh bentuk SLO tanpa mengunci angka yang belum tentu cocok untuk semua tim:

  • Data observability harus tersedia dalam jangka waktu yang masih berguna untuk debugging insiden.
  • Dashboard utama tidak boleh mengalami regresi latency yang berarti dibanding baseline.
  • Deviasi hasil query untuk metrik acuan harus tetap dalam toleransi yang telah disetujui.
  • Rollback read path harus bisa dilakukan cepat tanpa perubahan manual yang kompleks.

Jika tim Anda belum matang, mulailah dari sedikit SLI yang benar-benar diawasi. Lebih baik tiga SLI yang dipakai untuk keputusan rollout daripada dua puluh metrik yang tidak pernah dilihat.

Rollback cepat dan pembatasan blast radius

Rollback yang baik tidak bergantung pada redeploy besar. Targetkan rollback berbasis konfigurasi atau feature flag. Dalam konteks migrasi analytics, rollback biasanya dibagi menjadi dua jenis:

Rollback read path

Ini yang paling aman dan paling cepat. Jika query sistem baru lambat atau hasilnya mencurigakan, alihkan semua dashboard kembali ke storage lama. Syaratnya:

  • Adapter read lama masih aktif.
  • Konfigurasi routing bisa diubah tanpa build ulang.
  • Cache atau DNS tidak menunda perubahan terlalu lama.

Rollback write path

Lebih sensitif karena menyangkut kontinuitas data. Strategi aman biasanya:

  • Matikan dual-write ke sink baru.
  • Pertahankan sink lama sebagai jalur utama.
  • Biarkan backlog sink baru berhenti atau dikuras terkontrol.
  • Jangan lakukan replay besar saat cluster masih tidak sehat.

Untuk membatasi blast radius, rollout sebaiknya selalu bisa dihentikan di level berikut:

  • Per tenant.
  • Per dataset atau tabel.
  • Per tipe event.
  • Per dashboard atau kelompok query.

Catatan: rollback cepat sering gagal bukan karena teknologi, tetapi karena dependensi yang tidak terdokumentasi. Misalnya dashboard ternyata sudah memakai fungsi SQL khusus sistem baru, sehingga fallback ke sistem lama tidak lagi kompatibel. Jaga kompatibilitas query selama masa transisi.

Runbook insiden ringan saat rollout

Runbook berikut sengaja ringkas agar bisa dipakai saat on-call. Sesuaikan dengan tooling tim Anda.

Insiden 1: Data terlambat masuk

Gejala: freshness lag naik, dashboard tampak kosong atau tertinggal.

Pemeriksaan awal:

  1. Lihat backlog di broker, queue, atau buffer writer.
  2. Cek error insert, timeout, dan retry rate writer.
  3. Periksa ukuran batch, concurrency, dan rate limit rollout.
  4. Bandingkan apakah keterlambatan hanya terjadi pada tenant atau dataset tertentu.

Tindakan mitigasi:

  • Kurangi rollout dual-write atau matikan untuk tenant terdampak.
  • Turunkan beban query non-esensial sementara jika resource storage dan query berbagi kapasitas.
  • Naikkan kapasitas writer atau buffer jika bottleneck jelas ada di sisi ingest.
  • Jika perlu, rollback read path agar pengguna melihat data dari sistem lama.

Kesalahan umum: langsung melakukan replay backlog besar tanpa memahami apakah bottleneck ada di insert, merge, disk, atau query contention.

Insiden 2: Query melonjak dan dashboard melambat

Gejala: p95 latency dashboard naik, timeout meningkat, CPU atau IO tinggi saat jam sibuk.

Pemeriksaan awal:

  1. Identifikasi query termahal berdasarkan durasi, bytes scanned, atau frekuensi.
  2. Lihat apakah ada dashboard baru atau eksplorasi ad-hoc yang menembak cluster yang sama.
  3. Periksa filter waktu, cardinality tinggi, dan penggunaan wildcard atau group by besar.
  4. Bandingkan apakah query lambat hanya pada sistem baru atau juga terjadi di sistem lama.

Tindakan mitigasi:

  • Rollback dashboard tertentu ke legacy.
  • Terapkan kuota, timeout, atau batas concurrency lebih ketat.
  • Nonaktifkan query mahal yang belum dioptimalkan.
  • Jika arsitektur mendukung, pisahkan workload dashboard dan ad-hoc.

Debugging tip: query analytics yang tampak setara secara logika bisa sangat berbeda biayanya. Fokus pada pola akses data, bukan hanya teks SQL.

Insiden 3: Storage membengkak

Gejala: pertumbuhan disk lebih cepat dari perkiraan, merge berat, atau partisi terlalu banyak.

Pemeriksaan awal:

  1. Periksa retensi tabel, TTL, dan kebijakan penghapusan.
  2. Tinjau skema partisi dan cardinality key yang terlalu granular.
  3. Lihat apakah ada duplikasi akibat retry non-idempoten atau replay ganda.
  4. Bandingkan volume event masuk dengan volume storage aktual.

Tindakan mitigasi:

  • Hentikan dual-write untuk dataset bermasalah.
  • Perbaiki retensi dan skema partisi sebelum melanjutkan rollout.
  • Tahan replay sampai mekanisme deduplikasi dipahami.
  • Audit pipeline transformasi yang mungkin memperkaya event secara berlebihan.

Kesalahan umum: menganggap storage membengkak hanya soal kompresi. Sering kali akar masalahnya adalah duplikasi, partisi salah, atau retensi tak sengaja terlalu panjang.

Contoh checklist rollout operasional

  • Schema review selesai dan query canary sudah ditetapkan.
  • Feature flag write/read tersedia dan diuji di staging.
  • SLI ingest, query latency, divergence, dan fallback rate sudah ada di dashboard monitoring.
  • Alert untuk freshness lag, write error, query timeout, dan pertumbuhan storage sudah aktif.
  • Rollback read path bisa diuji tanpa redeploy.
  • Tenant atau dataset awal untuk rollout sudah dipilih dan disetujui.
  • Runbook insiden sudah dapat diakses on-call.

Otomasi pencegahan di CI/CD dan monitoring

Di CI/CD

  • Schema diff check: cegah perubahan skema yang memecahkan query canary atau retensi.
  • Query compatibility test: jalankan subset query acuan terhadap fixture atau environment uji.
  • Config lint: validasi flag rollout, timeout, kuota, dan fallback agar tidak salah konfigurasi.
  • Rollback drill otomatis: pastikan perubahan routing read path bisa dibalik oleh pipeline dengan satu perubahan konfigurasi.
  • Guardrail sampling: tolak rollout 100% jika divergence monitor belum hijau selama periode minimum.

Di monitoring

  • Alert freshness lag dengan ambang yang sesuai kebutuhan debugging.
  • Alert divergence untuk query canary di atas toleransi.
  • Alert fallback spike agar fallback otomatis tidak menyembunyikan masalah.
  • Alert storage growth anomaly berdasarkan tren, bukan hanya threshold statis.
  • Alert top query regression untuk dashboard prioritas.
# pseudo-policy untuk progressive rollout gate
rollout_gate:
  require:
    - ingest_freshness_ok
    - query_divergence_ok
    - dashboard_latency_ok
  block_if:
    - fallback_rate_high
    - storage_growth_anomaly
    - write_error_rate_high

Prinsipnya sederhana: jangan biarkan keputusan rollout hanya berdasarkan perasaan bahwa cluster terlihat sehat. Jadikan metrik dan guardrail sebagai syarat objektif untuk maju ke tahap berikutnya.

Template postmortem singkat

Gunakan format ringkas agar mudah diisi segera setelah insiden atau rollback.

Judul insiden:
Waktu mulai / selesai:
Dampak:
- Dashboard/tenant/dataset terdampak
- Gejala yang terlihat pengguna

Apa yang berubah:
- Flag rollout / perubahan schema / perubahan query / perubahan kapasitas

Timeline singkat:
- 10:05 rollout dual-write 20%
- 10:12 freshness lag naik
- 10:18 fallback read path aktif
- 10:25 dual-write dimatikan

Akar masalah:
- Misalnya: partisi terlalu granular menyebabkan write amplification dan backlog

Faktor kontribusi:
- Alert terlambat
- Query canary tidak mencakup dashboard tertentu
- Rollback write path belum terdokumentasi jelas

Apa yang berjalan baik:
- Read rollback cepat melalui feature flag

Apa yang gagal:
- Divergence monitor tidak mencakup metrik latency percentile

Tindakan pencegahan:
- Tambah CI check untuk schema partitioning
- Tambah alert storage growth anomaly
- Tambah kuota query untuk dashboard eksperimen
- Uji rollback drill mingguan

Penutup

Deployment bertahap untuk migrasi analytics tanpa ganggu produksi bukan sekadar teknik rollout, tetapi disiplin operasional. Untuk migrasi ke sistem kolom seperti ClickHouse, pola yang paling aman adalah memisahkan write dan read path, memulai dengan shadow traffic, melanjutkan dual-write terukur, memverifikasi hasil query secara sistematis, lalu mengaktifkan pembaca baru secara bertahap dengan rollback yang cepat.

Jika Anda hanya mengambil satu pelajaran, ambil ini: anggap migrasi analytics sebagai proses pembuktian operasional, bukan proyek pemindahan storage. Keberhasilan tidak ditentukan oleh apakah data masuk, tetapi oleh apakah data tetap benar, tepat waktu, terjangkau, dan bisa dihentikan dampaknya saat sesuatu berjalan salah.