Dua pekan data pemantauan kini tergeletak di folder tim sebagai berkas-berkas CSV, dan isinya membuka jendela yang tidak pernah kita punya sebelumnya: puncak nyata setiap service, jam datangnya, dan seberapa sering ia kembali. Pertanyaan yang sepanjang section ini dijawab dengan tebakan — “berapa limit yang benar untuk service ini?” — kini punya jawaban yang bisa dihitung. Chapter penutup ini merangkai seluruh perangkat menjadi praktik produksi yang utuh: right-sizing dari data p95, kebijakan anggaran per kelas service, perhitungan yang jujur sampai ke tagihan cloud, peluncuran limit baru secara bertahap, sampai runbook saat kegentingan datang — lalu menutup Section Manajemen Resource dengan satu checklist yang bisa diaudit siapa pun.

Right-sizing: P95 dan Headroom #

Kesalahan klasik penetapan limit adalah bertanya ke rata-rata. Rata-rata pemakaian backend tercatat 120 MB — angka yang manis dan menenangkan — padahal puncak jam sibuknya menembus 380 MB, dan OOM tidak terjadi di rata-rata melainkan di puncak. Ukuran yang tepat untuk keputusan limit adalah p95: nilai pemakaian yang hanya dilampaui 5% dari waktu pengamatan. P95 mengabaikan pencilan satu detik yang tidak berarti, tetapi tetap memegang kebenaran bahwa aplikasi harus selamat dari jam sibuk tiap hari.

Formula turunannya sederhana dan simetris: reservasi ditulis kira-kira sebesar p95 — jaminan penempatan yang jujur untuk penjadwal Swarm dari Chapter Resource di Swarm — sedangkan limit ditulis sekitar p95 dikali 1,3 sebagai langit-langit dengan ruang napas 30%, lalu dibulatkan ke angka yang sehat. Dari data pemantauan tim, tabelnya terbaca sebagai berikut:

Servicep95 terukurReservasiLimit finalCatatan angka
backend380 MB400m512m380 × 1,3 ≈ 494, dibulatkan ke 512m
db2,1 GB2g4gp95 × 1,3 ≈ 2,7; dinaikkan ke 4g karena tren cache naik tiap pekan
cache90 MB128m192mmaxmemory 128mb ditambah overhead proses Redis
proxy dan frontenddi bawah 20 MB64m128mberkas statis, puncaknya pun kecil

Tiga catatan melengkapi tabel itu. Pertama, db di staging sengaja diberi limit longgar 8g selama masa pengukuran — setelah kejadian flash sale pada Chapter Overcommit dan Noisy Neighbor, tim menaikkan angkanya darurat lalu membiarkannya longgar agar p95 yang terbaca adalah kebutuhan sungguhan, bukan pantulan langit-langit yang sempit; p95 2,1 GB adalah hasil pengukuran itu, dan 4g dipilih dengan ruang tumbuh karena tren cache PostgreSQL yang mendaki setiap pekan. Kedua, p95 bukan monopoli memori: backend yang menunjukkan 22% throttle berkelanjutan pada kuota cpus: "1.0" dinaikkan ke 1.5 — data throttle adalah argumen, bukan perasaan. Ketiga, cache mendapat pagar ganda yang selaras: maxmemory mengatur evict kunci di dalam Redis, limit cgroup 192m menjaga kernel tetap mengenal batasnya.

Kebijakan per Kelas Service #

Menetapkan angka satu per satu untuk tiap service baru adalah pekerjaan yang tidak skalabel. Kebijakan per kelas memotong pekerjaan itu: setiap service baru tinggal memilih kelasnya, lalu menyalin pola angkanya sebagai titik awal sebelum datanya sendiri berkumpul:

KelasContoh di tokocpusMemory limitReservasi memori
frontend statisproxy, frontend0,25128m64m
api statelessbackend1,5512m400m
data beratdb2,04g2g
pekerja latarworker-gambar1,01g512m

Untuk node produksi 16 GB yang direncanakan tim, kebijakan itu menjelma anggaran yang bisa diaudit:

Penghuni node 16 GBReservasiLimit
db2g4g
backend 2 replika2 × 400m2 × 512m
worker-gambar512m1g
cache128m192m
proxy dan frontend2 × 64m2 × 128m
Total±3,5g±6,7g

