Muhammad Adistya Azhar 05111640000103
Implementasi Multi Master Group Replica
Soal 1: Desain dan implementasi infrastruktur Arsitektur terdiri dari 3 database server, 1 database load balancer, 1 web server, dan 1 reverse proxy. Kotak merah menandakan berada dalam 1 vagrant machine.
Desain Infrastruktur Basis Data Terdistribusi & Load Balancing
a. Database Server
- Database 1
- RAM: 512 MB
- OS: Ubuntu 16.04
- IP: 192.168.16.103
- Database 2
- RAM: 512 MB
- OS: Ubuntu 16.04
- IP: 192.168.16.104
- Database 3
- RAM: 512 MB
- OS: Ubuntu 16.04
- IP: 192.168.16.105
b. Database Load Balancer
- ProxySQL:
- RAM: 512 MB
- OS: Ubuntu 16.04
- 192.168.16.107
c. Web Server & Reverse Proxy
- Kestrel & Nginx
- RAM: 1024 MB
- OS: Ubuntu 16.04
- 192.168.16.106
Implementasi infrastruktur basis data terdistribusi
a. Proses instalasi database server Database yang digunakan adalah MySQL dengan plugin MySQL Group replication. Berikut adalah step yang harus dilakukan:
- Download MySQL Server dan MySQL Client binary (dilakukan di ketiga DB server)
curl -OL https://dev.mysql.com/get/Downloads MySQL-5.7mysql-common_5.7.23-1ubuntu16.04_amd64.deb curl -OL https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-community-client_5.7.23-1ubuntu16.04_amd64.deb curl -OL https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-client_5.7.23-1ubuntu16.04_amd64.deb curl -OL https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-community-server_5.7.23-1ubuntu16.04_amd64.deb
- Set default MySQL password agar tidak perlu input manual saat instalasi (dilakukan di ketiga DB server)
sudo debconf-set-selections <<< 'mysql-community-server mysql-community-server/root-pass password admin' sudo debconf-set-selections <<< 'mysql-community-server mysql-community-server/re-root-pass password admin'
- Run .deb file yang telah didownload pada step 1 (dilakukan di ketiga DB server):
sudo dpkg -i mysql-common_5.7.23-1ubuntu16.04_amd64.deb sudo dpkg -i mysql-community-client_5.7.23-1ubuntu16.04_amd64.deb sudo dpkg -i mysql-client_5.7.23-1ubuntu16.04_amd64.deb sudo dpkg -i mysql-community-server_5.7.23-1ubuntu16.04_amd64.deb
- MySQL berkomunikasi menggunakan port 33061 dan 3306, maka kita harus membuka port tersebut (dilakukan di ketiga DB server):
sudo ufw allow 33061 sudo ufw allow 3306
- Setiap MySQL server membutuhkan file konfigurasi
my.cnf
. Agar group replication dapat berjalan, kita harus set beberapa variable. Database server yang akan kita buat memiliki IP sebagai berikut:192.168.16.103
,192.168.16.104
, dan192.168.16.105
. Ketiga nya akan berada dalam 1 group, dan berperan sebagaiwrite
danread
. Setiap group memiliki identifier yang unik, dan harus kita definisikan sendiri. Linux memiliki commanduuidgen
untuk membuat UUID. Output dariuuidgen
akan digunakan untuk set variableloose-group_replication_group_name="8f22f846-9922-4139-b2b7-097d185a93cb"
. Setelah setloose-group_replication_group_name
kita harus menambahkan IP DB server ke dalam whitelist untuk menentukan IP mana saja yang boleh connect ke group. Parameter tersebut adalahloose-group_replication_ip_whitelist="192.168.16.103, 192.168.16.104, 192.168.16.105"
. Ketiga member tersebut akan memberi data jika ada member yang baru join, maka agar pemberian data dapat terjadi, parameterloose-group_replication_group_seeds
terisi menjadiloose-group_replication_group_seeds = "192.168.16.103:33061, 192.168.16.104:33061, 192.168.16.105:33061"
. Agar multi primary mode nyala, kita harus mematikan single primary mode dengan caraloose-group_replication_single_primary_mode = OFF
. Setiap DB Server memiliki host specific konfigurasi, parameter berikut hanya berlaku dengan IP server dimana DB berjalan:
bind-address = "192.168.16.103"
report_host = "192.168.16.103"
loose-group_replication_local_address = "192.168.16.103:33061"
Berikut adalah contoh file my.cnf
.
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
[mysqld]
# General replication settings
gtid_mode = ON
enforce_gtid_consistency = ON
master_info_repository = TABLE
relay_log_info_repository = TABLE
binlog_checksum = NONE
log_slave_updates = ON
log_bin = binlog
binlog_format = ROW
transaction_write_set_extraction = XXHASH64
loose-group_replication_bootstrap_group = OFF
loose-group_replication_start_on_boot = OFF
loose-group_replication_ssl_mode = REQUIRED
loose-group_replication_recovery_use_ssl = 1
# Shared replication group configuration
loose-group_replication_group_name = "8f22f846-9922-4139-b2b7-097d185a93cb"
loose-group_replication_ip_whitelist = "192.168.16.103, 192.168.16.104, 192.168.16.105"
loose-group_replication_group_seeds = "192.168.16.103:33061, 192.168.16.104:33061, 192.168.16.105:33061"
# Single or Multi-primary mode? Uncomment these two lines
# for multi-primary mode, where any host can accept writes
loose-group_replication_single_primary_mode = OFF
loose-group_replication_enforce_update_everywhere_checks = ON
# Host specific replication configuration
server_id = 103
bind-address = "192.168.16.103"
report_host = "192.168.16.103"
loose-group_replication_local_address = "192.168.16.103:33061"
- Restart MySQL Server
sudo systemctl restart mysql
- Buat MySQL User khusus untuk proses replikasi, dan install
Group Replication Plugin
(dilakukan di ketiga DB server).
mysql -u root -p
msql> SET SQL_LOG_BIN=0;
msql> CREATE USER 'repl'@'%' IDENTIFIED BY 'password' REQUIRE SSL;
msql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
msql> FLUSH PRIVILEGES;
msql> SET SQL_LOG_BIN=1;
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='password' FOR CHANNEL 'group_replication_recovery';
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
- Mulai group replication. Ketika belum ada member yang belum join group, maka harus dilakukan step khusus. Harus dilakukan ini karena member akan bergantung pada member lain untuk mendapatkan data. Oleh karena itu, untuk member pertama yang join group, kita akan set agar tidak mengharapkan data. (Hanya dilakukan di salah 1 member)
(192.168.16.103) mysql> SET GLOBAL group_replication_bootstrap_group=ON;
(192.168.16.103) mysql> START GROUP_REPLICATION;
(192.168.16.103) mysql> SET GLOBAL group_replication_bootstrap_group=OFF;
Cek member sudah masuk grup:
(192.168.16.103) mysql> SELECT * FROM performance_schema.replication_group_members;
- Join group untuk member yang lain dengan cara:
(192.168.16.104) mysql> START GROUP_REPLICATION;
(192.168.16.105) mysql> START GROUP_REPLICATION;
Cek bahwa seluruh member sudah join group:
(192.168.16.105) mysql> SELECT * FROM performance_schema.replication_group_members;
b. Proses instalasi database load balancer ProxySQL
- Download file dan install
.deb
ProxySQL
curl -OL https://github.com/sysown/proxysql/releases/download/v1.4.4/proxysql_1.4.4-ubuntu16_amd64.deb
sudo dpkg -i proxysql_*
- Start ProxySQL
sudo systemctl start proxysql
- Konfigurasi monitoring MySQL member. Kita harus download
.sql
file yang berisi fungsi agar ProxySQL grou replication dapat berjalan. (Masuk ke salah 1 member MySQL)
(192.168.16.103)> curl -OL https://gist.github.com/lefred/77ddbde301c72535381ae7af9f968322/raw/5e40b03333a3c148b78aa348fd2cd5b5dbb36e4d/addition_to_sys.sql
(192.168.16.103) mysql -u root -p < addition_to_sys.sql
(192.168.16.103) mysql -u root -p
(192.168.16.103) mysql> CREATE USER 'monitor'@'%' IDENTIFIED BY 'monitorpassword';
(192.168.16.103) mysql> GRANT SELECT on sys.* to 'monitor'@'%';
(192.168.16.103) mysql> FLUSH PRIVILEGES;
- Tambahkan akun monitoring yang baru dibuat pada step 3 ke ProxySQL (run command pada server yang host ProxySQL)
mysql -u admin -p -h 127.0.0.1 -P 6032 --prompt='ProxySQLAdmin> '
ProxySQLAdmin> UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_username';
ProxySQLAdmin> UPDATE global_variables SET variable_value='monitorpassword' WHERE variable_name='mysql-monitor_password';
ProxySQLAdmin> LOAD MYSQL VARIABLES TO RUNTIME;
ProxySQLAdmin> SAVE MYSQL VARIABLES TO DISK;
- Tambahkan MySQL member ke ProxySQL Server Pool
Agar ProxySQL mengetahui MySQL member kita, maka MysSQL member harus dimasukkan ke dalam host group. Setiap host group teridentifikasi menggunakan angka. Host group memiliki 4 logical state:
- writers: query yang mengubah data.
- backup writers: query yang mengubah data, tapi hanya berjalan ketika primari writers bermasalah.
- readers: query yang membaca data, tidak ada operasi mengubah.
- offline: node yang bermasalah, ada network problem.
Kita akan menggunakan identifier host group 1
untuk offline, 2
untuk writer, 3 untuk reader, dan 4
untuk backup writer.
ProxySQLAdmin> INSERT INTO mysql_group_replication_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind) VALUES (2, 4, 3, 1, 1, 3, 1, 100);
ProxySQLAdmin> INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES (2, '192.168.16.103', 3306);
ProxySQLAdmin> INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES (2, '192.168.16.104', 3306);
ProxySQLAdmin> INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES (2, '192.168.16.105', 3306);
ProxySQLAdmin> LOAD MYSQL SERVERS TO RUNTIME;
ProxySQLAdmin> SAVE MYSQL SERVERS TO DISK;
Cek MySQL member yang terdapat dalam hostgroup:
ProxySQLAdmin> SELECT hostgroup_id, hostname, status FROM runtime_mysql_servers;
- Bikin MySQL member user yang akan digunakan oleh ProxySQL (dilakukan di salah 1 member)
(192.168.16.103) mysql -u root -p
(192.168.16.103) mysql> CREATE USER 'bloguser'@'%' IDENTIFIED BY 'password';
(192.168.16.103) mysql> CREATE DATABASE blog;
(192.168.16.103) mysql> GRANT ALL PRIVILEGES on blog.* to 'bloguser'@'%';
(192.168.16.103) mysql> FLUSH PRIVILEGES;
- Tambahkan MySQL user pada step 4 ke ProxySQL (command dilakukan di ProxySQL server)
mysql -u admin -p -h 127.0.0.1 -P 6032 --prompt='ProxySQLAdmin> '
ProxySQLAdmin> INSERT INTO mysql_users(username, password, default_hostgroup) VALUES ('bloguser', 'password', 2);
ProxySQLAdmin> LOAD MYSQL USERS TO RUNTIME;
ProxySQLAdmin> SAVE MYSQL USERS TO DISK;
File bash
yang digunakan untuk provisioning adalah:
- Database:
deployMySQL103.sh
,deployMySQL104.sh
,deployMySQL105.sh
- Database Load Balancer:
deployProxySQL.sh
- Webserver:
deployWebServer.sh
Selain itu, terdapat file:
- konfigurasi nginx:
adisblog
- cluster MySQL member:
cluster_bootstrap.sql
,cluster_member.sql
- ProxySQL member:
create_proxysql_user.sql
- ProxySQL init
proxy.sql
- kestrel http service
kestrel-adisblog.service
- mysql configurations
my103.cnf
,my104.cnf
,my105.cnf
Setiap command yang dijelaskan di atas terdapat di dalam file yang disebutkan, dan akan diprovision secara otomatis.
c. Proses instalasi webserver
- Install Nginx, .NET Core SDK & Runtime, NodeJS.
sudo apt install nginx -y
sudo ufw allow 'Nginx HTTP'
wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update -y
sudo apt-get install apt-transport-https -y
sudo apt-get update -y
sudo apt-get install dotnet-sdk-2.2 -y
wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update -y
sudo apt-get install apt-transport-https -y
sudo apt-get update -y
sudo apt-get install aspnetcore-runtime-2.2 -y
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get install nodejs -y
- Clone repo project
mkdir /home/vagrant/projects
cd /home/vagrant/projects
git clone https://github.com/adisazhar123/dotnet-core-reactredux-blog.git
cd /home/vagrant/projects/dotnet-core-reactredux-blog/src/App/Spa
- Install depedencies yang dibutuhkan project
dotnet restore /home/vagrant/projects/dotnet-core-reactredux-blog/src/App/Spa
npm install /home/vagrant/projects/dotnet-core-reactredux-blog/src/App/Spa/ClientApp
- Build project
sudo rm -r /home/vagrant/projects/dotnet-core-reactredux-blog/src/App/Spa/wwwroot/Storage
sudo ln -s /home/vagrant/projects/dotnet-core-reactredux-blog/src/App/Spa/Storage /home/vagrant/projects/dotnet-core-reactredux-blog/src/App/Spa/wwwroot
dotnet publish --configuration Release
mkdir /home/vagrant/projects/dotnet-core-reactredux-blog/src/App/Spa/bin/Release/netcoreapp2.2/publish/Storage
mkdir /home/vagrant/projects/dotnet-core-reactredux-blog/src/App/Spa/bin/Release/netcoreapp2.2/publish/Storage/Uploads
sudo chown www-data:www-data -R /home/vagrant/projects/dotnet-core-reactredux-blog/src/App/Spa/bin/Release/netcoreapp2.2/publish/Storage/Uploads
- Bikin symlink yang mengarah ke hasil build project. Ini akan digunakan oleh
systemd
untuk run service.
sudo mkdir /var/www/AdisBlog
sudo ln -s /home/vagrant/projects/dotnet-core-reactredux-blog/src/App/Spa/bin/Release/netcoreapp2.2/publish /var/www/AdisBlog
- Bikin konfigurasi Nginx. Nginx akan listen ke port 80, dan meneruskan ke Kestrel port 5000.
sudo cp /vagrant/adisblog /etc/nginx/sites-available
sudo ln -s /etc/nginx/sites-available/adisblog /etc/nginx/sites-enabled
sudo rm /etc/nginx/sites-enabled/default
Isi file Nginx:
server {
listen 80;
server_name 192.168.16.106;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
- Bikin service
systemd
. Systemd akan mengeksekusi fileAdisBlog.dll
yang merupakan hasil dari build project menggunakan/usr/bin/dotnet
. Hasil eksekusi command/usr/bin/dotnet AdisBlog.dll
akan menyalakan server Kestrel. Untuk menjalankan service tersebut bisa menggunakan commandsudo service kestrel-adisblog start
.
sudo cp /vagrant/kestrel-adisblog.service /etc/systemd/system
sudo systemctl enable kestrel-adisblog.service
sudo systemctl start kestrel-adisblog.service
Isi file kestrel-adisblog.service
:
[Unit]
Description=AdisBlog .NET Web API App & ReactJS running on Ubuntu
[Service]
WorkingDirectory=/var/www/AdisBlog/publish
ExecStart=/usr/bin/dotnet /var/www/AdisBlog/publish/AdisBlog.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
[Install]
WantedBy=multi-user.target
Agar kestrel-adisblog.service
dapat berjalan ketika server boot, jalankan command berikut:
sudo systemctl enable kestrel-adisblog.service
- Akses
192.168.16.106
melalui web browser.
Soal 2: Penggunaan basis data terdistribusi dalam aplikasi Aplikasi web yang digunakan adalah blog simple dikembangkan menggunakan framework ASP Net Core. Aplikasi web ini memiliki fitur: Login, Logout, Register, Bikin Post, Comment Post, Like Post dan Follow User.
Untuk melakukan konfigurasi aplikasi agar bisa terhubung dengan infrastruktur MySQL, adalah dengan cara mengubah connection string DB. Connection string DB pada aplikasi web ini terdapat pada class Startup.cs
dengan menambahkan statement ini di fungsi ConfigureServices
:
services.AddDbContext<BlogsDbContext>(options => options.UseMySql("Server=192.168.16.107;Database=blog;User=bloguser;Password=password;" ));
Connection string berisi credentials yang terdapat pada ProxySQL. ProxySQL secara otomatis akan me route query yang masuk ke 3 MySQL member yang telah di-set sebelumnya.
Setelah mengisi connection string, kita harus melakukan database migration. Database migration akan membuat table-table yang dibutuhkan. Untuk melakukan database migration dapat run command
/usr/bin/dotnet ef database update /home/vagrant/projects/dotnet-core-reactredux-blog/src/App/Spa
Web dapat diakses melalui 192.168.16.106
.
Soal 3: Simulasi fail-over
-
Dengan kondisi semua server jadi member ONLINE dalam group.
-
Matikan salah satu MySQL server (192.168.16.103) Member yang tergabung dalam group sebelum 192.168.16.103 dimatikan Member yang tergabung setelah 192.168.16.103 dimatikan
-
Menyalakan 192.168.16.103 Cek data pada 192.168.16.103 sebelum join group
Cek data pada 192.168.16.103 setelah join group
Simulasi fail-over menunjukkan ketika salah satu member keluar dari group atau mati, maka secara otomatis ProxySQL akan me route ke member yang masih active. ProxySQL dapat mengetahui kondisi MySQL server melalui monitoring yang sudah diregistrasi sebelumnya. Server yang sebelumnya mati, lalu join group akan mendapatkan data yang terbaru. Simulasi fail-over berhasil dilakukan.
File bash
yang digunakan untuk provisioning adalah:
- Database:
deployMySQL103.sh
,deployMySQL104.sh
,deployMySQL105.sh
- Database Load Balancer:
deployProxySQL.sh
- Webserver:
deployWebServer.sh
Selain itu, terdapat file:
- konfigurasi nginx:
adisblog
- cluster MySQL member:
cluster_bootstrap.sql
,cluster_member.sql
- ProxySQL member:
create_proxysql_user.sql
- ProxySQL init
proxy.sql
- kestrel http service
kestrel-adisblog.service
- mysql configurations
my103.cnf
,my104.cnf
,my105.cnf
Setiap command yang dijelaskan di atas terdapat di dalam file yang disebutkan, dan akan diprovision secara otomatis.