Membangun Kluster High Availability MySQL & Redis di Balik Nginx Load Balancer
1. Konteks Industri & Analisis Akar Masalah
Dalam lanskap arsitektur sistem modern, skalabilitas horizontal pada lapisan aplikasi (application layer) sering kali dipuja sebagai solusi utama untuk mengatasi lonjakan trafik. Kita dengan mudah dapat melakukan autoscaling pada kontainer Docker di Kubernetes atau menambah instans Node.js, Go, dan PHP-FPM di belakang reverse proxy. Namun, hukum Amdahl tetap berlaku: performa keseluruhan sistem sangat dibatasi oleh komponen paling lambat, yang dalam 90% kasus adalah lapisan persistensi data (database relasional) dan caching layer.
Secara historis, kegagalan infrastruktur sering kali bermula dari pendekatan Single Point of Failure (SPOF) pada database MySQL dan Redis. Ketika aplikasi mengalami lonjakan read/write requests, beban CPU dan I/O pada server database tunggal akan melonjak drastis. Koneksi TCP akan menumpuk (connection pool exhaustion), antrean kueri melambat, dan pada akhirnya seluruh layanan web mengalami downtime. Masalah ini diperparah oleh absennya mekanisme automatic failover yang handal untuk Redis (yang sering digunakan sebagai session store, rate limiter, atau full-page cache) dan MySQL (sebagai sumber kebenaran utama/single source of truth).
Sebelum penerapan arsitektur High Availability (HA) berbasis Nginx Stream Module, MySQL Master-Slave Replication, dan Redis Sentinel, infrastruktur umumnya rentan terhadap:
- Downtime total saat server database utama mengalami gangguan hardware atau kernel panic.
- Bottleneck jaringan karena aplikasi langsung menghujam satu IP database tanpa load balancing.
- Data inconsistency akibat tidak adanya replikasi asinkron/semi-sinkron yang terkonfigurasi dengan baik.
Sesudah penerapan arsitektur HA komprehensif ini, sistem mampu mendistribusikan beban baca (read operations) ke beberapa slave MySQL, mengarahkan lalu lintas TCP secara efisien melalui Nginx, dan menjamin pemulihan otomatis (automatic failover) dalam hitungan detik ketika node master mengalami kegagalan tanpa intervensi manual dari sysadmin.
2. Konsep Inti & Deep Dive Arsitektur
Arsitektur High Availability yang akan kita bedah melibatkan tiga pilar utama yang saling terintegrasi erat:
- Nginx Stream Module (Layer 4 Load Balancing): Bertindak sebagai pintu gerbang TCP transparan. Nginx tidak memproses protokol HTTP/HTTPS di sini, melainkan meneruskan paket TCP mentah dari aplikasi backend ke kluster database MySQL dan Redis dengan algoritma least_conn atau round-robin.
- MySQL Master-Slave Replication with GTID (Global Transaction Identifiers): Memastikan setiap transaksi yang dieksekusi pada Master dicatat dalam binary log (binlog) dan direplikasi ke satu atau lebih Slave secara akurat, meminimalkan risiko split-brain.
- Redis Sentinel: Sistem pemantauan terdistribusi dan manajemen failover otomatis. Sentinel memantau kesehatan Redis Master dan Slave, serta secara otomatis mempromosikan Slave terbaik menjadi Master baru jika Master utama tidak merespons (quorum-based decision).
+-------------------------------------------------------------------------+
| Application Servers |
| (PHP-FPM, Node.js, Go Backend Services) |
+-------------------------------------------------------------------------+
| |
| TCP Port 3306 (MySQL) | TCP Port 6379 (Redis)
v v
+-----------------------------------+ +---------------------------------+
| Nginx Load Balancer | | Nginx Load Balancer |
| (Stream Module - Read) | | (Stream Module - Redis) |
+-----------------------------------+ +---------------------------------+
| |
+-------------------+ +---------+
| |
v v
+-------------------------------------------+ +-----------------------------+
| MySQL Cluster | | Redis Sentinel |
| +-------------------+ +---------------+ | | +---------+ +---------+ |
| | MySQL Master |->| MySQL Slave 1 | | | |Master 63|->|Slave 64 | |
| | (Read/Write) | | (Read Only) | | | +---------+ +---------+ |
| +-------------------+ +---------------+ | | ^ ^ |
+-------------------------------------------+ +-----+------------+--------+
| |
+-----+------------+--------+
| Redis Sentinels |
| (Quorum: 2 / Ports 26379) |
+---------------------------+
3. Perbandingan Komparatif / Analisis Pendekatan
Untuk memahami mengapa desain ini dipilih, mari kita lakukan analisis komparatif terhadap pendekatan alternatif yang sering dijumpai di industri.
| Parameter Perbandingan | Nginx Stream + MySQL Master-Slave + Redis Sentinel | HAProxy + MySQL Group Replication (MGR) + Redis Cluster | Direct Connection (Tanpa Load Balancer) |
|---|---|---|---|
| Kompleksitas Setup | Sedang (Standar Industri, Dokumentasi Luas) | Tinggi (Butuh pemahaman mendalam konsensus Paxos/MGR) | Rendah di awal, Sangat Tinggi saat Skala Membesar |
| Penggunaan Sumber Daya (CPU/RAM) | Sangat Efisien (Nginx ringan, overhead rendah) | Tinggi (MGR butuh overhead komunikasi grup yang besar) | Minimal untuk server tunggal, tidak efisien untuk banyak app node |
| Latency Jaringan | Sangat Rendah (< 1ms tambahan di Nginx) | Rendah hingga Sedang (tergantung overhead konsensus) | Paling Rendah (tanpa proxy), namun rentan bottleneck |
| Automatic Failover | Ya (Redis Sentinel otomatis, MySQL manual/orchestrator) | Ya (Built-in MGR consensus) | Tidak Ada (Manual intervention required) |
| Cocok Untuk Beban Kerja | Web App standar hingga High Concurrency (>50k req/s) | Enterprise skala masif dengan multi-master write requirement | Aplikasi skala kecil/MVP (Minimum Viable Product) |
[!WARNING] Jangan pernah menggunakan MySQL Master-Master (Active-Active) untuk beban tulis yang tinggi tanpa pengelolaan konflik yang matang, karena isu deadlock dan inkonsistensi data auto-increment ID akan menghancurkan integritas basis data Anda.
4. Prasyarat Sistem & Persiapan Lingkungan
Sebelum menuliskan satu baris konfigurasi pun, pastikan infrastruktur dasar telah disiapkan dengan spesifikasi minimal berikut:
- OS: Ubuntu 22.04 LTS (Jammy Jellyfish) atau Debian 12 Bookworm pada seluruh node.
- Topologi Minimal:
- 1 Node Nginx Load Balancer (IP:
192.168.1.10) - 2 Node MySQL (Master:
192.168.1.20, Slave:192.168.1.21) - 3 Node Redis & Sentinel (
192.168.1.30,192.168.1.31,192.168.1.32)
- 1 Node Nginx Load Balancer (IP:
- Hak Akses: Akses
rootatausudopada seluruh server. - Pengaturan Firewall (UFW/Firewalld):
- Buka port 3306 untuk MySQL.
- Buka port 6379 untuk Redis.
- Buka port 26379 untuk Redis Sentinel.
- Buka port TCP yang dibutuhkan pada Nginx.
Verifikasi konektivitas jaringan antar server menggunakan utilitas ping dan nc (netcat):
nc -zv 192.168.1.20 3306
5. Panduan Implementasi Langkah demi Langkah
Langkah 5.1: Konfigurasi Replikasi Master-Slave MySQL
Masuk ke server MySQL Master (192.168.1.20) dan sunting file /etc/mysql/mysql.conf.d/mysqld.cnf:
[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
gtid_mode = ON
enforce-gtid-consistency = ON
relay-log = /var/log/mysql/mysql-relay-bin.log
log_slave_updates = ON
read_only = OFF
bind-address = 0.0.0.0
Restart layanan MySQL pada Master:
sudo systemctl restart mysql
Buat akun replikasi di MySQL Master melalui shell database:
CREATE USER 'replicator'@'%' IDENTIFIED WITH mysql_native_password BY 'StrongPasswordReplication123!';
GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%';
FLUSH PRIVILEGES;
SHOW MASTER STATUS;
Catat nilai File dan Position (atau pastikan GTID aktif). Sekarang, pada server MySQL Slave (192.168.1.21), sesuaikan /etc/mysql/mysql.conf.d/mysqld.cnf:
[mysqld]
server-id = 2
relay-log = /var/log/mysql/mysql-relay-bin.log
gtid_mode = ON
enforce-gtid-consistency = ON
read_only = ON
bind-address = 0.0.0.0
Restart dan konfigurasikan slave:
sudo systemctl restart mysql
Masuk ke shell MySQL Slave dan jalankan:
CHANGE MASTER TO
MASTER_HOST='192.168.1.20',
MASTER_USER='replicator',
MASTER_PASSWORD='StrongPasswordReplication123!',
MASTER_AUTO_POSITION=1;
START SLAVE;
SHOW SLAVE STATUSG
Pastikan Slave_IO_Running: Yes dan Slave_SQL_Running: Yes.
Langkah 5.2: Setup Redis Sentinel untuk Automatic Failover
Lakukan instalasi Redis pada ketiga node Redis (192.168.1.30, 192.168.1.31, 192.168.1.32). Sunting /etc/redis/redis.conf:
bind 0.0.0.0
protected-mode no
port 6379
daemonize yes
pidfile /var/run/redis/redis-server.pid
loglevel notice
logfile /var/log/redis/redis-server.log
dbfilename dump.rdb
dir /var/lib/redis
requirepass "StrongRedisAuthPass456!"
masterauth "StrongRedisAuthPass456!"
Pada node slave (misal .31 dan .32), tambahkan baris replikasi:
replicaof 192.168.1.30 6379
Selanjutnya, konfigurasikan Redis Sentinel pada file /etc/redis/sentinel.conf di ketiga node tersebut:
port 26379
daemonize yes
pidfile /var/run/redis/redis-sentinel.pid
logfile /var/log/redis/redis-sentinel.log
dir /var/lib/redis
# Memantau Master pada IP 192.168.1.30, Quorum diset 2 (butuh 2 sentinel sepakat untuk failover)
sentinel monitor mymaster 192.168.1.30 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 180000
sentinel auth-pass mymaster StrongRedisAuthPass456!
# Nonaktifkan security check bind jika diperlukan untuk lab, pastikan di produksi menggunakanACL
protected-mode no
Jalankan layanan Redis dan Sentinel:
sudo systemctl restart redis-server
redis-sentinel /etc/redis/sentinel.conf
Langkah 5.3: Load Balancing TCP dengan Nginx Stream Module
Masuk ke server Nginx Load Balancer (192.168.1.10). Pastikan modul ngx_stream_module telah terpasang. Sunting file konfigurasi utama /etc/nginx/nginx.conf dengan menambahkan blok stream di luar blok http:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
stream {
# Logging format khusus stream TCP
log_format proxy '$remote_addr [$time_local] '-
'$protocol $status $bytes_sent $bytes_received '-
'$session_time "$upstream_addr"';
access_log /var/log/nginx/tcp_access.log proxy;
error_log /var/log/nginx/tcp_error.log warn;
# Upstream untuk MySQL Read/Write (Menuju Master)
upstream mysql_master {
least_conn;
server 192.168.1.20:3306 max_fails=3 fail_timeout=10s;
}
# Upstream untuk MySQL Read-Only (Menuju Slave)
upstream mysql_slaves {
least_conn;
server 192.168.1.21:3306 max_fails=3 fail_timeout=10s;
# Anda bisa menambahkan server 192.168.1.22:3306 di sini jika ada slave kedua
}
# Upstream untuk Redis Cluster / Sentinel proxy
upstream redis_cluster {
least_conn;
server 192.168.1.30:6379 max_fails=3 fail_timeout=5s;
server 192.168.1.31:6379 max_fails=3 fail_timeout=5s;
server 192.168.1.32:6379 max_fails=3 fail_timeout=5s;
}
# Server Block untuk MySQL Write Proxy
server {
listen 3306;
proxy_pass mysql_master;
proxy_connect_timeout 5s;
proxy_timeout 300s;
}
# Server Block untuk MySQL Read Proxy
server {
listen 3307;
proxy_pass mysql_slaves;
proxy_connect_timeout 5s;
proxy_timeout 300s;
}
# Server Block untuk Redis Proxy
server {
listen 6379;
proxy_pass redis_cluster;
proxy_connect_timeout 3s;
proxy_timeout 60s;
}
}
http {
# Konfigurasi standar HTTP web server Anda di sini...
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
server {
listen 80;
server_name _;
return 200 "Nginx Infrastructure Load Balancer Operational\n";
}
}
Uji konfigurasi Nginx dan lakukan reload:
sudo nginx -t
sudo systemctl reload nginx
6. Bedah Kode & Penjelasan Detail Baris Kunci
Mari kita bedah beberapa parameter krusial dalam konfigurasi di atas:
least_conndalam blokupstream: Mengarahkan koneksi TCP baru ke server backend yang saat ini memiliki jumlah koneksi aktif paling sedikit. Ini sangat penting untuk database dan caching agar beban terdistribusi merata, mencegah satu node slave kelebihan beban sementara slave lain menganggur.gtid_mode = ONdanenforce-gtid-consistency = ON: Menggunakan Global Transaction Identifiers pada MySQL. GTID memastikan setiap transaksi memiliki ID unik di seluruh kluster replikasi. Tanpa GTID, proses failover manual saat master mati akan sangat melelahkan karena kita harus mencari posisi binlog yang tepat secara manual.sentinel monitor mymaster 192.168.1.30 6379 2: Angka2terakhir adalah Quorum. Artinya, minimal harus ada 2 dari 3 instans Sentinel yang sepakat bahwa Master utama (192.168.1.30) benar-benar down (down-after-milliseconds) sebelum memicu proses failover otomatis. Ini mencegah split-brain yang disebabkan oleh gangguan jaringan sesaat (network partition).
7. Skenario Produksi & Studi Kasus Dunia Nyata
Bayangkan sebuah platform e-commerce dengan trafik flash sale mencapai 40.000 request per detik.
- Strategi Pemisahan Beban (Command Query Responsibility Segregation / CQRS sederhana):
- Aplikasi backend dikonfigurasi agar operasi
INSERT,UPDATE, danDELETEdilempar ke port3306(Nginx proxy menuju MySQL Master). - Operasi
SELECTyang bersifat masif (seperti pencarian produk, daftar kategori, profil pengguna) diarahkan ke port3307(Nginx proxy menuju kluster MySQL Slave). - Sesi pengguna (user session) dan rate limiter di-offload sepenuhnya ke port
6379(Redis cluster di belakang Nginx stream).
- Aplikasi backend dikonfigurasi agar operasi
- Hasil Nyata: Beban CPU pada MySQL Master turun hingga 65%, karena seluruh kueri pembacaan berat berhasil diserap oleh dua node Slave, sementara Nginx stream bekerja secara asinkron tanpa overhead HTTP parsing.
8. Common Pitfalls, Anti-Patterns & Solusi
- Anti-Pattern: Menggunakan Nginx HTTP Module untuk Database (TCP)
- Kesalahan: Mencoba menggunakan
location / { proxy_pass http://... }untuk koneksi database. - Solusi: Selalu gunakan modul
stream(stream { server { listen ...; proxy_pass ...; } }) karena database menggunakan protokol TCP murni, bukan HTTP.
- Kesalahan: Mencoba menggunakan
- Pitfall: Time-to-Live (TTL) Koneksi dan Timeout yang Terlalu Panjang
- Kesalahan: Mengabaikan
proxy_timeoutdi Nginx, menyebabkan koneksi TCP zombie menumpuk saat aplikasi terputus tiba-tiba. - Solusi: Definisikan
proxy_timeout 300sdan aktifkanSO_KEEPALIVEpada level sistem operasi Linux (net.ipv4.tcp_keepalive_time).
- Kesalahan: Mengabaikan
- Pitfall: Konfigurasi Quorum Sentinel yang Ganjil
- Kesalahan: Menjalankan 2 node Sentinel dengan Quorum 2. Jika 1 node mati, failover tidak akan pernah terjadi karena kuorum minimal tidak tercapai.
- Solusi: Selalu gunakan jumlah node Sentinel ganjil (minimal 3 instans) dengan kuorum
(n/2) + 1.
9. Benchmark, Metrik Kinerja & Tuning Performa
Untuk menguji ketahanan kluster, kita dapat menggunakan tool benchmark database seperti sysbench atau wrk untuk web aplikasinya. Contoh perintah sysbench untuk menguji performa OLTP read/write melalui Nginx proxy:
sysbench /usr/share/sysbench/oltp_read_write.lua \
--mysql-host=192.168.1.10 \
--mysql-port=3306 \
--mysql-user=app_user \
--mysql-password=SecureAppPass \
--mysql-db=ecommerce \
--tables=10 \
--table-size=100000 \
--threads=64 \
--time=60 \
run
Tuning Parameter Linux Kernel (/etc/sysctl.conf):
Untuk menangani puluhan ribu koneksi TCP konkuren pada Nginx Load Balancer, tambahkan parameter berikut:
fs.file-max = 2097152
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
Terapkan perubahan dengan perintah sudo sysctl -p.
10. Checklist Penerapan Produksi & Kesimpulan
Sebelum meluncurkan arsitektur ini ke lingkungan produksi, pastikan Anda telah mencentang seluruh poin dalam checklist berikut:
- Seluruh kata sandi default (MySQL root, Replicator, Redis AUTH) telah diganti dengan string acak yang kompleks.
- Konfigurasi Firewall (UFW) hanya mengizinkan port yang dibutuhkan dari IP internal aplikasi yang sah.
- Pengujian failover Redis Sentinel telah disimulasikan (matikan proses Master Redis secara paksa dan pastikan aplikasi dapat kembali menulis dalam waktu < 5 detik).
- Log rotasi untuk Nginx stream log dan MySQL binlog telah dikonfigurasi menggunakan
logrotateuntuk mencegah kehabisan ruang disk. - Sistem monitoring (seperti Prometheus dan Grafana dengan node_exporter serta mysqld_exporter) telah aktif memantau metrik kunci.
Dengan mengimplementasikan panduan komprehensif ini, Anda telah membangun fondasi infrastruktur backend yang tidak hanya berkinerja tinggi, tetapi juga memiliki ketahanan tangguh terhadap kegagalan komponen di tingkat enterprise.