Total reservasi 3,5 GB berarti penjadwal cluster masih melihat ruang lega untuk task tambahan, dan total limit 6,7 GB terhadap RAM 16 GB adalah overcommit ringan yang tertib — puncak bersama yang terukur 5,5 GB masih menyisakan ruang aman. Angka-angka ini ditulis dalam deploy.resources di compose.yaml produksi, sehingga kebijakan dan pelaksanaannya tidak pernah berpisah.

Cloud: Ukur dari Reservasi, Bukan dari Limit #

Di cloud, anggaran resource berubah wujud menjadi tagihan bulanan, dan satu kekeliruan membaca tabel di atas bisa menggandakannya. Ukuran instance yang tepat dihitung dari total reservasi ditambah puncak terukur ditambah ruang napas — bukan dari total limit. Dengan reservasi 3,5 GB dan puncak nyata 5,5 GB, instance 8 GB sudah memadai; mengukur dari total limit 6,7 GB lalu menambah “jaga-jaga” akan mendorong tim ke instance 12–16 GB, dan selisihnya terbayar setiap bulan untuk puncak yang tidak pernah datang.

Bedahnya perlu satu kalimat yang tegas: limit bukan tagihan. Menulis memory: 4G pada db tidak menagih apa pun — limit hanyalah langit-langit yang boleh tidak pernah tersentuh. Yang menuntut kapasitas sungguhan — dan dengan itu tagihan — adalah reservasi (yang menuntut penjadwal menyiapkan tempat) dan puncak nyata (yang benar-benar memakai RAM). Karena itu limit yang membengkak tidak langsung menagih, tetapi menggoda tim menaikkan ukuran mesin “untuk jaga-jaga”, dan di situlah uang terbakar diam-diam. Jalan keluarnya dua macam: turunkan limit yang memang tidak pernah tersentuh agar buku anggaran jujur, atau — untuk beban yang memang bergelombang — serahkan penambahan kapasitas pada autoscaling horizontal: orchestrator menambah replika saat beban naik dan memangkasnya saat turun, sehingga kapasitas mengikuti kurva permintaan. Mekanika autoscaling adalah materi Section Orchestration dan Ekosistem pada Chapter Pengantar Container Orchestration; yang penting bagi anggaran hari ini adalah prinsipnya — replika ber-reservasi kecil yang datang dan pergi lebih murah daripada mesin besar yang menganggur.

Meluncurkan Limit Baru Secara Bertahap #

Limit yang berubah adalah eksperimen pada sistem hidup, dan eksperimen tidak dijalankan pada seluruh pengguna sekaligus. Urutan peluncuran yang dipakai tim toko:

TahapTindakanBukti sehat sebelum lanjut
1. Kandidatterapkan limit baru pada satu replika atau satu host ujicontainer hidup, tidak ada restart tak terduga
2. Pengamatanbiarkan 1–2 hari: throttle, MEM %, oom di memory.events, dan error rate aplikasithrottle di bawah 20%, MEM % di bawah 85%, tidak ada oom baru
3. Rollout penuhangkat ke seluruh replika lewat docker compose up -dstats merata antar replika, error rate stabil
4. Mundurbila memburuk: kembalikan angka lama dari Git, darurat lewat docker update—

Dua hal pada tabel itu sering terlewat. Pertama, pengamatan tahap dua mencakup error rate aplikasi — galat 5xx yang naik tipis dan latensi p95 yang melebar adalah gejala kelaparan resource yang tidak pernah tampil di docker stats. Kedua, di dunia Compose murni, “satu replika” didekati lewat host uji atau project berdampingan dengan flag -p; canary yang mengalirkan trafik sungguhan ke sebagian kecil pengguna adalah fitur bawaan orchestrator, dan itu satu lagi alasan menunggu Section Orchestration dan Ekosistem.

Aplikasi Berat: JVM dan Limit Container #

Saat tim menambahkan service pelaporan berbasis Java, satu kelas masalah baru ikut masuk: runtime yang mengatur dirinya sendiri di atas memori. JVM menentukan besar heap-nya saat menyala, dan container limit tidak dihitung ke dalam keputusan itu kecuali JVM diberi tahu. JVM modern menyediakan persentase yang dihitung dari batas container:

dockerfile
CMD ["java", "-XX:MaxRAMPercentage=75.0", "-jar", "laporan.jar"]

