Anti-Pattern Database: Read Replica Menganggur dan Salah Kaprah Penggunaannya
Keberadaan read replica sering dianggap tanda sistem yang sudah scalable dan mature. Infrastruktur sudah disiapkan, biaya sudah dibayar, dan tim engineering merasa arsitekturnya sudah benar. Tapi ada anti-pattern yang lebih berbahaya justru karena tidak terlihat jelas: read replica tersedia, berjalan, dibayar setiap bulan — namun hampir tidak mendapatkan traffic dari aplikasi. Atau lebih buruk lagi, satu-satunya yang menggunakannya adalah tim data untuk query analitik, sementara aplikasi tetap sepenuhnya membaca dari master. Kondisi ini bukan sekadar suboptimal. Ini adalah pemborosan biaya sekaligus indikasi desain yang tidak tuntas — dan artikel ini membahas mengapa itu terjadi, apa konsekuensinya, dan bagaimana seharusnya read replica ditempatkan dalam arsitektur yang benar.
Cara Kerja Read Replica dan Replication Lag
Sebelum membahas anti-pattern, penting untuk memahami mekanisme dasar replikasi. Sebagian besar managed database — MySQL, PostgreSQL, Amazon RDS, Aurora — menggunakan asynchronous replication sebagai default untuk read replica.
sequenceDiagram
participant App as Aplikasi
participant Master as Master DB
participant Replica as Read Replica
App->>Master: WRITE (INSERT/UPDATE/DELETE)
Master-->>App: Commit berhasil
Master--)Replica: Kirim binary log (async)
Note over Master,Replica: Replication lag: 10ms–beberapa detik
Replica--)Replica: Apply log
App->>Replica: READ (SELECT)
Note over Replica: Data mungkin belum ter-updateKonsekuensi dari model ini:
- Semua write selalu masuk ke master
- Replica menerima perubahan dengan delay — disebut replication lag
- Lag ini bisa berkisar dari puluhan milidetik hingga beberapa detik tergantung beban write dan jarak network
Replication lag adalah karakteristik sistem terdistribusi, bukan bug. Ia tidak bisa dihilangkan sepenuhnya — hanya bisa dihadapi secara arsitektural. Read replica bukan salinan real-time; ia adalah eventually consistent copy dari master.
Replication lag bisa meningkat drastis saat master mengalami write spike — misalnya batch insert besar, migrasi data, atau traffic lonjakan. Sistem yang tidak pernah mengukur lag replication di production sering terkejut saat menemukan lag mencapai menit, bukan milidetik, saat beban tinggi.
Read Replica Idle — Anti-Pattern yang Tidak Terlihat
Anti-pattern ini mudah lolos dari perhatian karena sistem tetap berjalan normal. Tidak ada error, tidak ada alert, tidak ada keluhan dari user. Yang ada hanya tagihan cloud yang terus berjalan untuk resource yang tidak memberikan nilai.
Tanda-tanda read replica idle:
✗ CPU replica konsisten single-digit (< 5%) sementara master di atas 50%
✗ Connections ke replica hampir nol sepanjang hari
✗ Query per second di replica jauh lebih rendah dari master
✗ Satu-satunya traffic ke replica adalah dari cron job atau tim data
✗ Engineer tidak tahu endpoint mana yang membaca dari replica
Mengapa Ini Terjadi
Penyebab paling umum bukan ketidaktahuan tentang replica — tim biasanya tahu ada replica. Penyebabnya adalah kekhawatiran terhadap replication lag yang kemudian dijadikan alasan untuk tidak menggunakan replica sama sekali:
"Kalau kita baca dari replica, datanya bisa stale."
"Lebih aman baca dari master saja biar konsisten."
"Nanti user komplain lihat data yang beda."
Argumen-argumen ini tidak salah secara teknis, tapi salah secara arsitektur. Mereka menyamakan semua read operation dengan critical read operation — padahal keduanya sangat berbeda.
Biaya Nyata dari Anti-Pattern Ini
Contoh estimasi biaya (AWS RDS, db.r6g.xlarge, us-east-1):
Master: ~$300/bulan
Replica: ~$300/bulan (identik)
Jika replica hanya dipakai 5% kapasitas:
→ $285/bulan dibuang sia-sia
→ $3.420/tahun untuk infrastruktur yang tidak memberikan value
Jika ada 2 replica idle:
→ $6.840/tahun pemborosan langsung
Ironisnya, biaya replica ini sering tidak dipertanyakan karena dianggap sebagai “biaya HA (high availability)”. Padahal replica untuk HA dan replica untuk read offload adalah dua kebutuhan berbeda dengan desain berbeda.
Konsistensi Adalah Masalah Use Case, Bukan Alasan Menolak Replica
Pertanyaan yang tepat bukan “Bagaimana menghilangkan replication lag?” melainkan “Read mana yang benar-benar membutuhkan strong consistency?”
Jawabannya: jauh lebih sedikit dari yang diasumsikan kebanyakan tim.
| Use Case | Butuh Strong Consistency? | Aman ke Replica? | Alasan |
|---|---|---|---|
| User profile tepat setelah update | ✓ Ya | ✗ Tidak | User harus melihat perubahan yang baru disimpan |
| Form submit + halaman konfirmasi | ✓ Ya | ✗ Tidak | Data harus mencerminkan write yang baru terjadi |
| Transaksi finansial | ✓ Ya | ✗ Tidak | Konsistensi adalah keharusan bisnis |
| Dashboard statistik | ✗ Tidak | ✓ Ya | Selisih beberapa detik tidak material |
| List produk / katalog | ✗ Tidak | ✓ Ya | Data jarang berubah dalam hitungan detik |
| Feed / timeline | ✗ Tidak | ✓ Ya | Eventual consistency adalah norm di feed |
| Hasil pencarian | ✗ Tidak | ✓ Ya | Sedikit stale masih acceptable |
| Laporan dan reporting | ✗ Tidak | ✓ Ya | Laporan biasanya sudah agregasi data historis |
| Halaman detail produk | ✗ Tidak | ✓ Ya | Data produk jarang berubah real-time |
Pada sistem e-commerce atau aplikasi SaaS yang umum, lebih dari 70% read operation tidak membutuhkan strong consistency dan aman diarahkan ke replica.
flowchart TD
A[Incoming READ Request] --> B{Apakah read ini terjadi\nlangsung setelah WRITE\noleh user yang sama?}
B -- Ya --> C{Apakah ketidakcocokan\ndata akan terlihat\njelas oleh user?}
C -- Ya --> D[→ Baca dari MASTER]
C -- Tidak --> E[→ Baca dari REPLICA]
B -- Tidak --> F{Apakah data yang\nsedikit stale bisa\nditerima secara bisnis?}
F -- Ya --> E
F -- Tidak --> DStrategi Menghadapi Replication Lag
Setelah memutuskan bahwa replica harus digunakan, langkah berikutnya adalah menangani kasus di mana consistency memang dibutuhkan — tanpa harus mengirim semua traffic ke master.
Read Your Own Write (RYOW)
RYOW adalah strategi paling umum untuk menangani ketidaksinkronan setelah write. Intinya sederhana: setelah user melakukan write, arahkan read berikutnya ke master untuk sementara waktu.
-- ANTI-PATTERN: baca dari replica langsung setelah write
BEGIN TRANSACTION;
UPDATE users SET display_name = 'Budi Santoso' WHERE id = 123;
COMMIT;
-- Lalu langsung:
SELECT * FROM users WHERE id = 123; -- ke replica, bisa dapat data lama!
-- BENAR: RYOW — baca dari master dalam window setelah write
BEGIN TRANSACTION;
UPDATE users SET display_name = 'Budi Santoso' WHERE id = 123;
COMMIT;
-- Tandai sesi: "user ini baru saja melakukan write"
-- Read pertama ke master, read berikutnya (setelah window) boleh ke replica
SELECT * FROM users WHERE id = 123; -- ke master, pasti fresh
Implementasi RYOW di application layer bisa sesederhana menyimpan flag di session atau cache:
Session flag: user_just_wrote = true (TTL: 2 detik)
Read routing logic:
IF session.user_just_wrote = true
→ baca dari MASTER
ELSE
→ baca dari REPLICA
Read Routing Berdasarkan Use Case
Pendekatan yang lebih eksplisit adalah mendefinisikan routing langsung di repository atau service layer:
-- Contoh routing eksplisit di query layer
-- Query untuk dashboard (eventual consistency OK)
-- Gunakan read replica connection
SELECT
COUNT(*) AS total_orders,
SUM(amount) AS total_revenue,
DATE(created_at) AS order_date
FROM orders
WHERE created_at >= NOW() - INTERVAL 30 DAY
GROUP BY DATE(created_at);
-- → Directed to: REPLICA
-- Query setelah user update profile (strong consistency required)
-- Gunakan master connection
SELECT id, email, display_name, avatar_url
FROM users
WHERE id = :userId;
-- → Directed to: MASTER
Time-Based Routing
Untuk sistem yang tidak bisa melacak state per-user dengan mudah, time-based routing memberikan jaminan sederhana:
Aturan routing:
- Read dalam 2 detik pertama setelah write oleh session yang sama → MASTER
- Read setelah 2 detik → REPLICA
Implementasi:
- Simpan timestamp write terakhir per session
- Saat ada read request, cek selisih waktu
- Jika < threshold → master, jika >= threshold → replica
Adaptive Routing Berdasarkan Lag Monitoring
Strategi paling tangguh adalah membuat routing bersifat adaptif berdasarkan kondisi replikasi aktual:
flowchart LR
A[Read Request] --> B{Cek replication\nlag saat ini}
B -- "Lag < 500ms\n(acceptable)" --> C[→ REPLICA]
B -- "Lag ≥ 500ms\n(too high)" --> D[→ MASTER fallback]
C --> E[Response]
D --> E-- Query untuk memonitor replication lag (PostgreSQL)
SELECT
client_addr AS replica_host,
state,
EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))
AS lag_seconds,
sent_lsn,
replay_lsn
FROM pg_stat_replication;
-- Jika lag_seconds > threshold, fallback ke master untuk sementara
Tentukan threshold lag yang relevan untuk aplikasi kamu berdasarkan SLA bisnis, bukan asumsi. Aplikasi finansial mungkin hanya toleran terhadap lag < 100ms, sementara platform konten bisa toleran sampai beberapa detik. Ukur dulu, baru tentukan threshold.
Kesalahan Desain: Tim Data Membaca dari Read Replica
Ini adalah anti-pattern kedua yang sering terjadi bersamaan dengan replica idle — dan ironisnya, keduanya saling memperburuk.
OLTP dan OLAP Adalah Dua Dunia Berbeda
| Karakteristik | OLTP (RDS/Aurora) | OLAP (Redshift/BigQuery) |
|---|---|---|
| Tujuan utama | Melayani transaksi aplikasi | Analitik dan reporting |
| Pola query | Point read, small result set | Full scan, heavy aggregation |
| Latency | Harus rendah (< 100ms) | Bisa lebih tinggi (detik–menit) |
| Optimasi storage | Row-oriented | Column-oriented |
| Concurrency | Ribuan transaksi kecil | Sedikit query besar |
| Beban tipikal | Write-heavy | Read-heavy analitik |
Query analitik yang dijalankan tim data memiliki karakteristik yang bertolak belakang dengan query aplikasi — full table scan, join besar, agregasi jutaan baris, dan runtime yang bisa mencapai menit. Ketika ini dijalankan di read replica:
flowchart TD
subgraph "Kondisi Salah"
A1[Tim Data] -- "Query analitik\nberat" --> R1[Read Replica]
APP1[Aplikasi] -- "Query aplikasi\nnormal" --> R1
R1 -- "CPU spike,\nlatency naik" --> R1
R1 -- "Replica lag\nmeningkat" --> R1
end
subgraph "Kondisi Benar"
A2[Tim Data] -- "Query analitik" --> DW[Data Warehouse\nRedshift / BigQuery]
APP2[Aplikasi] -- "Read non-kritis" --> R2[Read Replica]
APP3[Aplikasi] -- "Write / Critical read" --> M2[Master DB]
M2 -- "CDC / ETL pipeline" --> DW
endDampak Query Analitik di Read Replica
Skenario nyata yang sering terjadi:
1. Tim data menjalankan query "ringan" di replica:
SELECT * FROM orders
JOIN order_items ON orders.id = order_items.order_id
JOIN products ON order_items.product_id = products.id
WHERE orders.created_at >= '2024-01-01'
ORDER BY orders.created_at DESC;
-- Ini full scan orders + join, bisa jutaan baris
2. CPU replica naik ke 80-90%
3. Replication lag mulai meningkat — replica tidak bisa apply
log dari master secepat biasanya karena sibuk melayani query berat
4. Aplikasi yang seharusnya membaca dari replica kini mendapat
data yang semakin stale
5. Jika lag melewati threshold, semua traffic fallback ke master
6. Master yang seharusnya hanya melayani write kini mendapat
seluruh read traffic — persis kondisi sebelum ada replica
Satu query analitik bisa menghapus semua manfaat dari keberadaan replica.
Data Warehouse adalah Tempat yang Tepat
Data warehouse dirancang spesifik untuk pola kerja tim data:
Keunggulan columnar storage untuk analitik:
Query: SELECT SUM(amount), AVG(amount), COUNT(*)
FROM orders WHERE status = 'completed'
Row-oriented (OLTP):
→ Baca seluruh row termasuk kolom yang tidak diperlukan
→ Inefficient untuk agregasi kolom tunggal
Columnar (OLAP):
→ Hanya baca kolom 'amount' dan 'status'
→ 5-10x lebih cepat untuk query agregasi
→ Kompresi lebih baik (data sejenis disimpan berdekatan)
Selain performa, pemisahan ini memberikan separation of concern yang jelas: OLTP melayani aplikasi, OLAP melayani analitik. Gangguan di satu sisi tidak merembet ke sisi lain.
Arsitektur yang Sehat
Arsitektur database yang mature memisahkan traffic berdasarkan sifat dan kebutuhan tiap jenis operasi:
flowchart TD
subgraph "Application Layer"
WEB[Web / API Server]
end
subgraph "Database Layer"
MASTER[Master DB\nWrite + Critical Read]
REPLICA1[Read Replica 1\nApp Read Offload]
REPLICA2[Read Replica 2\nApp Read Offload]
end
subgraph "Analytics Layer"
ETL[CDC / ETL Pipeline\nDebezium / Fivetran]
DW[Data Warehouse\nRedshift / BigQuery / Snowflake]
end
subgraph "Consumers"
ANALYST[Tim Data / BI Tools]
end
WEB -- "Write & Critical Read" --> MASTER
WEB -- "Non-critical Read" --> REPLICA1
WEB -- "Non-critical Read" --> REPLICA2
MASTER -- "Binary log stream" --> ETL
ETL --> DW
ANALYST --> DWSetiap komponen melayani peran yang jelas:
MASTER → satu-satunya target write; critical read setelah write
READ REPLICA → offload non-critical read dari aplikasi; tidak untuk analitik
DATA WAREHOUSE → satu-satunya target query analitik tim data
Query langsung dari tim data ke OLTP hanya boleh untuk:
✓ Debugging ad-hoc yang tidak bisa dilakukan di warehouse
✓ Verifikasi data real-time yang sangat mendesak
✗ Bukan untuk query reguler atau laporan rutin
Dampak terhadap Cost dan Reliability
Desain yang benar memberikan dampak langsung pada dua hal yang paling diperhatikan: biaya dan ketersediaan sistem.
Dengan arsitektur yang tepat:
BEFORE:
- Master: CPU 70%, under pressure dari read + write
- Replica: CPU 5%, hampir idle (biaya terbuang)
- Tim data: query ke replica, sesekali spike
AFTER:
- Master: CPU 40%, hanya melayani write + critical read
- Replica: CPU 40–60%, aktif melayani read aplikasi
- Data warehouse: melayani semua analitik tim data
Hasil:
✓ Master lebih stabil → write latency lebih rendah
✓ Replica punya utilisasi nyata → ROI terbayar
✓ Query analitik tidak mengganggu operasional aplikasi
✓ Replication lag lebih stabil karena replica tidak dibebani query berat
Cost reduction datang sebagai efek samping dari desain yang benar — bukan dari pemotongan paksa.
Checklist Audit Read Replica
UTILISASI:
□ Cek QPS (query per second) replica vs master — rasio target minimal 40:60
□ Cek CPU utilization replica — jika konsisten < 10%, traffic tidak terdistribusi
□ Cek active connections ke replica dari application servers
□ Identifikasi semua endpoint/query yang masih baca dari master tanpa alasan
KONSISTENSI:
□ Petakan semua read operation per endpoint: mana yang butuh strong consistency?
□ Implementasikan RYOW untuk semua operation write-then-read dalam session yang sama
□ Set replication lag monitoring dengan alert jika melewati threshold bisnis
□ Tentukan fallback behavior saat lag tinggi: otomatis ke master atau error?
PEMISAHAN OLTP/OLAP:
□ Audit apakah ada query analitik reguler yang berjalan di replica
□ Pastikan tim data memiliki akses ke data warehouse, bukan ke OLTP
□ Set up CDC atau ETL pipeline dari master ke data warehouse
□ Dokumentasikan kebijakan: kapan boleh query langsung ke OLTP?
ARSITEKTUR:
□ Konfigurasi connection pool terpisah untuk master dan replica
□ Read routing logic terdokumentasi dan di-enforce di repository layer
□ Tidak ada hardcoded master connection string di query yang seharusnya ke replica
Ringkasan
- Read replica idle adalah pemborosan nyata — resource dibayar penuh tapi tidak memberikan value; CPU single-digit di replica adalah tanda arsitektur yang tidak tuntas.
- Replication lag adalah karakteristik, bukan bug — pertanyaan yang tepat bukan bagaimana menghilangkannya, tapi read mana yang benar-benar butuh strong consistency.
- Mayoritas read tidak butuh strong consistency — dashboard, list data, feed, search, dan reporting semua aman diarahkan ke replica; hanya read tepat setelah write yang butuh master.
- Read Your Own Write (RYOW) adalah strategi paling praktis untuk menangani kasus write-then-read: arahkan ke master sementara dalam window waktu tertentu setelah write.
- Adaptive routing berbasis lag monitoring membuat sistem tangguh — jika replication lag melewati threshold, fallback otomatis ke master.
- Tim data membaca dari read replica adalah kesalahan desain — query analitik bersifat full scan dan bisa menyebabkan CPU spike yang meningkatkan replication lag dan mengganggu seluruh aplikasi.
- Data warehouse adalah tempat yang tepat untuk analitik — columnar storage, parallel execution, dan isolasi dari traffic aplikasi menjadikannya jauh lebih efisien untuk query tim data.
- Arsitektur sehat = pemisahan jelas: master untuk write dan critical read, replica untuk non-critical read aplikasi, data warehouse untuk semua analitik.