Flash sale hari ulang tahun TokoKita melipatgandakan pesanan menjadi tiga kali lipat selama empat jam. Fleet worker ETL yang statis menghadapi dua pilihan buruk: disiapkan seukuran puncak (boros biaya selama 44 jam sepi berikutnya) atau disiapkan seukuran rata-rata (antrean menumpuk saat promo). Autoscaling menyelesaikan dilema ini dengan menambah worker saat beban naik dan menguranginya kembali saat beban turun. Chapter ini menyimulasikan kebijakan tersebut selama 48 jam dengan beban yang meniru pola harian toko sungguhan.
Konsep Dasar Autoscaling #
Autoscaling adalah kemampuan menambah atau mengurangi jumlah komponen secara otomatis berdasarkan sinyal beban — bentuk paling umum dari horizontal scaling yang sudah kita bahas di Chapter Horizontal vs Vertical Scaling. Tiga istilah kuncinya:
- Scale-out: menambah instance karena sinyal melewati ambang (misalnya queue depth naik).
- Scale-in: mengurangi instance karena sinyal turun kembali.
- Cooldown: jeda minimum antar aksi scaling, terutama scale-in, agar fleet tidak berdenyut naik-turun mengikuti noise.
Kebijakan paling praktik untuk pipeline data adalah target tracking: kita cukup menyatakan target — misalnya “maksimal 1000 task mengantre per worker” — dan sistem menghitung sendiri berapa worker yang dibutuhkan. Worker berbentuk container sebagaimana Chapter Container dan Docker, sehingga image yang sama bisa diperbanyak dalam hitungan menit.
Simulasi 48 Jam #
Simulasi berikut memodelkan 48 jam operasional TokoKita. Beban masuk mengikuti kurva harian (sepi dini hari, ramai malam), flash sale jam 19-22 hari pertama melipatgandakan beban tiga kali, dan noise acak dibangkitkan dengan seed tetap agar hasil dapat direproduksi. Kebijakan target tracking menaikkan target worker bila backlog melewati 1000 per worker, dengan provisioning delay satu jam; scale-in memakai ambang lebih longgar plus cooldown tiga jam.
"""Simulasi autoscaling worker ETL TokoKita selama 48 jam.
Kebijakan target tracking pada queue depth: target worker =
ceil(backlog / 1000) untuk scale-out, ambang lebih longgar (2500) untuk
scale-in dengan cooldown 3 jam. Worker baru efektif jam berikutnya
(provisioning delay). Seed tetap -> hasil deterministik.
"""
import math
import random
rng = random.Random(42)
JAM_TOTAL, KAPASITAS = 48, 1200 # jam, task per jam per worker
MIN_W, MAKS_W = 2, 20
KURVA = [0.4, 0.35, 0.3, 0.3, 0.35, 0.5, 0.7, 0.9, 1.0, 1.0, 1.0, 1.1,
1.1, 1.0, 1.0, 1.1, 1.2, 1.3, 1.5, 1.8, 1.8, 1.6, 1.2, 0.8]
def kedatangan(jam_ke):
"""Task masuk per jam; flash sale jam 19-22 hari pertama (x3)."""
dasar = 900 * KURVA[jam_ke % 24]
if 19 <= jam_ke % 24 <= 22 and jam_ke < 24:
dasar *= 3
return int(dasar * rng.uniform(0.9, 1.1))
backlog, aktif, target, ubah_terakhir = 300, 2, 2, -10
baris = []
for jam in range(JAM_TOTAL):
aksi = "-"
backlog += kedatangan(jam)
butuh = math.ceil(backlog / 1000) # ambang scale-out
if butuh > target:
target = min(butuh, MAKS_W)
aksi, ubah_terakhir = f"scale-out->{target}", jam
elif jam - ubah_terakhir >= 3: # cooldown scale-in
target_baru = max(math.ceil(backlog / 2500), MIN_W) # histeresis
if target_baru < target:
target, aksi, ubah_terakhir = target_baru, f"scale-in->{target_baru}", jam
diproses = min(backlog, aktif * KAPASITAS) # worker AKTIF memproses
backlog -= diproses
baris.append((jam, aktif, target, diproses, backlog, aksi))
aktif = target # provisioning jam depan
print("jam aktif target diproses backlog aksi")
for jam, a, t, p, b, aksi in baris:
print(f"{jam:>3} {a:>5} {t:>6} {p:>8} {b:>6} {aksi}")
maks_b = max(b[4] for b in baris)
jam_b = [b[0] for b in baris if b[4] == maks_b][0]
wjam = sum(b[1] for b in baris)
maks_w = max(b[2] for b in baris)
print(f"\nbacklog puncak {maks_b} (jam {jam_b}); target worker puncak {maks_w}")
print(f"total {wjam} worker-jam: on-demand ${wjam*0.12:.2f}, "
f"spot ${wjam*0.036:.2f} (diskon 70%)")
print(f"fleet statis puncak: {maks_w*JAM_TOTAL} worker-jam "
f"(${maks_w*JAM_TOTAL*0.12:.2f})")Output yang Dihasilkan (potongan tabel 48 jam — header dan jam 16-27; baris jam 0-15 dipangkas, hari kedua fleet stabil di 2 worker):
jam aktif target diproses backlog aksi
16 2 2 1019 0 -
17 2 2 1190 0 -
18 2 2 1433 0 -
19 2 5 2400 1980 scale-out->5
20 5 8 6000 1137 scale-out->8
21 8 8 5628 0 -
22 8 8 3136 0 -
23 8 2 670 0 scale-in->2
24 2 2 392 0 -
25 2 2 304 0 -
26 2 2 248 0 -
27 2 2 248 0 -Output yang Dihasilkan (ringkasan akhir simulasi):
backlog puncak 1980 (jam 19); target worker puncak 8
total 117 worker-jam: on-demand $14.04, spot $4.21 (diskon 70%)
fleet statis puncak: 384 worker-jam ($46.08)Mari kita telaah baris-baris kode di atas:
- Baris 18-23 (
kedatangan): beban per jam = kurva harian × faktor acak 0,9-1,1. Generatorrngber-seed membuat seluruh simulasi deterministik — menjalankan ulang menghasilkan tabel yang sama. - Baris 26 (state):
backlogadalah sisa antrean,aktifjumlah worker yang benar-benar memproses,targetukuran fleet yang diinginkan kebijakan. Pemisahanaktifdantargetinilah yang memodelkan provisioning delay. - Baris 32-39 (kebijakan): scale-out langsung menaikkan target ke
ceil(backlog/1000), sedangkan scale-in baru boleh jalan tiga jam setelah perubahan terakhir dan memakai ambang 2500 yang lebih longgar — histeresis mencegah worker dilepas terlalu dini lalu diminta kembali. - Baris 41-44 (eksekusi): yang memproses adalah
aktif, bukantarget. Baris terakhiraktif = targetmenyimulasikan worker yang baru saja diminta baru siap bekerja pada jam berikutnya.
Dua angka dari output layak digarisbawahi. Backlog puncak 1980 task pada jam 19 terjadi karena worker baru butuh satu jam untuk siap — autoscaling cepat, tetapi tidak seketika. Total 117 worker-jam berbanding 384 worker-jam untuk fleet statis berukuran puncak: biaya komputasi turun 70 persen hanya dengan mengikuti kurva beban.
Autoscaling vs Scheduled Scaling #
Bila pola beban benar-benar teratur, scaling terjadwal adalah alternatif yang lebih sederhana:
| Aspek | Autoscaling (reaktif) | Scheduled scaling |
|---|---|---|
| Pemicu | metrik (queue depth, CPU) | waktu (cron/jadwal) |
| Menangani beban tak terduga | ya, menyesuaikan otomatis | tidak — jadwal salah berarti salah ukuran |
| Kompleksitas | butuh metrik dan ambang yang benar | sekadar kalender |
| Cocok untuk | beban tidak terduga, streaming | job batch malam yang pasti jamnya |
Praktik umum menggabungkan keduanya: scheduled scaling menyiapkan kapasitas dasar menjelang jam sibuk yang diketahui, dan autoscaling menangani kejutan di atasnya.
Spot Instance untuk Worker Fleksibel #
Worker ETL bersifat interruptible: bila satu worker dihentikan, task yang diambil dikembalikan ke antrean dan diproses worker lain. Beban seperti ini adalah kandidat sempurna untuk spot instance (AWS) atau preemptible VM (GCP) — kapasitas surplus penyedia dengan diskon besar, dengan konsekuensi bisa diberi tahu berhenti kapan saja. Pada simulasi kita, harga spot $0.036/jam memangkas biaya 48 jam dari $14.04 menjadi $4.21. Aturannya sederhana: jangan pernah menaruh komponen yang menyimpan state penting di spot tanpa mekanisme checkpoint.
Referensi resmi kebijakan target tracking ada di Amazon EC2 Auto Scaling User Guide , dan untuk fleet container di Kubernetes di Horizontal Pod Autoscaler .
Fleet yang elastis menjaga biaya dan kecepatan pemrosesan, tetapi autoscaling tidak melindungi kita dari bencana yang lebih besar: kehilangan data dan region. Chapter Backup dan Disaster Recovery menyusun pertahanan berikutnya.