~/blog/#57
Index
#57··11 min read·database

Replikasi Master-Master MariaDB + Nginx Reverse Proxy

Catatan setup replikasi dua arah MariaDB (Master-Master) bareng Nginx TCP stream sebagai reverse proxy buat ngatasin single point of failure tanpa cluster yang ribet.

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.

Master-Master MariaDB Topology
Topologi Replikasi Master-Master MariaDB dengan Nginx Proxy

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:

AspekMaster-Slave (Satu Arah)Master-Master (Dua Arah)
Arah Replikasi1 arah (Master > Slave)2 arah bolak-balik (Node 1 > Node 2 dan sebaliknya)
Hak Nulis (Write)Cuma boleh di MasterBisa diterima di kedua node
Failover saat Node MatiManual promosi Slave atau butuh tool failover ekstraGak perlu promosi, node cadangan udah berstatus Master
Pengaturan Auto-IncrementDefault / normalWajib set increment dan offset (ganjil/genap)
Maintenance ServerBikin waswas, butuh maintenance window malam hariSantai, bisa gantian reboot server tanpa bikin web down
Resource Minimum2 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?

  1. 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.
  2. 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.
  3. 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 / NodeIP AddressPeran
Nginx Proxy192.168.2.3TCP Stream Reverse Proxy (Port 3306)
MariaDB 1192.168.2.11Node Master 1 (server-id = 1)
MariaDB 2192.168.3.11Node 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.cnf

Cari 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    = 1

Konfigurasi di Server 2 (192.168.3.11)

Buka file yang sama di Server 2:

sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf

Sesuaikan 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    = 2

Kalau udah, restart service MariaDB di kedua server biar config barunya kebaca:

sudo systemctl restart mariadb

Langkah 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 -p

Bikin 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 -p
CREATE 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 \G

Parameter yang wajib diperhatiin: Pastikan dua baris ini statusnya bernilai Yes:

  • Slave_IO_Running: Yes
  • Slave_SQL_Running: Yes

Kalau salah satunya masih No atau Connecting, 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 \G

Pastikan 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:

  1. 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_satu langsung muncul otomatis di Server 2.

  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_dua juga 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.conf

Tambahkan 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;
    }
}
Nginx Stream Configuration
Penempatan Blok Stream di nginx.conf

Tes dulu konfigurasinya, baru reload service Nginx:

sudo nginx -t
sudo systemctl restart nginx

Pastikan Nginx udah beneran nahan port 3306 TCP:

sudo netstat -tulpn | grep nginx
Nginx Listening on Port 3306
Nginx Sudah Standby di Port 3306 TCP

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;
Konfigurasi Hak Akses Database
Memberikan Hak Akses Login dari IP Nginx Proxy

Sekarang coba tes koneksi dari mesin lain atau server aplikasi ke IP Nginx:

mysql -h 192.168.2.3 -P 3306 -u appuser -p

Begitu 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:

  1. Jaga Auto-Increment Offset: Parameter auto_increment_increment dan auto_increment_offset yang 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.
  2. 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 backup di upstream Nginx (server 192.168.3.11:3306 backup;). Jadi kalau Node 1 mati, traffic baru otomatis pindah ke Node 2.
  3. Atur Retensi Binlog: File log transaksi (mysql-bin.xxxxxx) bakal terus nambah seiring banyaknya transaksi database. Jangan lupa set batas waktu rotasi di config (misal binlog_expire_logs_seconds = 604800 buat nyimpen log 7 hari) biar partisi disk /var/log/ gak mendadak penuh dan bikin database mogok.
  4. Pantau Lag Replikasi: Sesekali cek nilai Seconds_Behind_Master di SHOW SLAVE STATUS \G. Di kondisi jaringan normal nilainya harus 0. 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.

Tags:#mariadb#database#high-availability#nginx#linux