Belajar Ruby on Rails - Scaling & High Availability
Episode 24 of 27

Belajar Ruby on Rails - Scaling & High Availability

Membedah scaling Rails: aplikasi stateless, shared cache store, read replicas, worker terpisah, observability, serta praktik load test dan tuning menuju high availability

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 23 aplikasi kalian live di VPS, episode 24 membahas apa yang terjadi ketika trafik tumbuh: scaling. Satu server yang cukup untuk 100 user akan tercekik oleh 10 ribu. Pertanyaannya bukan apakah perlu scale, melainkan bagaimana melakukannya tanpa menulis ulang aplikasi.

Mengapa episode ini penting? Karena scaling Rails mengikuti pola yang sangat terprediksi — stateless app, shared cache, read replicas, worker terpisah, dan observability. Memahami pola ini sejak awal mencegah rewrite di tengah jalan dan membuat high availability (app tetap hidup saat satu komponen mati) menjadi desain, bukan keberuntungan.

Aplikasi Stateless: Fondasi Scaling Horizontal

Untuk menjalankan banyak instance app di belakang load balancer, aplikasi harus stateless — tidak menyimpan state di memori proses:

StateLokasi yang Benar
Session userCookie (default Rails) atau store shared
CacheRedis / Solid Cache (shared store)
File uploadVolume persisten / S3
Background jobsDatabase queue (Solid Queue)
RealtimeDatabase pub/sub (Solid Cable)

Jika app menyimpan data di memori proses (misal $global_state atau ActiveSupport::Cache::MemoryStore), instance yang berbeda melihat data berbeda — hasilnya inkonsisten. Rails 8 dengan Solid Stack sudah stateless-friendly secara default.

Shared Cache Store

Cache harus shared antar instance (dari episode 12 & 22):

Rubyconfig/environments/production.rb
config.cache_store = :solid_cache_store
# atau
config.cache_store = :redis_cache_store, { url: "redis://.../1" }

Konsekuensinya: fragment cache yang ditulis instance A bisa dibaca instance B. Cache in-memory per-instance akan menghasilkan hit rate rendah dan data stale.

Database: Read Replicas

Beban baca (SELECT) hampir selalu mendominasi. Read replicas memindahkan query baca ke replica database:

Rubyconfig/database.yml
production:
  primary:
    url: <%= ENV["DATABASE_URL"] %>
    pool: 10
  primary_replica:
    url: <%= ENV["REPLICA_DATABASE_URL"] %>
    pool: 10
    replica: true

Aktifkan per-request (atau per blok) agar Active Record mengarahkan baca ke replica:

RubyMengarahkan baca ke replica
ActiveRecord::Base.connected_to(role: :reading) do
  @posts = Post.published.limit(20)
end

Pola umum: sebagian besar request memakai replica untuk baca; transaksi tulis tetap di primary. Rails 8 juga punya automatic primary/replica routing berbasis per-thread jika diaktifkan.

Warning

Read replicas punya replication lag — data yang baru ditulis mungkin belum ada di replica beberapa milidetik. Untuk operasi read-after-write (misal redirect ke halaman yang baru dibuat), paksa baca ke primary atau gunakan routing transaksi. Jangan biarkan user melihat "404 setelah create".

Worker Terpisah

Background jobs jangan berbagi resource dengan web process. Di Kamal (episode 23), proses terpisah dideklarasikan:

config/deploy.yml
servers:
  web:
    - 203.0.113.10
    - 203.0.113.11
  workers:
    hosts:
      - 203.0.113.12
    cmd: bin/rails solid_queue:start

Web di mesin 10-11, worker di mesin 12 — pekerjaan berat tidak memperlambat response. Dengan systemd (non-Kamal), daftarkan worker sebagai unit service tersendiri dengan restart otomatis.

Observability: Melihat ke Dalam

Scaling butuh data. Observability = logs + metrics + traces:

PilarTool RailsFungsi
Logslograge (episode 17)Riwayat request terstruktur
Metricssolid_metrics / PrometheusRequest rate, error rate, latency
TracesOpenTelemetryAlur satu request lintas service

Solid Metrics (ekosistem Solid Stack) menyimpan metrik di database yang sama — satu dashboard tanpa infra tambahan. Metrik yang wajib dipantau:

  • Request rate & error rate — QPS dan % 5xx.
  • Latency p95/p99 — pengalaman pengguna terburuk.
  • Queue depth — jumlah job pending (episode 22).
  • DB connection pool usage — kehabisan koneksi = crash.
  • Cache hit ratio — cache yang tidak efektif = beban DB naik.

Praktik Load Test & Tuning

Jangan menebak kapasitas — ukur. Alur yang benar:

Load test dengan k6/vegeta
k6 run load-test.js
# atau
vegeta attack -targets=targets.txt -rate=100 -duration=30s | vegeta report

Alur pengukuran yang disarankan:

  1. Baseline — ukur satu instance tanpa beban (latency & p95).
  2. Load test bertahap — naikkan rate sampai error/5xx muncul; catat titik jenuh.
  3. Identifikasi bottleneck — dari metrik: DB? queue? CPU? cache miss?
  4. Tune — naikkan pool, tambah index (episode 21), perbaiki N+1, tambah cache.
  5. Ulang — pastikan titik jenuh naik.

Contoh tuning yang umum: pool: 25 pada database config, timeout yang masuk akal, dan config.hosts yang tepat.

High Availability

HA berarti app tetap melayani saat satu komponen mati. Pola yang menciptakannya:

  • Multi-instance app di belakang load balancer — satu instance mati, lainnya mengambil alih.
  • Database primary + replica — failover ke replica saat primary down.
  • Worker multi-process — job tetap diproses saat satu worker mati.
  • Healthcheck (/up) — load balancer mengeluarkan instance yang sakit.
  • Zero-downtime deploy — Kamal rolling deploy (episode 23) tanpa jeda layanan.
100%

Ketika satu instance mati, user tidak menyadarinya — instance lain masih melayani dari cache shared dan database yang sama.

Common Pitfalls

  • State di memori proses — session/global di MemoryStore membuat instance tidak konsisten.
  • Read replica dipakai untuk read-after-write — user melihat data hilang; routing ke primary untuk transaksi.
  • Worker berbagi resource web — response melambat; pisahkan process.
  • Tanpa observability saat scaling — tidak tahu titik jenuh; pasang metrik sebelum trafik naik.
  • Load test pada environment development — hasil tak mewakili production; test di staging yang mirip produksi.
  • Scaling app tapi tidak database — bottleneck pindah; scale DB (replica, index, pool) bersamaan.

Penutup

Episode 24 membekali kalian scaling Rails: aplikasi stateless sebagai fondasi horizontal scaling, shared cache store, read replicas untuk beban baca, worker terpisah untuk beban async, observability dengan logs/metrics/traces (Solid Metrics), dan load test untuk tuning berbasis data menuju high availability.

Inti yang harus dibawa pulang:

  • Stateless: session/cache/storage/jobs harus shared, bukan di memori proses.
  • Read replicas: baca ke replica, tulis ke primary; waspadai lag.
  • Worker terpisah dari web process; queue depth dipantau.
  • Observability: request rate, error rate, latency, queue, pool, cache hit.
  • Load test bertahap → temukan bottleneck → tune → ukur ulang.

Di episode 25 selanjutnya kita akan membedah ekosistem & tren modern 2026 — Rails 8.1.3.1, Ruby 4.0 ZJIT, Hotwire, Solid Stack, Kamal, dan perbandingan dengan Laravel/Django/Node. Sampai jumpa di episode 25!