Replikasi MySQL dengan Metode Master Slave

Database replication

Metode master slave adalah metode replikasi sederhana yang bisa kita gunakan untuk mendemonstrasikan clustering basis data. Biasanya metode ini tidak direkomendasikan pada lingkungan production, namun sudah cukup menggambarkan bagaimana clustering bekerja.

Dalam latihan ini kita akan membuat sebuah cluster basis data MySQL dengan metode master slave replication dengan menggunakan Docker.

Untuk lingkungan production kita bisa menggunakan image mysql/cluster yang sudah production-ready untuk clustering. mysql/cluster menggunakan engine database yang berbeda yaitu NDB (Network Database) yang teroptimasi untuk basis data terdistribusi.

Mendefinisikan container untuk node master dan slave

Pertama buat sebuah directory baru untuk menempatkan file project latihan. Misalkan dengan nama mysql-cluster. Di dalam directory mysql-cluster, buat sebuah file dengan nama docker-compose.yml. Isikan file tersebut dengan code berikut:

services:
  master:
    image: mysql:8
    container_name: bdl-master
    environment:
      MYSQL_ROOT_PASSWORD: telurrebus
      MYSQL_DATABASE: appku
      MYSQL_USER: bang_kopi
      MYSQL_PASSWORD: telurrebus
    command: >
      --server-id=1
      --log-bin=mysql-bin
      --binlog-do-db=appku
      --binlog_format=ROW
      --gtid_mode=ON
      --enforce-gtid-consistency=ON
      --mysql-native-password=ON
    ports:
      - "3307:3306"
    networks:
      - appku-net
    volumes:
      - ./custom.cnf:/etc/mysql/conf.d/mysql.cnf
  slave1:
    image: mysql:8
    container_name: bdl-slave1
    environment:
      MYSQL_ROOT_PASSWORD: telurrebus
      MYSQL_DATABASE: appku
      MYSQL_USER: bang_kopi
      MYSQL_PASSWORD: telurrebus
    command: >
      --server-id=2
      --relay-log=mysql-relay-bin
      --log-bin=mysql-bin
      --read-only=ON
      --gtid_mode=ON
      --enforce-gtid-consistency=ON
      --mysql-native-password=ON
    ports:
      - "3308:3306"
    depends_on:
      - master
    networks:
      - appku-net
    volumes:
      - ./custom.cnf:/etc/mysql/conf.d/mysql.cnf
  slave2:
    image: mysql:8
    container_name: bdl-slave2
    environment:
      MYSQL_ROOT_PASSWORD: telurrebus
      MYSQL_DATABASE: appku
      MYSQL_USER: bang_kopi
      MYSQL_PASSWORD: telurrebus
    command: >
      --server-id=3
      --relay-log=mysql-relay-bin
      --log-bin=mysql-bin
      --read-only=ON
      --gtid_mode=ON
      --enforce-gtid-consistency=ON
      --mysql-native-password=ON
    ports:
      - "3309:3306"
    depends_on:
      - master
    networks:
      - appku-net
    volumes:
      - ./custom.cnf:/etc/mysql/conf.d/mysql.cnf
networks:
  appku-net:

Selanjutnya, jalankan cluster dengan perintah:

docker compose up -d

Cek status apakah cluster sudah berjalan dengan baik:

docker ps 

Atau kita juga bisa cek dari status dari container dari aplikasi Docker Desktop.

docker compose adalah tools untuk mendefinisikan dan menjalankan serangkaian container. docker compose membaca setiap definisi dari file bernama docker-compose.yml.

docker compose up -d adalah perintah untuk menjalankan rangkaian container yang telah didefinisikan. Argument -d membuat proses container berjalan di sisi background (detach dari session bash). -d adalah shorthand dari detach .

Di dalam docker-compose.yml di atas kita akan membuat 3 buah node MySQL yang terdiri dari 1 master database dan 2 node slave. Master berfungsi sebagai basis data utama, sumber data yang terkini ada di dalam master. Sedangkan slave, kita gunakan sebagai replikasi dan backup. Masing-masing slave hanya kita gunakan untuk membaca data, jadi perubahan data pada slave tidak diizinkan. Ini secara explisit telah kita konfigurasikan pada parameter —read-only=ON .

  slave1:
    image: mysql:8
    container_name: bdl-slave1
    environment:
      MYSQL_ROOT_PASSWORD: telurrebus
      MYSQL_DATABASE: appku
      MYSQL_USER: bang_kopi
      MYSQL_PASSWORD: telurrebus
    command: >
      --server-id=2
      --relay-log=mysql-relay-bin
      --log-bin=mysql-bin
      --read-only=ON # Update data (insert, update, delete) tidak diizinkan
      --gtid_mode=ON
      --enforce-gtid-consistency=ON
      --mysql-native-password=ON

