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 checkContohYang dibuktikanYang tidak dibuktikan
ICMP pingping 192.0.2.20network stack hidupaplikasi ikut hidup
port TCPport 443 terbukaada proses yang mendengarkanrequest diproses berhasil
endpoint HTTPcurl 192.0.2.20/healthzaplikasi meresponsdependensinya (DB, cache) siap
deep check/healthz mengecek koneksi DBseluruh rantai siapbeban 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:

json
{"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:

bash
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:

text
{"status":"ok","db":"ok"}
HTTP 200
SEHAT (HTTP 200)
server latihan dimatikan

Bedah blok di atas:

  1. printf ... > webroot/healthz: isi endpoint — satu baris JSON, persis kontrak yang kita rancang di atas.
  2. python3 -m http.server ... &: server “aplikasi” berjalan di belakang, dengan stdout/stderr dibuang ke /dev/null agar output blok tetap bersih. Port 8642 dipilih sembarang agar tidak bertabrakan dengan layanan lain.
  3. 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.
  4. curl -s -w 'HTTP %{http_code}\n': -s sunyi, -w menambahkan status code — ini dia; 200 adalah satu-satunya jawaban sehat.
  5. bash cek-kesehatan.sh ... 2: skrip pemeriksa memanggil endpoint yang sama dengan maksimal 2 percobaan.
  6. kill, wait, lalu echo: mematikan server dan membesihkan proses latarnya. Baris echo terakhir bukan hiasan — wait mengembalikan 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 dengan exit 0 di 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:

  1. kode=$(curl -s -o /dev/null -w '%{http_code}' --max-time 2 "$url"): satu percobaan — -o /dev/null membuang body, -w '%{http_code}' mengambil status, --max-time menahan agar tidak menggantung selamanya.
  2. if [ "$kode" = "200" ]: satu-satunya jalan pulang yang sehat; exit 0 memberi tahu pemanggil bahwa layanan baik-baik saja.
  3. [ "$i" -lt "$maks" ] && sleep 1: jeda antar percobaan hanya bila masih ada percobaan berikutnya.
  4. exit 1 di 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
bash cek-kesehatan.sh 127.0.0.1:8643/healthz 3

Output yang Dihasilkan:

text
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:

SaluranSifatContoh kondisi
SMS / panggilan on-callmembangunkanservice down lebih dari 5 menit
chat tim (Slack dsb.)perlu perhatian cepattingkat error naik dua kali lipat
email ringkasan hariantidak mendesaktren 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:

bash
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
done

Output yang Dihasilkan:

text
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:

  1. 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.
  2. 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.
  3. [ "$gagal" -ge 3 ] && [ "$sudah_alert" -eq 0 ]: alert hanya menyala pada kegagalan ketiga, dan bendera sudah_alert menjaganya tetap satu — perhatikan putaran 4 tidak lagi mengirim SMS walau tetap gagal.
  4. sleep 1: interval antar pemeriksaan; di produksi nilainya dari interval di 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):

SLADowntime 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
bash
#!/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