Continuous integration memastikan kode yang digabungkan aman; continuous deployment (CD) menempatkannya di depan pengguna. Untuk model machine learning, langkah ini lebih berisiko daripada perangkat lunak biasa: pengujian pra-produksi tidak pernah menjamin perilaku pada data nyata, dan kegagalan model jarang berupa crash yang langsung terlihat — prediksi yang salah tetap menghasilkan angka sah. Karena itu CD untuk ML dibangun di sekitar satu prinsip: rilis bertahap dengan pengukuran, dan pintu keluar yang selalu terbuka. Chapter ini membandingkan strategi rilis, lalu mensimulasikan canary yang benar-benar mengambil keputusan promote atau abort.

Tiga Strategi Rilis #

StrategiCara kerjaRisiko utama
big-bangv2 langsung menggantikan v1 untuk seluruh trafficseluruh pengguna terdampak bila v2 bermasalah
blue-greenv2 berjalan paralel; alihkan seluruh traffic sekaligus bila sehatpemborosan sumber daya saat keduanya aktif; lompatan tetap serentak
canarysebagian kecil traffic (misal 10%) mencoba v2 dulu, naik bertahapkeputusan butuh metrik andal; jendela evaluasi bisa lama
shadowv2 menerima salinan traffic tetapi jawabannya tidak dikirim ke penggunabiaya inference ganda; butuh infrastruktur khusus

Canary menjadi pilihan umum untuk model karena kerugiannya terukur: bila 10% traffic memakai v2 dan v2 bermasalah, 90% pengguna tidak pernah menyentuhnya. Shadow menambah keamanan satu tingkat lagi — pengguna sepenuhnya tidak terdampak — dengan membayar biaya komputasi ganda pada seluruh traffic.

Alur keputusan canary membentuk tangga dengan dua pintu keluar:

Promotion Gate dan Rollback Otomatis #

Dua mekanisme menjaga tangga tersebut. Promotion gate adalah ambang metrik yang harus terpenuhi sebelum traffic naik — error rate, latensi P95, atau metrik bisnis — dievaluasi pada jumlah request yang cukup besar agar keputusan tidak dibuat dari tiga sampel. Rollback otomatis adalah kebalikannya: metrik yang melampaui ambang pada langkah mana pun mengembalikan seluruh traffic ke v1 tanpa menunggu manusia bangun. Mekanisme lengkap menyiapkan versi lama tetap termuat (warm standby) sehingga pengalihan hanya mengubah rute, bukan memuat ulang model — pola yang akan kita buktikan di chapter Rollback dan Model Update .

Contoh Teruji: Simulasi Canary #

Berkas canary_mini.py menjalankan dua skenario dengan metrik dari RNG berseed — deterministik namun berperilaku seperti data nyata. Skenario A menguji v2 sehat; skenario B menguji v2 bermasalah:

python
"""Simulasi canary deployment mini untuk model versi baru.

Versi lama (v1) dan versi baru (v2) melayani traffic secara bertahap:
10% -> 50% -> 100%. Setiap langkah mengukur error rate pada sampel
request (RNG berseed), lalu memutuskan lanjut, atau abort dan
mengembalikan seluruh traffic ke v1. Dua skenario dijalankan:
v2 sehat dan v2 bermasalah.
"""

import numpy as np

AMBANG_ERROR = 0.05   # batas error rate yang masih dapat diterima
N_REQUEST = 300       # jumlah request per langkah evaluasi


def ukur_error(rng, p_error):
    """Error rate dari N_REQUEST sampel binomial — deterministik."""
    return rng.binomial(N_REQUEST, p_error) / N_REQUEST


def jalankan_canary(nama, p_error_v2, seed):
    """Naikkan traffic v2 bertahap; ukur; putuskan lanjut atau abort."""
    rng = np.random.default_rng(seed)
    for persen in (10, 50, 100):
        error = ukur_error(rng, p_error_v2)
        status = "OK" if error <= AMBANG_ERROR else "MELEBIHI AMBANG"
        print(f"  [{nama}] traffic v2 {persen:>3}% | error rate "
              f"{error:.3f} | {status}")
        if error > AMBANG_ERROR:
            print("  -> ABORT: canary dihentikan, 100% traffic "
                  "kembali ke v1")
            return "abort"
    print("  -> PROMOTE: v2 melayani 100% traffic, v1 siap rollback")
    return "promote"