Dalam docker-compose.yml, kita mendefinisikan service dengan nama master , slave1 , dan slave2 . Perlu dicatat bahwa penamaan ini mewakili nama host dari masing-masing intance MySQL yang terhubung di dalam network appku-net . Dengan demikian, masing-masing instance dapat mengenali host yang lainnya dari nama service tersebut.

services:
  master:
    # ... konfigurasi lainnya
    container_name: bdl-master
    networks:
      - appku-net
    # ... konfigurasi lainnya
    
  slave1:
    # ... konfigurasi lainnya
    container_name: bdl-slave1
    networks:
      - appku-net
    # ... konfigurasi lainnya
    
  slave2:
    # ... konfigurasi lainnya
    container_name: bdl-slave2
    networks:
      - appku-net
    # ... konfigurasi lainnya

networks:
  appku-net:


Jika Anda ingin menguji coba koneksi dari salah satu instance MySQL ke instance lainnya, Anda bisa mencoba dengan mengakses mysql-server master dengan menggunakan mysql-client dari salah satu slave. Contoh:

# bash session baru ke dalam bdl-slave1
docker exec -it bdl-slave1 bash
# eksekusi query pada master dari mysql-client dari bdl-slave1 
mysql -h master -u root -p appku -e 'show tables'

Argument dalam menjalankan mysqld

Pada setiap container, kita menggunakan image mysql:8 yang akan di-pull dari DockerHub. Konfigurasi command berfungsi untuk mem-passing argument saat menjalankan mysqld

command: >
      --server-id=3
      --relay-log=mysql-relay-bin
      --log-bin=mysql-bin
      --read-only=ON
      --gtid_mode=ON
      --enforce-gtid-consistency=ON
      --mysql-native-password=ON

Berikut penjelasan beberapa argument kunci yang digunakan dalam konfgurasi:

  • --relay-log=mysql-relay-bin Menentukan nama file relay log yang digunakan oleh server slave dalam replikasi.
  • --log-bin=mysql-bin Mengaktifkan binary log untuk mencatat semua perubahan data. Diperlukan untuk replikasi master-slave dan pemulihan data.
  • --read-only=ON Membuat server hanya bisa menerima query baca (SELECT)
  • --gtid_mode=ON Mengaktifkan Global Transaction Identifiers (GTID) untuk replikasi yang lebih andal dan mudah dikelola.
  • --enforce-gtid-consistency=ON Memastikan semua transaksi dalam database mematuhi aturan GTID agar replikasi tetap konsisten.
  • --mysql-native-password=ON Mengaktifkan metode autentikasi lama mysql_native_password, biasanya untuk kompatibilitas dengan klien atau aplikasi lama.

mysqld adalah program daemon untuk menjalankan mysql-server . mysqld dapat menerima berbagai argument/option eksekusi seperti contoh pada docker-compose.yml

Setup database client dengan DataGrip (atau client lainnya)

Untuk tahap selanjutnya, saya sarankan Anda mnggunakan DataGrip atau aplikasi client berbasis GUI untuk memudahkan interaksi dengan masing-masing instance.

Buat sebuah project baru dengan DataGrip kemudian, tambahkan setiap node sebagai data source. Untuk membuat project baru bisa dengan:

  1. File → New Project
  2. Berikan nama project, misalkan dbl-cluster
  3. Tambahkan data source baru ke dalam project dengan klik icon Plus (+) → MySQL → MySQL
add new data source on DataGrip
  1. Gunakan user root dan masukan credentials lain sesuai dengan docker-compose.yml
set new datasource credentials
  1. Lakukan langkah 4 untuk data source dari master, slave1, dan slave2.

Melakukan konfigurasi pada master

Kita perlu melakukan konfigurasi pada node master untuk mengijinkan replikasi dari semua slave.

Klik kanan pada data source master → New → Query Console.

Lakukan eksekusi query berikut:

