UNDER PRESSURE

Level 1 · Menggandakan Mesin

Sesi 12: Stateless adalah Syarat: Mengapa Redis Bukan Sekadar Cache

Bayangkan jika kamu login di loket 1, lalu pindah ke loket 2 dan petugas loket 2 sama sekali tidak mengenalimu. Siapa yang salah — kamu, atau desain loketnya?

Sesi 12 / 343 menit baca

1. Masalah Utama: "Stateful" Menghancurkan Horizontal Scaling

Horizontal scaling mengasumsikan bahwa semua instance server identik dan bisa digantikan kapan saja.

Tetapi jika aplikasi menyimpan data status user (state) di memori lokal proses (RAM server itu sendiri): - User login di Server A ──► Session tersimpan di RAM Server A. - Request kedua diarahkan oleh Load Balancer ke Server B ──► Server B tidak punya session itu ──► User ditendang keluar (HTTP 401 Unauthorized).

                  ┌──────────────┐
                  │ Load Balancer│
                  └──────┬───────┘
          Request 1      │      Request 2
          (Login)        │      (Checkout)
               ┌─────────┴─────────┐
               ▼                   ▼
        ┌─────────────┐     ┌─────────────┐
        │  Server A   │     │  Server B   │
        │ [RAM: User1]│     │ [RAM: Kosong│
        │  LOGIN OK   │     │ 401 ERROR!  │
        └─────────────┘     └─────────────┘

Untuk mengatasi ini, arsitek pemula tergoda menggunakan Sticky Session (Sesi 10). Tapi seperti yang kita pelajari, sticky session menciptakan Single Point of Failure dan merusak autoscaling.


2. Definisi Arsitektur Stateless

Aplikasi disebut Stateless jika: 1. Tidak ada data transaksi atau user session yang disimpan di disk lokal atau RAM server aplikasi. 2. Setiap instance aplikasi bisa mati, restart, atau diganti detik ini juga tanpa ada satu pun user yang terputus atau kehilangan keranjang belanjanya. 3. Server aplikasi hanya bertindak sebagai alat pemroses logika (Compute Engine murni).

Data status disimpan di lapisan penyimpanan bersama terpusat: Shared State Layer (Redis).


3. Redis Muncul: Bukan Cuma "Cache", Tapi Shared State Store

Banyak orang mengira Redis hanya untuk "membuat query lambat jadi cepat" (caching). Peran sebenarnya dalam arsitektur terdistribusi jauh lebih fundamental: menjadi sumber kebenaran status sesi (Session Store) dan koordinasi lintas server.

              ┌──────────────┐
              │ Load Balancer│
              └──────┬───────┘
         ┌───────────┴───────────┐
         ▼                       ▼
  ┌─────────────┐         ┌─────────────┐
  │  Server A   │         │  Server B   │
  │ (Stateless) │         │ (Stateless) │
  └──────┬──────┘         └──────┬──────┘
         │                       │
         └───────────┬───────────┘
                     ▼
             ┌──────────────┐
             │ Redis Shared │
             │ Session Store│
             └──────────────┘

Karakteristik Session Store di Redis:

  1. In-Memory Speed: Latensi sub-milidetik (< 1 ms), tidak membebani database SQL.
  2. TTL Otomatis (Time-To-Live): Data sesi otomatis terhapus saat expired (EXPIRE session:123 3600) tanpa perlu cronjob pembersih manual.
  3. Data Structure Lengkap: String, Hash (untuk user attributes), Set (untuk active tokens).

4. Distributed Lock: Menghindari Double-Execution

Ketika ada 10 server aplikasi yang berjalan paralel, apa yang terjadi jika dua request dari user yang sama masuk di milidetik yang sama (misal user menekan tombol "Bayar Sekarang" dua kali)?

Jika tidak ada mekanisme kunci terdistribusi (Distributed Lock), kedua server akan sama-sama memotong saldo user!

Mekanisme Redis Lock (SETNX / Redlock):

# Server A mencoba mengambil lock
acquired = redis.set("lock:order:user_123", "server_a", nx=True, ex=10)

if acquired:
    try:
        # Proses pembayaran...
        potong_saldo()
        kirim_barang()
    finally:
        # Lepas lock
        redis.delete("lock:order:user_123")
else:
    # Server B ditolak karena lock sedang dipegang Server A
    return "Transaksi sedang diproses, mohon tunggu."
  • nx=True (Not Exists): Hanya berhasil jika kunci belum ada.
  • ex=10 (Expire 10s): Jika Server A mendadak mati (crash/OOM) saat memproses, kunci otomatis lepas setelah 10 detik agar tidak deadlock permanen.

5. Idempotency: Jaring Pengaman Terakhir

Bahkan dengan lock dan Redis, jaringan internet tidak pernah sempurna. Klien bisa saja mengirim ulang request yang sama karena timeout jaringan (retry).

Idempotency Key: - Klien menyertakan header unik untuk tiap aksi mutasi data: Idempotency-Key: uuid-v4-abc-123. - Server memeriksa di Redis: - Jika key sudah pernah selesai ──► kembalikan response lama dari Redis tanpa mengeksekusi ulang ke database. - Jika belum ──► simpan key di Redis dengan status PROCESSING, eksekusi, lalu simpan hasil.


6. Ringkasan Perbandingan

Dimensi Stateful App (Buruk untuk Skala) Stateless + Redis (Standar Cloud)
Lokasi Session RAM / Disk lokal server Redis Cluster Terpusat
Autoscaling Sangat sulit (harus sticky) Bebas tambah/kurang server kapan saja
Server Crash User di server itu logout Nol dampak ke user (transparan)
Deploy Baru Butuh drain panjang & resiko Rolling update instan
Concurrency Control Thread mutex lokal (hanya 1 mesin) Distributed Lock Redis (lintas cluster)

7. Istilah Kunci

  • Stateless: Desain aplikasi di mana server tidak menyimpan status user antar-request.
  • Shared State: Lapisan penyimpanan terpusat yang diakses bersama oleh semua node worker.
  • Redis: Data store in-memory berlatensi sangat rendah untuk session, cache, dan lock.
  • Distributed Lock: Mekanisme penguncian resource bersama lintas banyak server independen.
  • SETNX: Perintah Redis "Set if Not Exists" sebagai dasar mutex terdistribusi.
  • Idempotency: Sifat operasi yang memberikan hasil identik meskipun dieksekusi berkali-kali.