Kalau kamu ngurus server produksi, database itu biasanya komponen yang paling bikin jantungan. Mau server aplikasi kamu dipasang autoscaling sampai puluhan instance pun, kalau database cuma sebiji dan mendadak mati, ya seluruh sistem langsung lumpuh total (single point of failure).
Banyak orang ngakalin ini pakai replikasi klasik Master-Slave. Tapi jujur aja, skema Master-Slave itu sering bikin ribet di lapangan. Begitu Master mati di tengah malam, kamu mesti manual promosiin Slave jadi Master baru, utak-atik IP di config aplikasi, baru service bisa jalan normal lagi.
Nah, solusi yang lebih praktis buat arsitektur dua server adalah Replikasi Master-Master MariaDB (sering disebut Active-Active atau Dual-Master) yang dipadukan bareng Nginx Reverse Proxy (TCP Stream Layer 4). Dua node database saling kirim dan terima data secara silang, sementara aplikasi backend kamu cukup tahu satu IP pintu masuk lewat Nginx.

Apa Sih Replikasi Master-Master Itu?
Singkatnya, di arsitektur Master-Master, kedua server MariaDB berperan ganda: masing-masing jadi Master sekaligus Slave buat pasangannya.
- Node 1 adalah Master bagi Node 2, dan sekaligus jadi Slave yang narik data dari Node 2.
- Node 2 adalah Master bagi Node 1, dan sekaligus jadi Slave yang narik data dari Node 1.
Tiap kali ada transaksi tulis (INSERT, UPDATE, DELETE) di Node 1, MariaDB bakal nyatet transaksi itu ke file binary log (binlog), lalu Node 2 bakal baca log tersebut dan ngejalanin query yang sama di databasenya. Begitu juga sebaliknya. Hasilnya, isi data di kedua server selalu sinkron secara real-time.
Master-Master vs Master-Slave: Apa Bedanya?
Biar kebayang kenapa kita gak pakai skema biasa, coba bandingin karakteristik keduanya:
| Aspek | Master-Slave (Satu Arah) | Master-Master (Dua Arah) |
|---|---|---|
| Arah Replikasi | 1 arah (Master > Slave) | 2 arah bolak-balik (Node 1 > Node 2 dan sebaliknya) |
| Hak Nulis (Write) | Cuma boleh di Master | Bisa diterima di kedua node |
| Failover saat Node Mati | Manual promosi Slave atau butuh tool failover ekstra | Gak perlu promosi, node cadangan udah berstatus Master |
| Pengaturan Auto-Increment | Default / normal | Wajib set increment dan offset (ganjil/genap) |
| Maintenance Server | Bikin waswas, butuh maintenance window malam hari | Santai, bisa gantian reboot server tanpa bikin web down |
| Resource Minimum | 2 server (1 Master, 1 Slave) | 2 server DB + 1 proxy ringan |
Kenapa Master-Slave Sering Bikin Pusing?
Di Master-Slave biasa, si Slave diset dalam mode read-only. Aplikasi cuma diizinin nulis ke Master.
Pas Master tiba-tiba mati (entah kernel panic, storage penuh, atau hardware jebol), Slave gak bakal otomatis naik kasta jadi Master. Aplikasi bakal langsung ngelempar error gagal nulis database (read-only error). Ujung-ujungnya, sysadmin harus kebangun jam 3 subuh, login lewat SSH, matiin mode read-only di Slave, terus ganti config database di seluruh aplikasi. Ada jeda downtime yang gak terelakkan di situ.
Gimana dengan Master-Master?
Karena sejak awal kedua server posisinya setara (sama-sama Master), kita gak perlu pusing mikirin proses "promosi database". Dua-duanya siap nampung query tulis kapan aja.
Kenapa Milih Master-Master?
Kenapa skema ini sering jadi pilihan favorit buat infrastruktur skala kecil sampai menengah?
- Maintenance Tanpa Downtime: Mau upgrade versi MariaDB, nambah RAM, atau reboot kernel OS? Tinggal arahin traffic aplikasi ke Node 2, kerjain maintenance di Node 1 sampai beres. Begitu Node 1 nyala lagi, dia bakal langsung ngejar ketertinggalan datanya lewat binlog. Habis itu gantian giliran Node 2. Aplikasi tetap online 100% dan user gak bakal sadar ada server yang lagi di-restart.
- Hemat Resource (Gak Boros Budget): Kalau mau cluster database sekelas Galera Cluster, kamu butuh minimal 3 node biar tercapai quorum dan terhindar dari kondisi split-brain. Buat tim kecil atau proyek dengan budget terbatas, sewa 3 server khusus DB itu kerasa boros. Master-Master cuma butuh 2 node DB ditambah 1 proxy enteng.
- Redundansi Data Aman: Datanya terduplikasi secara real-time di dua mesin fisik atau datacenter terpisah. Kalau salah satu server kebakar atau kena gangguan network, data kamu gak hilang.
Kenapa Perlu Nginx TCP Stream?
Nginx selama ini terkenal sebagai web server buat port 80 (HTTP) dan 443 (HTTPS). Tapi Nginx juga punya modul bawaan sakti namanya stream yang jalan di Layer 4 (TCP/UDP).
Fungsi Nginx di sini simpel tapi penting banget:
- Single Entry Point: Aplikasi backend kita (Laravel, Node.js, Go, Python, dll.) gak usah dipusingin sama urusan ada berapa server database di belakang. Di file
.env, aplikasi cukup nembak ke satu IP: IP Nginx port 3306. - Penyambung Koneksi: Nginx yang bertugas nerusin koneksi TCP database ke node MariaDB yang lagi aktif dan sehat.
Topologi Lab
Di panduan ini, kita simulasiin pakai 3 server Ubuntu:
| Hostname / Node | IP Address | Peran |
|---|---|---|
| Nginx Proxy | 192.168.2.3 | TCP Stream Reverse Proxy (Port 3306) |
| MariaDB 1 | 192.168.2.11 | Node Master 1 (server-id = 1) |
| MariaDB 2 | 192.168.3.11 | Node Master 2 (server-id = 2) |
Kalau MariaDB dan Nginx belum terpasang di server kamu, tinggal install lewat package manager standar:
sudo apt update && sudo apt install -y mariadb-server nginx.
Langkah 1: Nyetel Config MariaDB (Node 1 dan Node 2)
Di replikasi Master-Master, ada satu aturan wajib: Primary Key auto-increment gak boleh tabrakan.
Bayangin kalau Node 1 dan Node 2 nerima query INSERT di detik yang sama. Kalau dua-duanya nge-generate ID 1, pas datanya mau disinkronin ke seberang bakal langsung error duplicate entry dan replikasi bakal putus seketika.
Trik buat ngatasinnya gampang: kita atur Node 1 cuma nge-generate ID ganjil (1, 3, 5, 7...), sedangkan Node 2 cuma nge-generate ID genap (2, 4, 6, 8...).
Konfigurasi di Server 1 (192.168.2.11)
Buka file konfigurasi MariaDB:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnfCari bagian [mysqld], terus sesuaikan baris-baris ini:
# Buka bind address biar bisa diakses lewat network lokal
bind-address = 0.0.0.0
# ID unik buat Node 1
server-id = 1
# Aktifkan binary logging
log_bin = /var/log/mysql/mysql-bin.log
# Set auto-increment ID Ganjil (1, 3, 5, 7...)
auto_increment_increment = 2
auto_increment_offset = 1Konfigurasi di Server 2 (192.168.3.11)
Buka file yang sama di Server 2:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnfSesuaikan konfigurasinya (perhatiin server-id dan auto_increment_offset):
# Buka bind address biar bisa diakses lewat network lokal
bind-address = 0.0.0.0
# ID unik buat Node 2 (wajib beda sama Node 1)
server-id = 2
# Aktifkan binary logging
log_bin = /var/log/mysql/mysql-bin.log
# Set auto-increment ID Genap (2, 4, 6, 8...)
auto_increment_increment = 2
auto_increment_offset = 2Kalau udah, restart service MariaDB di kedua server biar config barunya kebaca:
sudo systemctl restart mariadbLangkah 2: Bikin User Replikasi
Biar kedua server bisa saling kontak dan narik file binlog, kita perlu bikinin user khusus dengan privilege REPLICATION SLAVE di masing-masing mesin.
Di Server 1 (192.168.2.11)
Masuk ke MySQL console:
sudo mysql -u root -pBikin user dan kasih izin khusus dari IP Server 2:
CREATE USER 'replikasi'@'192.168.3.11' IDENTIFIED BY 'PasswordKuatReplikasi123!';
GRANT REPLICATION SLAVE ON *.* TO 'replikasi'@'192.168.3.11';
FLUSH PRIVILEGES;
EXIT;Di Server 2 (192.168.3.11)
Lakuin hal yang sama di Server 2, tapi izinkan akses dari IP Server 1:
sudo mysql -u root -pCREATE USER 'replikasi'@'192.168.2.11' IDENTIFIED BY 'PasswordKuatReplikasi123!';
GRANT REPLICATION SLAVE ON *.* TO 'replikasi'@'192.168.2.11';
FLUSH PRIVILEGES;
EXIT;Langkah 3: Sambungin Replikasi Dua Arah (Handshake)
Sekarang kita catat posisi file binlog aktif di masing-masing server, terus kita tautkan secara silang.
1. Cek Binlog Status di Server 1
Di console MariaDB Server 1, jalankan:
SHOW MASTER STATUS;Outputnya bakal mirip kayak gini:
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 | 564 | | |
+------------------+----------+--------------+------------------+Catat nama File (mysql-bin.000001) dan angka Position (564).
2. Cek Binlog Status di Server 2
Di console MariaDB Server 2, jalankan perintah yang sama:
SHOW MASTER STATUS;Outputnya:
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 | 564 | | |
+------------------+----------+--------------+------------------+Catat juga nama File dan angka Position milik Server 2.
3. Set Server 1 Mengikuti Server 2
Di console MariaDB Server 1, jalanin query CHANGE MASTER TO yang mengarah ke IP Server 2 beserta posisi log-nya:
STOP SLAVE;
CHANGE MASTER TO
MASTER_HOST='192.168.3.11',
MASTER_USER='replikasi',
MASTER_PASSWORD='PasswordKuatReplikasi123!',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=564;
START SLAVE;Cek apakah koneksinya udah nyambung:
SHOW SLAVE STATUS \GParameter yang wajib diperhatiin: Pastikan dua baris ini statusnya bernilai
Yes:
Slave_IO_Running: YesSlave_SQL_Running: YesKalau salah satunya masih
NoatauConnecting, cek lagi password replikasi, firewall port 3306, atau bind-address server tujuan.
4. Set Server 2 Mengikuti Server 1
Sekarang balik ke console MariaDB Server 2, jalankan perintah yang sama tapi arahkan ke Server 1:
STOP SLAVE;
CHANGE MASTER TO
MASTER_HOST='192.168.2.11',
MASTER_USER='replikasi',
MASTER_PASSWORD='PasswordKuatReplikasi123!',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=564;
START SLAVE;Cek lagi statusnya:
SHOW SLAVE STATUS \GPastikan Slave_IO_Running: Yes dan Slave_SQL_Running: Yes. Kalau keduanya udah Yes, replikasi dua arah kamu udah aktif.
Langkah 4: Uji Coba Sinkronisasi Data
Biar makin yakin replikasi bolak-baliknya jalan beneran, kita coba tes bikin database dari kedua sisi:
-
Tes tulis di Server 1: Di Server 1, bikin database baru:
CREATE DATABASE db_test_satu;Buka console Server 2 terus cek:
SHOW DATABASES;Database
db_test_satulangsung muncul otomatis di Server 2. -
Tes tulis di Server 2: Di Server 2, bikin database lain:
CREATE DATABASE db_test_dua;Buka console Server 1 terus cek:
SHOW DATABASES;Database
db_test_duajuga langsung nongol di Server 1. Sinkronisasi dua arah udah terbukti jalan mulus.
Langkah 5: Setup Nginx Reverse Proxy (TCP Stream)
Sekarang pindah ke server ketiga: Nginx Proxy (192.168.2.3).
Buka file /etc/nginx/nginx.conf:
sudo nano /etc/nginx/nginx.confTambahkan blok stream di bagian paling bawah file (ingat: posisinya di luar blok http { ... }):
stream {
upstream mariadb_cluster {
server 192.168.2.11:3306;
server 192.168.3.11:3306;
}
server {
listen 3306;
proxy_pass mariadb_cluster;
proxy_connect_timeout 2s;
proxy_timeout 10m;
}
}
Tes dulu konfigurasinya, baru reload service Nginx:
sudo nginx -t
sudo systemctl restart nginxPastikan Nginx udah beneran nahan port 3306 TCP:
sudo netstat -tulpn | grep nginx
Langkah 6: Atur Hak Akses User Aplikasi lewat IP Nginx
Karena aplikasi backend nantinya nembak ke database lewat perantara IP Nginx (192.168.2.3), MariaDB di kedua node perlu dikasih tahu kalau user aplikasi boleh login dari IP Nginx tersebut.
Di console MariaDB Server 1 dan Server 2, bikinin user aplikasi kamu:
CREATE USER 'appuser'@'192.168.2.3' IDENTIFIED BY 'PasswordAplikasiRahasia123!';
GRANT ALL PRIVILEGES ON *.* TO 'appuser'@'192.168.2.3';
FLUSH PRIVILEGES;
Sekarang coba tes koneksi dari mesin lain atau server aplikasi ke IP Nginx:
mysql -h 192.168.2.3 -P 3306 -u appuser -pBegitu login berhasil, Nginx bakal secara transparan nerusin sesi TCP database kamu ke salah satu node MariaDB yang sehat.
Catatan Penting Buat di Lingkungan Produksi
Biar gak kena jebakan di kemudian hari, ada beberapa hal krusial yang perlu kamu perhatiin kalau mau masang setup ini di production:
- Jaga Auto-Increment Offset: Parameter
auto_increment_incrementdanauto_increment_offsetyang kita pasang di awal itu jangan sampai kelewat atau diubah sembarangan. Ini pengaman utama biar gak tabrakan ID waktu ada transaksi barengan di kedua server. - Pakai Skema Active-Passive via Proxy Lebih Aman: Walaupun arsitekturnya Master-Master, untuk aplikasi web umum yang sering update record di tabel yang sama (misal saldo rekening, stok barang), nulis ke dua server secara bersamaan (Active-Active Write) rawan memicu race condition. Pendekatan paling aman di lapangan adalah bikin routing Nginx jadi Active-Passive: arahkan semua traffic tulis ke Node 1, dan tandai Node 2 sebagai cadangan pakai opsi
backupdi upstream Nginx (server 192.168.3.11:3306 backup;). Jadi kalau Node 1 mati, traffic baru otomatis pindah ke Node 2. - Atur Retensi Binlog: File log transaksi (
mysql-bin.xxxxxx) bakal terus nambah seiring banyaknya transaksi database. Jangan lupa set batas waktu rotasi di config (misalbinlog_expire_logs_seconds = 604800buat nyimpen log 7 hari) biar partisi disk/var/log/gak mendadak penuh dan bikin database mogok. - Pantau Lag Replikasi: Sesekali cek nilai
Seconds_Behind_MasterdiSHOW SLAVE STATUS \G. Di kondisi jaringan normal nilainya harus0. Kalau nilainya bengkak gede, berarti ada antrean transaksi panjang di salah satu node yang perlu diinvestigasi.
Setup Master-Master plus Nginx stream ini udah lebih dari cukup buat bikin database kamu tahan banting tanpa harus nguras resource server dan tanpa ribet ngurus cluster yang rumit. Tinggal disesuaikan sama kebutuhan aplikasi dan resource yang kamu punya.