Baris tersebut menyuruh JVM mengalokasikan heap maksimal 75% dari limit container — sisanya 25% disisakan untuk metaspace, thread stack, dan buffer di luar heap yang tetap dihitung cgroup. Jalur eksplisit yang lebih tua juga sah: java -Xmx384m mematok heap 384 MB pada container ber-limit 512m, dengan syarat seluruh pemakaian di luar heap ikut diperhitungkan.

Runtime lain kebanyakan sudah sadar container — Node.js dan Go membaca limit cgroup dengan benar — sehingga JVM tua adalah pengecualian paling terkenal, bukan aturan umum. Pelajarannya tetap berlaku luas: aplikasi yang mengelola memori sendiri harus diberi tahu tentang pagar, karena cgroup membatasi tanpa bernegosiasi.

Runbook: Container Lambat #

Sisa satu perangkat adalah prosedur tertulis untuk kegentingan — karena kegentingan bukan waktu yang baik untuk berpikir dari nol. Ini runbook mini tim toko untuk keluhan paling umum, “API-nya lambat”, tiap langkahnya memakai perangkat yang sudah kita kuasai:

LangkahPerintah atau tindakanYang dibaca
1docker stats --no-streamsiapa yang CPU %-nya menempel kuota, MEM % di atas 90%
2docker compose exec backend cat /sys/fs/cgroup/cpu.statnr_throttled yang menanjak → kunci CPU
3free -m dan swapon --show di hostswap yang aktif membengkak → kunci memori host
4docker update --cpus 1.5 toko-backend-1darurat: kuota dinaikkan tanpa recreate — senjata Chapter Docker Update
5sunting compose.yaml lalu commitpermanen: darurat adalah jembatan, bukan tempat tinggal

Langkah keempat dan kelima adalah pasangan yang tidak boleh berpisah. docker update menyelamatkan malam itu tanpa mematikan layanan, tetapi perbaikan itu hidup hanya selama container-nya — beginilah cara kerjanya yang kita pelajari pada Chapter Docker Update dan alasan seluruh perjalanan section ini berawal. Keesokan paginya, angka yang sama harus sudah duduk di compose.yaml, direview, dan di-commit; runbook yang berakhir di langkah empat hanyalah utang yang menunggi.

Checklist Akhir Section #

Tujuh pertanyaan berikut merangkum seluruh Section Manajemen Resource sebagai audit yang bisa dijalankan siapa pun terhadap stack mana pun:

  1. Setiap service punya limit cpus dan memory eksplisit di compose.yaml — tidak ada yang mengandalkan kebetulan host-nya besar.
  2. Reservasi ditulis dari p95 terukur, bukan dari limit yang dipotong separuh secara buta.
  3. Total reservasi per node di bawah kapasitas dengan ruang napas, dan total limit diperiksa terhadap puncak bersama yang terukur.
  4. Overcommit memori dijaga konservatif — puncak bersama di bawah sekitar 80% RAM — sementara overcommit CPU diperbolehkan dan dipantau lewat throttle.
  5. Pemantauan tren berjalan: ambang throttle, MEM %, PIDS, dan oom punya pemilik, ritme, dan kanal alert.
  6. Aplikasi sadar batasnya — heap JVM dan buffer aplikasi lain disetel di bawah limit container, bukan di bawah RAM host.
  7. Jalur darurat pernah dilatih dan setiap darurat selalu berakhir dengan perbaikan compose.yaml yang di-commit.

Section Manajemen Resource menutup perjalanannya di sini, dan jarak tempuhnya layak direnungkan sejenak: kita berangkat dari satu flag --memory di Section Konfigurasi Container, membedah cgroups sampai ke berkas-berkasnya, memasang pagar CPU, memori, proses, dan I/O, memindahkan semuanya ke compose.yaml, meminjam mata penjadwal Swarm, menakar overcommit dan tetangga yang berisik, merekam tren, dan berakhir di kebijakan anggaran yang bisa dijelaskan sampai ke tagihan cloud. Resource kini dikuasai penuh — dari flag tunggal sampai keputusan produksi. Tetapi toko yang sebenarnya belum berdiri: masih ada sertifikat TLS yang harus terpasang, backup yang harus terjadwal, image produksi yang harus ramping, dan checklist go-live yang harus lulus audit. Seluruh bekal teknis sudah di tangan; yang tersisa adalah membawanya ke medan sesungguhnya. Section Deployment dan Production membuka medan itu, dimulai dari Chapter Persiapan Production Image.

Referensi #