GRANT REPLICATION SLAVE ON *.* TO 'bang_kopi'@'%';
FLUSH PRIVILEGES;
SHOW BINARY LOG STATUS;
SHOW BINARY LOG STATUS;

Catat value dari kolom File dan Position karena akan kita gunakan pada tahap berikutnya.

Melakukan konfigurasi pada slave

Ekskusi query berikut pada node slave:

STOP REPLICA;

CHANGE REPLICATION SOURCE TO 
    SOURCE_HOST='master',
    SOURCE_USER='bang_kopi',
    SOURCE_PASSWORD='telurrebus',
    SOURCE_LOG_FILE='mysql-bin.000004', -- gunakan hasil dari SHOW BINARY LOG STATUS dari master
    SOURCE_LOG_POS=582; -- gunakan hasil dari SHOW BINARY LOG STATUS dari master

START REPLICA; -- memulai replikasi

SHOW REPLICA STATUS; -- melihat status replikasi (koneksi) dengan master

SHOW REPLICA STATUS akan menampilkan apakah slave sudah terhubung dengan master. Jika sukses, hasilnya akan menampilkan log bahwa slave telah siap menerima perubahan dari master.

             Replica_IO_State: Waiting for source to send event
                  Source_Host: master
                  Source_User: bang_kopi
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: mysql-bin.000007
          Read_Source_Log_Pos: 1465
               Relay_Log_File: mysql-relay-bin.000002
                Relay_Log_Pos: 1171
        Relay_Source_Log_File: mysql-bin.000007
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 1465
              Relay_Log_Space: 1382
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Source_SSL_Allowed: No
           Source_SSL_CA_File:
           Source_SSL_CA_Path:
              Source_SSL_Cert:
            Source_SSL_Cipher:
               Source_SSL_Key:
        Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Source_Server_Id: 1
                  Source_UUID: 7203c779-0a23-11f0-8899-0242ac120002
             Source_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
    Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Source_Retry_Count: 10
                  Source_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Source_SSL_Crl:
           Source_SSL_Crlpath:
           Retrieved_Gtid_Set: 7203c779-0a23-11f0-8899-0242ac120002:6-8
            Executed_Gtid_Set: 7203c779-0a23-11f0-8899-0242ac120002:6-8
                Auto_Position: 0
         Replicate_Rewrite_DB:
                 Channel_Name:
           Source_TLS_Version:
       Source_public_key_path:
        Get_Source_public_key: 0
            Network_Namespace:

Lakukan tahap di atas pada semua node slave (slave1 dan slave2).

Error authentication

Jika Anda menemukan error Authentication plugin 'caching_sha2_password' cannot be loaded pada SHOW REPLICA STATUS , lakukan pergantian plugin password user pada node master agar menggunakan plugin mysql_native_password .

ALTER USER 'bang_kopi'@'%' IDENTIFIED WITH mysql_native_password BY 'telurrebus';
FLUSH PRIVILEGES;

Setelah itu pada node slave, ulangi proses:

STOP REPLICA;

CHANGE REPLICATION SOURCE TO 
    SOURCE_HOST='master',
    SOURCE_USER='bang_kopi',
    SOURCE_PASSWORD='telurrebus',
    SOURCE_LOG_FILE='mysql-bin.000004', -- gunakan hasil dari SHOW BINARY LOG STATUS dari master
    SOURCE_LOG_POS=582; -- gunakan hasil dari SHOW BINARY LOG STATUS dari master

START REPLICA;

SHOW REPLICA STATUS;

Oleh karena koneksi di dalam Docker network tidak menggunakan SSL/TLS, maka kita perlu menggunakan otentikasi dengan cara lama yaitu mysql_native_password . SSL/TLS secara default telah berlaku pada MySQL versi 8+.

Test replikasi

Kita bisa melakukan uji coba replikasi dengan membuat table baru pada database appku pada node master. Setelah itu, cek node slave, dan pastikan table baru tersebut juga muncul. Eksekusi query berikut untuk membuat sebauh test table dengan nama pendaftaran:

create table pendaftaran
(
    id int auto_increment primary key,
    nama varchar(255) null
);

Selamat mencoba 🍃

Download project:

Contoh project dapat didownload via Github repository berikut: https://github.com/budasuyasa/mysql-cluster-demo

Previous Article

Multi Form dengan InertiaJS

Next Article

Membuat Single Sign On menggunakan OAuth 2.0 dengan Laravel.