CAP Theorem
CAP Theorem: Konsistensi, Ketersediaan, dan Toleransi Partisi dalam Sistem Terdistribusi

Pendahuluan
CAP Theorem (dikenal juga sebagai Brewer’s Theorem) adalah prinsip fundamental dalam desain sistem terdistribusi yang menjelaskan trade-off antara tiga properti utama: Consistency (Konsistensi), Availability (Ketersediaan), dan Partition Tolerance (Toleransi Partisi). Teorema ini menjadi panduan kritis bagi pengembang untuk memilih prioritas sistem ketika menghadapi kegagalan jaringan.
Sejarah CAP Theorem
2000: Eric Brewer, ilmuwan komputer dari UC Berkeley, pertama kali memperkenalkan konsep CAP dalam konferensi ACM Symposium on Principles of Distributed Computing (PODC). Ia menyatakan bahwa sistem terdistribusi tidak dapat secara bersamaan menjamin ketiga properti tersebut.
2002: Nancy Lynch dan Seth Gilbert dari MIT membuktikan teorema ini secara formal dalam makalah berjudul “Brewer’s Conjecture and the Feasibility of Consistent, Available, Partition-Tolerant Web Services”, sehingga CAP Theorem menjadi landasan teoretis.
Tiga Komponen CAP
1. Consistency (Konsistensi)
Definisi: Setiap pembacaan data mengembalikan respons terbaru atau error. Semua node menampilkan data yang sama pada waktu yang sama. Pada sistem database terdistribusi biasanya kita akan melakukan replikasi dari database ke dalam beberapa node. Konsistensi dicapai apabila kita mendapatkan semua data sama pada setiap node pada waktu yang sama. Dengan kata lain, setelah kita melakukan berbagai operasi write ke database kita akan mendapatkan data yang sama ketika melakukan operasi read pada setiap node yang kita akses.
Apabila terjadi perbedaan data maka kita menyebutkan sebagai sistem yang tidak konsisten atau in consistency system.Perlu diperhatikan bahwa konsistensi pada teorema CAP berbeda pengertiannya dengan arti konsistensi pada sistem monolith atau pada konsep ACID database transaksional.
Contoh: Sistem perbankan memastikan saldo rekening konsisten di semua server.
2. Availability (Ketersediaan)
Definisi: Setiap permintaan ke sistem selalu mendapat respons (bukan error), meskipun beberapa node gagal merespons. Umumnya ketersediaan dari sistem diukur dengan up-time nya. Sistem yang memiliki up time 90 % akan memiliki availability yang lebih tinggi dari pada sistem yang memiliki uptime 80%. Akan tetapi, pengertian availability pada teorema CAP agak berbeda sedikit. Pada teorema CAP availability berarti sistem atau semua node akan senantiasa setiap waktu akan memberikan non error respon. Respon yang diberikan asal bukan lah error respon dan data tidak konsisten pun disebut memiliki tingkat availability yang tinggi. Serta perlu diperhatikan pula bukan hanya operasi read yang dijadikan patokan tetapi semu operasi baik read atau write.
Perlu diperhatikan juga bahwa availability terkait dengan respon time. Apabila respon time terlalu lama maka akan mengakibatkan client yang mengakses sistem kita akan mengalami pengalaman yang kurang baik. Dengan demikian, secara tidak langsung availability akan memiliki arti respon time yang tinggi atau cepat pula.
Sebuah contoh sistem dengan tingkat availability yang sangat tinggi adalah customer masih dapat melihat dan menambahkan item ke keranjang belanja mereka bahkan jika disk gagal, rute jaringan flapping, atau pusat data dihancurkan oleh tornado.
Contoh: Platform media sosial tetap dapat diakses meskipun sebagian server down.
3. Partition Tolerance (Toleransi Partisi)
Definisi: Sistem terus beroperasi meskipun terjadi network partition (gangguan komunikasi antarnode). Kita tidak dapat menghindari kenyataan bahwa jaringan itu akan mengalami kegagalan baik akibat dari permasalahan fisik ataupun logical. Kita akan mendapatkan kegagalan secara fisikal apabia terjadi pemasalahan pada jaringan kabel kita. Sedangkan kegagalan secara logical bisa diakibatkan oleh proses garbage collection yang berat terjadi.
Dengan demikian, sistem dengan partition tolerance yang tinggi adalah suatu sistem masih dapat bekerja walaupun komunikasi antar node terganggu. Masing-masing node mengetahui terjadi permasalah komunikasi misalkan antara node 1 dan node 2 dan ketika komunikasinya berjalan dengan baik kembali maka data dapat disiskronikasi ulang. Perlu diperhatikan bahwa yang dimaksud bukan node yang mati tetapi komunikasi antar node yang terganggu.
Contoh: Sistem cloud yang tetap berjalan saat kabel jaringan terputus.
Dengan melihat diagram CAP di atas apabila kita akan merancang sistem terdsitribusi atau secara lebih khusus microservice arsitektur maka pilihan yang terbaik adalah pada jenis database dengan konsep AP atau CP. Kalau tidak secara terpaksa maka kita semestinya menghindari database dengan kategori CA.
Pada jenis CA apabila ada request baik berupa write atau query dan koneksi antar node terganngu maka kita akan mendapatkan informasi system database bermasalah dan tidak berjalan dengan baik
Pada jenis AP apabila request write dan komunikasi antar node terganggu data akan tetap dituliskan ke database melalui salah satu node. Dengan demikian, ketika ada pencarian pada node yang lain mungkin saja data tidak ditemukan. Baru apabila komunikasi antar node sudah terjadi kembali kita akan mendapatkan data yang sama karena data sudah diupdate pada setiap nodenya.
Pada jenis CP apabila terjadi request write dan sedang terjadi permasalahan antar node, maka data tidak akan dituliskan ke database karena sistem ini memilih konsistensi data. Baru jika komunikasi antar semua node aman kita dapat menulis data kembali. Adapun unutk proses read sistem masih dapat memberikan data yang diminta walaupun komunikasi antar node lagi bermasalah.
CAP Theorem: Hanya Dua dari Tiga
CAP Theorem menyatakan bahwa dalam sistem terdistribusi, hanya dua dari tiga properti yang dapat dijamin secara bersamaan saat terjadi partisi jaringan:
CP (Consistency + Partition Tolerance): Prioritaskan konsistensi dan toleransi partisi. Sistem akan mengembalikan error atau menunda respons jika data tidak konsisten.
Contoh: Database seperti MongoDB (dengan konfigurasi kuat) dan Google Spanner.
AP (Availability + Partition Tolerance): Prioritaskan ketersediaan dan toleransi partisi. Sistem merespons dengan data yang mungkin tidak konsisten.
Contoh: Apache Cassandra dan Amazon DynamoDB.
CA (Consistency + Availability): Hanya mungkin dalam sistem non-terdistribusi atau tanpa partisi. Tidak praktis di dunia nyata karena partisi jaringan tak terhindarkan.
Implementasi Nyata CAP Theorem
1. Sistem CP (Consistency-Partition Tolerance)
Google Spanner: Database terdistribusi global yang menjamin konsistensi kuat menggunakan jam atomik (TrueTime API).
MongoDB: Dalam mode replikasi dengan write concern “majority”, MongoDB mengorbankan ketersediaan sementara untuk menjaga konsistensi.
2. Sistem AP (Availability-Partition Tolerance)
Apache Cassandra: Mengadopsi model tunable consistency. Saat partisi, Cassandra tetap merespons dengan data terbaru yang tersedia, lalu melakukan read repair untuk sinkronisasi.
Amazon DynamoDB: Menggunakan eventual consistency untuk ketersediaan tinggi, cocok untuk layanan seperti keranjang belanja di e-commerce.
3. Sistem CA (Praktis Tidak Ada)
Database Single-Node: Seperti MySQL atau PostgreSQL standalone (bukan cluster) hanya menjamin CA selama tidak ada partisi. Namun, ini bukan sistem terdistribusi sejati.
Use Case dalam Industri
1. Perbankan (CP)
Transaksi keuangan memerlukan konsistensi mutlak. Jika terjadi partisi, sistem mungkin menolak transaksi hingga jaringan pulih.
2. Media Sosial (AP)
Platform seperti Facebook atau Twitter mengutamakan ketersediaan. Postingan mungkin terlambat muncul di beberapa region, tetapi layanan tetap aktif.
3. E-commerce (AP)
Amazon menggunakan strategi AP untuk keranjang belanja: pelanggan tetap bisa menambah item meski terjadi partisi, dan data disinkronisasi nanti.
Mitos dan Kesalahpahaman
"CAP Berlaku untuk Setiap Operasi": CAP hanya berlaku saat terjadi partisi jaringan. Di kondisi normal, sistem mungkin menyediakan ketiganya.
"Pilihan Hanya CP atau AP": Beberapa sistem seperti Redis atau Kafka menggunakan konfigurasi hibrid, memungkinkan pengguna menyesuaikan trade-off.
Contoh Program
Berikut adalah Docker Compose untuk mensimulasikan Redis Cluster dan program Go untuk menguji konsistensi dalam skenario CP:
services:
redis-node-1:
image: redis:7.2-alpine
container_name: redis-node-1
command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
networks:
- redis-net
ports:
- 6379:6379
- 16379:16379 # Cluster bus port
redis-node-2:
image: redis:7.2-alpine
container_name: redis-node-2
command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
networks:
- redis-net
ports:
- 6380:6379
- 16380:16379
redis-node-3:
image: redis:7.2-alpine
container_name: redis-node-3
command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
networks:
- redis-net
ports:
- 6381:6379
- 16381:16379
# Replicas
redis-node-4:
image: redis:7.2-alpine
container_name: redis-node-4
command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
networks:
- redis-net
ports:
- 6382:6379
- 16382:16379
redis-node-5:
image: redis:7.2-alpine
container_name: redis-node-5
command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
networks:
- redis-net
ports:
- 6383:6379
- 16383:16379
redis-node-6:
image: redis:7.2-alpine
container_name: redis-node-6
command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
networks:
- redis-net
ports:
- 6384:6379
- 16384:16379
networks:
redis-net:
driver: bridge
services:
go-app:
build: .
container_name: go-app
command: go run main.go
networks:
- redis-net
networks:
redis-net:
driver: bridge
FROM golang:1.24-alpine
WORKDIR /app
COPY . .
RUN go mod tidy
CMD ["go", "run", "main.go"]
2. Skrip Inisialisasi Cluster (init-cluster.sh)
#!/bin/bash
# Inisialisasi Redis Cluster dengan 3 master dan 3 replica
docker exec -it redis-node-1 redis-cli --cluster create \
redis-node-1:6379 \
redis-node-2:6379 \
redis-node-3:6379 \
redis-node-4:6379 \
redis-node-5:6379 \
redis-node-6:6379 \
--cluster-replicas 1 \
--cluster-yes
Jalankan skrip setelah container berjalan:
chmod +x init-cluster.sh
./init-cluster.sh
3. Program Go untuk Simulasi CP (main.go)
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/redis/go-redis/v9"
)
func main() {
// Konfigurasi Redis Cluster
cluster := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{
"redis-node-1:6379",
"redis-node-2:6379",
"redis-node-3:6379",
"redis-node-4:6379",
"redis-node-5:6379",
"redis-node-6:6379",
},
})
ctx := context.Background()
// Test 1: Tulis data dengan WAIT untuk konsistensi
err := cluster.Set(ctx, "cp_test", "initial_value", 0).Err()
if err != nil {
log.Fatalf("Set error: %v", err)
}
// WAIT untuk memastikan replikasi ke 2 node (N/2+1 dari 3 master)
replicas, err := cluster.Wait(ctx, 2, 5*time.Second).Result()
if err != nil {
log.Fatalf("Wait error: %v", err)
}
fmt.Printf("Data direplikasi ke %d node\n", replicas)
// Test 2: Baca data dari semua node
for i := 6379; i <= 6384; i++ {
val, err := cluster.Get(ctx, "cp_test").Result()
if err != nil {
fmt.Printf("Error pada port %d: %v\n", i, err)
continue
}
fmt.Printf("Port %d: %s\n", i, val)
}
// Simulasi network partition (manual via Docker)
fmt.Println("\nSimulasikan network partition dengan:")
fmt.Println("docker network disconnect redis-cluster_redis-net redis-node-1")
// Test 3: Coba tulis selama partition
fmt.Println("\nMencoba menulis selama partition...")
err = cluster.Set(ctx, "cp_test", "new_value", 0).Err()
if err != nil {
fmt.Printf("Write error selama partition: %v\n", err)
}
// Cleanup
cluster.Del(ctx, "cp_test")
}
Cara Menjalankan
Mulai Cluster:
docker-compose up -d ./init-cluster.sh
Jalankan Program Go:
go mod init cp-test go get github.com/redis/go-redis/v9 go run main.go
Simulasi Network Partition:
docker network disconnect redis-cluster_redis-net redis-node-1
Hasil yang Diharapkan
Sebelum Partition:
Data konsisten di semua node
WAIT mengonfirmasi replikasi ke 2+ node
Selama Partition:
Operasi tulis gagal jika tidak mencapai quorum
Node yang terisolasi (redis-node-1) menolak permintaan
Kode ini mensimulasikan:
1. Setup Redis Cluster dengan 6 node (3 master + 3 replica)
2. Operasi tulis dengan jaminan konsistensi menggunakan `WAIT`
3. Pembacaan data dari semua node
4. Perilaku sistem selama network partition
Untuk skenario CP yang lebih kompleks, Anda bisa menambahkan:
- Simulasi failover otomatis
- Penggunaan Redlock untuk distributed locking
- Pemantauan cluster health menggunakan `CLUSTER NODES`
Penjelasan detail bagian yang mengatur 3 master dan 3 replica pada Docker Compose dan skrip inisialisasi Redis Cluster:
1. Docker Compose: Definisi 6 Node Redis
File docker-compose.yml
mendefinisikan 6 container Redis (redis-node-1 hingga redis-node-6).
services:
redis-node-1: # Master 1
redis-node-2: # Master 2
redis-node-3: # Master 3
redis-node-4: # Replica untuk Master 1
redis-node-5: # Replica untuk Master 2
redis-node-6: # Replica untuk Master 3
2. Skrip Inisialisasi Cluster: init-cluster.sh
init-cluster.sh
Bagian kritis ada pada perintah redis-cli --cluster create
dengan parameter --cluster-replicas 1
:
docker exec -it redis-node-1 redis-cli --cluster create \
redis-node-1:6379 \
redis-node-2:6379 \
redis-node-3:6379 \
redis-node-4:6379 \
redis-node-5:6379 \
redis-node-6:6379 \
--cluster-replicas 1
Penjelasan Parameter:
--cluster-replicas 1
: Setiap master akan memiliki 1 replica.Total 6 node = 3 master + (3 master × 1 replica) = 3 + 3 = 6 node.
Proses yang Terjadi:
Redis CLI akan otomatis memilih 3 node pertama sebagai master.
3 node sisanya akan dijadikan replica dan ditempatkan di belakang master:
redis-node-4 → replica dari redis-node-1 (master 1)
redis-node-5 → replica dari redis-node-2 (master 2)
redis-node-6 → replica dari redis-node-3 (master 3)
3. Verifikasi Roles Node
Setelah cluster berjalan, cek status node menggunakan perintah:
docker exec -it redis-node-1 redis-cli cluster nodes
Contoh Output:
e93f... redis-node-1:6379@16379 myself,master - 0 0 1 connected 0-5460
a1b2... redis-node-2:6379@16379 master - 0 0 2 connected 5461-10922
c3d4... redis-node-3:6379@16379 master - 0 0 3 connected 10923-16383
f5e6... redis-node-4:6379@16379 slave e93f... 0 0 4 connected # Replica dari node-1
g7h8... redis-node-5:6379@16379 slave a1b2... 0 0 5 connected # Replica dari node-2
i9j0... redis-node-6:6379@16379 slave c3d4... 0 0 6 connected # Replica dari node-3
master
: Node dengan peran master (penyimpan data utama).slave
: Node dengan peran replica (menyalin data dari master).
4. Arsitektur Cluster yang Terbentuk
+-----------------+
| Client |
+-----------------+
|
v
+----------------+----------------+----------------+
| Master 1 | Master 2 | Master 3 |
| (redis-node-1) | (redis-node-2) | (redis-node-3) |
+----------------+----------------+----------------+
| | |
v v v
+----------------+----------------+----------------+
| Replica 1 | Replica 2 | Replica 3 |
| (redis-node-4) | (redis-node-5) | (redis-node-6) |
+----------------+----------------+----------------+
5. Bagaimana Data Direplikasi?
Saat client menulis data ke master, data akan otomatis disinkronkan ke replica-nya.
Jika master down, salah satu replica bisa dipromosikan menjadi master baru (failover).
6. Testing Replikasi
Contoh skenario untuk memverifikasi replikasi:
Tulis data ke master (redis-node-1):
docker exec -it redis-node-1 redis-cli SET test_key "hello"
Baca data dari replica (redis-node-4):
docker exec -it redis-node-4 redis-cli GET test_key
Output harus:
"hello"
.
Dengan konfigurasi ini, Redis Cluster diatur untuk memiliki 3 master dan 3 replica, memenuhi kebutuhan sistem CP (Consistency & Partition Tolerance).
Troubleshooting Tambahan
Pastikan Port Terbuka:
lsof -i :6379-6384
Check Firewall:
sudo ufw allow 6379:6384/tcp
Log Redis:
docker logs redis-node-1
Referensi
Brewer, E. (2000). “Towards Robust Distributed Systems”. PODC.
Gilbert, S., & Lynch, N. (2002). “Brewer’s Conjecture and the Feasibility of Consistent, Available, Partition-Tolerant Web Services”. ACM SIGACT News.
Apache Cassandra Documentation. “Consistency Levels”.
MongoDB. “Write Concern”.
Last updated