Server yang menjawab ping belum tentu melayani pelanggan. Kernel bisa hidup dan load rata-rata rendah, sementara aplikasi web di dalamnya mati lemas karena koneksi database terputus — dan satu-satunya pihak yang sadar adalah pengguna yang gagal checkout. Monitoring yang baik membalik urutannya: sistem kita yang tahu lebih dulu, pengguna yang mendapat maaf. Chapter ini membedah beda antara uptime dan health, merancang endpoint /healthz, lalu membangun health check sungguhan dengan curl dan skrip yang punya timeout, retry, dan exit code yang jujur. Latihannya memakai server HTTP lokal yang hidup sesaat — semua deterministik, dan hasilnya bisa Anda bandingkan baris demi baris.
Uptime Bukan Health #
Uptime mengukur hidupnya mesin; health mengukur bergunanya layanan. Dua kata ini sering dianggap sama padahal menjawab pertanyaan yang berbeda, dan tiap lapisan pemeriksaan hanya membuktikan lapisan di bawahnya:
| Lapisan check | Contoh | Yang dibuktikan | Yang tidak dibuktikan |
|---|---|---|---|
| ICMP ping | ping 192.0.2.20 | network stack hidup | aplikasi ikut hidup |
| port TCP | port 443 terbuka | ada proses yang mendengarkan | request diproses berhasil |
| endpoint HTTP | curl 192.0.2.20/healthz | aplikasi merespons | dependensinya (DB, cache) siap |
| deep check | /healthz mengecek koneksi DB | seluruh rantai siap | beban pengguna sesungguhnya |
Mengukur uptime dengan ping saja adalah jebakan klasik: skrip ping yang berhasil setiap menit tidak akan berbunyi ketika nginx hidup tetapi aplikasi di belakangnya mengembalikan error 500 ke semua pengunjung. Karena itu lapisan ketiga — endpoint health milik aplikasi sendiri — adalah standar minimum, dan lapisan keempat menjadikannya bermakna.
Merancang Endpoint /healthz #
Endpoint health kecil tetapi punya kontrak yang ketat. Aturan utamanya: status HTTP 200 berarti sehat, dan selain 200 berarti tidak — jangan pernah mengembalikan 200 dengan body berisi pesan error, karena pemeriksa berbasis curl hanya melihat status code. Body biasanya JSON supaya mesin bisa membacanya:
{"status": "ok", "db": "ok", "queue": "ok"}Tiga aturan lanjutan menjaga endpoint ini tetap berguna. Pertama, ia harus murah — dipanggil tiap 10 detik oleh monitor, jangan melakukan query berat; deep check yang menyentuh database sebaiknya berjalan lebih jarang lewat endpoint terpisah (misalnya /readyz). Kedua, tanpa efek samping — health check tidak boleh menulis log atau mengubah state. Ketiga, tanpa autentikasi untuk pemeriksaan internal — monitor sederhana tidak membawa kredensial. Prinsip ini nanti nyambung ke curl yang kita pakai di latihan: curl dan wget
adalah klien HTTP paling sederhana untuk pekerjaan ini.
Latihan: /healthz Sungguhan dengan Server Lokal #
Kita nyalakan aplikasi mini — direktori berisi file healthz yang disajikan oleh python3 -m http.server — lalu periksa dengan curl dan skrip cek-kesehatan.sh dari bundle chapter ini:
mkdir -p webroot
printf '{"status":"ok","db":"ok"}\n' > webroot/healthz
python3 -m http.server 8642 --bind 127.0.0.1 --directory webroot >/dev/null 2>&1 &
pid=$!
for i in 1 2 3 4 5 6 7 8 9 10; do
curl -s 127.0.0.1:8642/healthz >/dev/null 2>&1 && break
sleep 0.2
done
curl -s -w 'HTTP %{http_code}\n' 127.0.0.1:8642/healthz
bash cek-kesehatan.sh 127.0.0.1:8642/healthz 2
kill "$pid" 2>/dev/null
wait "$pid" 2>/dev/null
echo "server latihan dimatikan"Output yang Dihasilkan:
{"status":"ok","db":"ok"}
HTTP 200
SEHAT (HTTP 200)
server latihan dimatikanBedah blok di atas:
printf ... > webroot/healthz: isi endpoint — satu baris JSON, persis kontrak yang kita rancang di atas.python3 -m http.server ... &: server “aplikasi” berjalan di belakang, dengan stdout/stderr dibuang ke/dev/nullagar output blok tetap bersih. Port 8642 dipilih sembarang agar tidak bertabrakan dengan layanan lain.for i in 1..10; do curl ... && break; sleep 0.2; done: loop tunggu-siap — server butuh sepersekian detik untuk hidup; loop ini mendeteksi kesiapan tanpa mencetak apa pun, sehingga output tetap deterministik.curl -s -w 'HTTP %{http_code}\n':-ssunyi,-wmenambahkan status code — ini dia;200adalah satu-satunya jawaban sehat.bash cek-kesehatan.sh ... 2: skrip pemeriksa memanggil endpoint yang sama dengan maksimal 2 percobaan.kill,wait, laluecho: mematikan server dan membesihkan proses latarnya. Barisechoterakhir bukan hiasan —waitmengembalikan exit status proses yang dibunuh (143, karena SIGTERM), dan status itulah yang jadi exit code blok; satu perintah sukses di akhir memastikan blok dilaporkan berhasil, pola yang sama denganexit 0di skrip.
Timeout dan Retry: cek-kesehatan.sh #
Satu kegagalan ping tidak berarti mati — jaringan bisa sesekali tersendat. Skrip pemeriksa yang baik memberi napas: --max-time 2 membatasi satu percobaan dua detik (curl mengembalikan code 000 bila gagal koneksi), dan beberapa percobaan beruntun menjadi syarat menyalakan alarm. Berikut isi inti skrip dari bundle:
kode=$(curl -s -o /dev/null -w '%{http_code}' --max-time 2 "$url"): satu percobaan —-o /dev/nullmembuang body,-w '%{http_code}'mengambil status,--max-timemenahan agar tidak menggantung selamanya.if [ "$kode" = "200" ]: satu-satunya jalan pulang yang sehat;exit 0memberi tahu pemanggil bahwa layanan baik-baik saja.[ "$i" -lt "$maks" ] && sleep 1: jeda antar percobaan hanya bila masih ada percobaan berikutnya.exit 1di baris terakhir: setelah semua percobaan gagal, skrip keluar dengan status gagal — exit code inilah yang dibaca cron, systemd, dan pipeline CI.
Sekarang kita lihat perilakunya ketika tidak ada yang mendengarkan di port 8643 — inilah kondisi “aplikasi mati” yang sesungguhnya:
bash cek-kesehatan.sh 127.0.0.1:8643/healthz 3Output yang Dihasilkan:
percobaan 1/3 gagal (HTTP 000)
percobaan 2/3 gagal (HTTP 000)
percobaan 3/3 gagal (HTTP 000)
TIDAK SEHAT (3/3 gagal)Tiga percobaan, tiga gagal, exit code 1 — dan 000 yang tercetak adalah tanda curl tidak pernah berhasil terhubung, bukan server menolak. Berbeda dari HTTP 500 (server hidup, aplikasi error), 000 berarti tidak ada jawaban sama sekali. Beda dua kondisi ini penting saat diagnosis: yang pertama masalah aplikasi, yang kedua masalah jaringan atau proses.
Kebijakan Alert: Membangunkan yang Tepat #
Alert adalah sumber daya mahal: setiap halaman membangunkan manusia. Karena itu rutenya dibagi menurut urgensinya:
| Saluran | Sifat | Contoh kondisi |
|---|---|---|
| SMS / panggilan on-call | membangunkan | service down lebih dari 5 menit |
| chat tim (Slack dsb.) | perlu perhatian cepat | tingkat error naik dua kali lipat |
| email ringkasan harian | tidak mendesak | tren pemakaian disk, jumlah warning |
Dua penyakit alert yang paling sering: threshold terlalu sensitif (alarm bunyi untuk hal yang bisa menunggu pagi) dan banjir alert (ratusan notifikasi membuat yang kritis ikut diabaikan — dikenal sebagai alert fatigue). Obatnya dua: syarat kegagalan beruntun (misalnya 3 kali berturut-turut) dan dedup — alert dikirim sekali sampai keadaan pulih. Kita praktikkan keduanya dengan fixture aturan-alert.txt plus loop monitor mini:
cat aturan-alert.txt
echo "--- simulasi monitor (interval dipendekkan) ---"
gagal=0
sudah_alert=0
for i in 1 2 3 4; do
if curl -s --max-time 1 127.0.0.1:8643/healthz >/dev/null 2>&1; then
echo "putaran $i: SEHAT"
gagal=0
sudah_alert=0
else
gagal=$((gagal+1))
echo "putaran $i: GAGAL (beruntun $gagal)"
if [ "$gagal" -ge 3 ] && [ "$sudah_alert" -eq 0 ]; then
echo ">>> ALERT: api-toko gagal $gagal kali berturut-turut — SMS on-call"
sudah_alert=1
fi
fi
sleep 1
doneOutput yang Dihasilkan:
service : api-toko
check : 192.0.2.20/healthz
interval : 10 detik
gagal_min : 3 kegagalan beruntun
rute : SMS ke on-call (sekali saja, sampai pulih)
--- simulasi monitor (interval dipendekkan) ---
putaran 1: GAGAL (beruntun 1)
putaran 2: GAGAL (beruntun 2)
putaran 3: GAGAL (beruntun 3)
>>> ALERT: api-toko gagal 3 kali berturut-turut — SMS on-call
putaran 4: GAGAL (beruntun 4)Bedah logikanya:
cat aturan-alert.txt: kebijakan dibaca sebelum dijalankan — service, URL, interval, ambang 3 kegagalan beruntun, dan rutenya. Di sistem nyata, berkas semacam ini adalah aturan Prometheus atau konfigurasi layanan monitoring eksternal.gagal=$((gagal+1))dan reset saat sehat: penghitung kegagalan beruntun — dua gagal lalu satu berhasil berarti hitungan mulai dari nol lagi; ini yang menyaring kedut jaringan sesaat.[ "$gagal" -ge 3 ] && [ "$sudah_alert" -eq 0 ]: alert hanya menyala pada kegagalan ketiga, dan benderasudah_alertmenjaganya tetap satu — perhatikan putaran 4 tidak lagi mengirim SMS walau tetap gagal.sleep 1: interval antar pemeriksaan; di produksi nilainya dariintervaldi aturan (10 detik).
Layanan pihak ketiga seperti UptimeRobot memeriksa dari luar (memvalidasi jalur DNS sampai aplikasi), sedangkan Prometheus blackbox exporter memeriksa dari dalam jaringan kita secara berkala terjadwal — keduanya menjalankan logika yang sama seperti loop di atas.
SLA, SLO, dan Error Budget #
Ketersediaan akhirnya bicara angka. SLA adalah janji ke pelanggan dalam persentase, dan persentase itu punya arti nyata dalam menit per bulan (30 hari):
| SLA | Downtime yang diizinkan per bulan |
|---|---|
| 99% | sekitar 7 jam 12 menit |
| 99.9% | sekitar 43 menit |
| 99.99% | sekitar 4 menit |
Di dalam organisasi, targetnya dinamakan SLO. Sisi praktisnya: selisih antara 100% dan SLO adalah error budget — jumlah gangguan yang masih “diizinkan” bulan itu. Tim yang error budget-nya menipis sebaiknya menahan peluncuran fitur baru dan memprioritaskan keandalan; error budget memberi bahasa netral untuk perdebatan “cepat atau stabil” yang selalu muncul di keseharian tim — termasuk setiap kali rilis baru lewat pipeline di Chapter Deployment Automation .
Health check memberi kita sinyal cepat saat layanan tumbang, dan log terpusat dari Chapter Log Aggregation menjelaskan alasannya. Bab berikutnya mengunci pintu yang selama ini kita biarkan terbuka: mengecilkan permukaan serangan server produksi lewat hardening.
Referensi lanjut: halaman manual curl
untuk opsi -w, --max-time, dan -s.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
cek-kesehatan.sh
Unduh berkas#!/usr/bin/env bash
# cek-kesehatan.sh — health check HTTP dengan timeout dan retry.
# Pemakaian: bash cek-kesehatan.sh <url> [jumlah-percobaan]
url="${1:-}"
maks="${2:-3}"
if [ -z "$url" ]; then
echo "pemakaian: bash cek-kesehatan.sh <url> [percobaan]" >&2
exit 0
fi
for i in $(seq 1 "$maks"); do
kode=$(curl -s -o /dev/null -w '%{http_code}' --max-time 2 "$url")
if [ "$kode" = "200" ]; then
echo "SEHAT (HTTP $kode)"
exit 0
fi
echo "percobaan $i/$maks gagal (HTTP $kode)"
[ "$i" -lt "$maks" ] && sleep 1
done
echo "TIDAK SEHAT ($maks/$maks gagal)"
exit 1