def main():
    print(f"ambang error rate : {AMBANG_ERROR}")
    print(f"request per langkah evaluasi : {N_REQUEST}")

    print("\n== baseline v1 (seluruh traffic) ==")
    rng_v1 = np.random.default_rng(seed=7)
    error_v1 = ukur_error(rng_v1, 0.010)
    print(f"  [v1] error rate {error_v1:.3f} — acuan tolak ukur")

    print("\n== skenario A: v2 sehat (error serupa v1) ==")
    hasil_a = jalankan_canary("A", p_error_v2=0.012, seed=11)

    print("\n== skenario B: v2 bermasalah (error tinggi) ==")
    hasil_b = jalankan_canary("B", p_error_v2=0.140, seed=13)

    print("\n== keputusan akhir ==")
    print(f"skenario A -> {hasil_a}: v2 menggantikan v1 secara penuh")
    print(f"skenario B -> {hasil_b}: v2 tidak pernah melewati 10% traffic")
    print("dampak skenario B terbatas: hanya sebagian kecil request "
          "mencoba v2")


if __name__ == "__main__":
    main()

Output yang Dihasilkan:

text
ambang error rate : 0.05
request per langkah evaluasi : 300

== baseline v1 (seluruh traffic) ==
  [v1] error rate 0.010 — acuan tolak ukur

== skenario A: v2 sehat (error serupa v1) ==
  [A] traffic v2  10% | error rate 0.007 | OK
  [A] traffic v2  50% | error rate 0.010 | OK
  [A] traffic v2 100% | error rate 0.013 | OK
  -> PROMOTE: v2 melayani 100% traffic, v1 siap rollback

== skenario B: v2 bermasalah (error tinggi) ==
  [B] traffic v2  10% | error rate 0.107 | MELEBIHI AMBANG
  -> ABORT: canary dihentikan, 100% traffic kembali ke v1

== keputusan akhir ==
skenario A -> promote: v2 menggantikan v1 secara penuh
skenario B -> abort: v2 tidak pernah melewati 10% traffic
dampak skenario B terbatas: hanya sebagian kecil request mencoba v2

Mari kita telaah kode di atas baris per baris:

  1. Baris 16-18 (ukur_error): error rate dihitung dari sampel binomial(N_REQUEST, p_error) — jumlah request gagal dari 300. Menariknya, hasil per langkah berbeda-beda (0.007, 0.010, 0.013) meski peluang dasarnya sama: persis perilaku pengukuran nyata yang berisik, dan alasan jumlah sampel per langkah harus cukup besar.
  2. Baris 21-35 (jalankan_canary): seluruh strategi canary dalam satu fungsi pendek. Tangga (10, 50, 100) didefinisikan sebagai data; setiap langkah mengukur lalu memutuskan lanjut atau berhenti. Kembalian "abort" atau "promote" membuat fungsi ini bisa dipanggil sistem lain — bentuk yang sama dengan promotion gate sungguhan.
  3. Baris 42-44 (baseline v1): sebelum canary dimulai, v1 diukur dulu (error 0.010). Ambang 0.05 dipilih beberapa kali lipat di atas baseline — ambang yang hanya sedikit di atas derau pengukuran akan memicu abort karena fluktuasi normal.
  4. Baris 46-50 (dua skenario): perbedaan A dan B hanya satu parameter — p_error_v2 0.012 lawan 0.140. Skenario A melewati tiga langkah dan promote; skenario B gagal di langkah pertama, sehingga v2 tidak pernah melayani lebih dari 10% traffic.
  5. Baris 52-57 (keputusan akhir): ringkasan menegaskan inti canary: pada skenario B, eksposur pengguna terhadap v2 dibatasi sejak awal. Tanpa canary (big-bang), seluruh traffic mengalami error rate 0.14 selama jendela waktu sampai manusia bereaksi.

Perhatikan satu detail pada skenario B: abort terjadi setelah satu langkah evaluasi melebihi ambang — untuk keputusan traffic, kita sengaja memilih berhenti cepat. Sebaliknya untuk rollback model yang sudah full-deploy, konvensi yang dipakai chapter Rollback dan Model Update adalah menunggu dua jendela berturut-turut agar tidak reaksi berlebihan terhadap lonjakan sesaat. Kedua konvensi itu tidak bertentangan: makin besar eksposur, makin besar alasan menunggu konfirmasi.

Canary mengelola rilis versi baru ke pengguna. Setelah rilis, pertanyaan berubah menjadi: apakah dunia tempat model bekerja masih seperti saat ia dilatih? Chapter berikutnya, Data dan Model Drift , mengukur pergeseran yang terjadi diam-diam.