การจำลองแบบ Master-Slave ใช้เพื่อแก้ปัญหาต่าง ๆ เกี่ยวกับประสิทธิภาพการทำงาน รองรับการสำรองข้อมูลของฐานข้อมูลที่แตกต่างกันและเป็นส่วนหนึ่งของโซลูชันขนาดใหญ่เพื่อลดความล้มเหลวของระบบ ช่วยให้สามารถจำลองข้อมูลจากเซิร์ฟเวอร์ฐานข้อมูล (master) ไปยังเซิร์ฟเวอร์ฐานข้อมูลอย่างน้อยหนึ่งเซิร์ฟเวอร์ (slave) master ทำการ log การอัปเดตซึ่งจะส่งผลไปยัง slave ซึ่ง slave จะแสดงข้อความที่ระบุว่าได้รับการอัปเดตสำเร็จซึ่งอนุญาตให้ส่งการอัปเดตในภายหลัง การจำลองแบบ Master-Slave สามารถเป็นแบบซิงโครนัสหรืออะซิงโครนัสก็ได้ ความแตกต่างเป็นเพียงช่วงเวลาของการเผยแพร่การเปลี่ยนแปลง หากการเปลี่ยนแปลงเกิดขึ้นกับ master และ slave ในเวลาเดียวกันจะเป็นแบบซิงโครนัส หากการเปลี่ยนแปลงถูกจัดคิวและเขียนในภายหลังจะเป็นแบบอะซิงโครนัส
เป้าหมายการใช้งานสำหรับการจำลองแบบในฐานข้อมูล MariaDB และ MySQL ประกอบด้วย:
- Scale-out โซลูชัน
- ความปลอดภัยของข้อมูล
- การวิเคราะห์
- การกระจายข้อมูลทางไกล
คุณสามารถใช้การจำลองแบบดังกล่าวและใช้ประโยชน์จากมันได้อย่างไร
- Backups: เพื่อใช้การจำลองแบบเป็นโซลูชันสำรองจำลองข้อมูลจาก master ไปยัง slave แล้วสำรองข้อมูล slave ซึ่ง slave สามารถหยุดชั่วคราวและปิดเครื่องได้โดยไม่ส่งผลกระทบต่อการทำงานของ master เพื่อให้คุณสามารถสร้าง snapshot ของข้อมูล “live” ที่มีประสิทธิภาพได้มิฉะนั้นจะต้องปิดตัว master
- Scale-out: คุณสามารถใช้การจำลองแบบเป็น scale-out โซลูชัน นั่นคือที่ที่คุณต้องการแบ่งภาระงานคิวรี่ฐานข้อมูลจำนวนมากในเซิร์ฟเวอร์ฐานข้อมูลหลายตัวภายในข้อจำกัดที่สมเหตุสมผล เนื่องจากการจำลองแบบทำงานจากการแจกจ่าย master หนึ่งไปยัง slave หนึ่งตัวขึ้นไป ใช้สำหรับ scale-out จะทำงานได้ดีที่สุดใน Env ที่คุณมีจำนวนการอ่านสูง และการเขียน / อัปเดตน้อย
- Spreading the load: อาจมีสถานการณ์เมื่อคุณมี master เดียวและต้องการจำลองฐานข้อมูลที่แตกต่างกันไปยัง slave ที่แตกต่างกัน ตัวอย่างเช่นคุณอาจต้องการกระจายข้อมูลการขายไปยังแผนกที่จำเป็นเท่านั้นเพื่อช่วยกระจายภาระระหว่างการวิเคราะห์ข้อมูล
- Increasing the performance: เมื่อจำนวน slave ที่เชื่อมต่อกับ master เพิ่มขึ้น ภาระงานนั้นแม้ว่าจะน้อยที่สุด แต่ก็เพิ่มขึ้นเช่นกันเนื่องจาก slave แต่ละตัวใช้การเชื่อมต่อ client กับ master เนื่องจาก slave แต่ละตัวต้องได้รับสำเนาทั้งหมดของไบนารี log ภาระงานของเครือข่ายบน master อาจเพิ่มขึ้นและสร้างปัญหาคอขวด หากคุณใช้ slave จำนวนมากที่เชื่อมต่อกับ master หนึ่งตัวและ master ตัวนั้นก็กำลังดำเนินการตามคำขอ (เช่น เป็นส่วนหนึ่งของ scale-out โซลูชัน) คุณอาจต้องการปรับปรุงประสิทธิภาพของกระบวนการจำลองแบบ วิธีหนึ่งในการปรับปรุงประสิทธิภาพของกระบวนการจำลองแบบคือการสร้างโครงสร้างการจำลองแบบที่ลึกขึ้น ซึ่งช่วยให้ master สามารถจำลองเป็น slave เพียงตัวเดียวและสำหรับ slave ที่เหลือสามารถเชื่อมต่อกับ slave ตัวหลักสำหรับข้อกำหนดในการจำลองแบบได้
- Failover alleviating: คุณสามารถตั้งค่า master และ slave (หรือ slave หลายตัว) และเขียนสคริปต์ที่คอยตรวจสอบ master เพื่อตรวจสอบว่ามันขึ้นหรือไม่ จากนั้นสั่งให้แอปพลิเคชันและ slave เปลี่ยน master ในกรณีที่เกิดความล้มเหลว
- Security: คุณสามารถใช้ SSL เพื่อเข้ารหัสการถ่ายโอนไบนารี log ที่จำเป็นในระหว่างการจำลองแบบ แต่ทั้ง master และ slave ต้องรองรับการเชื่อมต่อเครือข่าย SSL หากโฮสต์ใดไม่รองรับการเชื่อมต่อ SSL การจำลองแบบผ่านการเชื่อมต่อ SSL จะไม่สามารถทำได้ การตั้งค่าการจำลองแบบโดยใช้การเชื่อมต่อ SSL คล้ายกับการตั้งค่าเซิร์ฟเวอร์และไคลเอนต์โดยใช้ SSL คุณต้องได้รับ (หรือสร้าง) ใบรับรองความปลอดภัยที่เหมาะสมซึ่งคุณสามารถใช้ได้กับ master และใบรับรองที่คล้ายกัน (จากผู้ออกใบรับรองเดียวกัน) ใน slave แต่ละตัว
ตอนนี้เรามาดูตัวอย่างง่าย ๆ ของวิธีกำหนดค่าการจำลองแบบ Master-Slave บน Ruk-Com PaaS กัน
คุณสามารถตั้งค่าคลัสเตอร์ฐานข้อมูลได้สองวิธี:
- automatically (ผ่านวิดเจ็ต one-click)
- manually (ทำตามคำแนะนำทีละขั้นตอน)
การติดตั้ง One-Click
คุณสามารถรับคลัสเตอร์ฐานข้อมูล MySQL หรือ MariaDB ที่มีประเภทการจำลองแบบที่ต้องการ (รวมถึง master-slave one) และทำงานภายในไม่กี่นาทีโดยใช้วิดเจ็ตติดตั้ง Ruk-Com one-click
ขั้นตอนนี้ง่ายมากเพียงระบุอีเมลของคุณและยืนยันผ่านการแจ้งเตือน อ่านบทความ MariaDB / MySQL Auto-Clustering สำหรับข้อมูลเพิ่มเติมเกี่ยวกับแพ็คเกจที่ติดตั้งและตัวเลือกการปรับแต่งที่พร้อมใช้งาน
การติดตั้งด้วยตนเอง
หากคุณต้องการกำหนดค่าการจำลองแบบ Master-Slave ด้วยตนเองเพื่อรับตัวจำลอง Slave เพิ่มเติมหรือระบุการกำหนดค่าที่กำหนดเองบางอย่าง โปรดปฏิบัติตามคำแนะนำด้านล่าง
การสร้าง Env
เคล็ดลับ : คำแนะนำด้านล่างนี้เหมาะสำหรับเซิร์ฟเวอร์ฐานข้อมูล MySQL และ MariaDB อย่างยิ่ง
ก่อนอื่นต้องสร้าง Env 2 ตัวใน Ruk-Com สำหรับฐานข้อมูล master และฐานข้อมูล slave
- ล็อกอินเข้าสู่แดชบอร์ด Ruk-Com แล้วคลิกปุ่ม New Environment
- ใน Env Topology wizard ให้เลือก MariaDB (หรือ MySQL) เป็นฐานข้อมูลที่คุณต้องการใช้ ตั้งค่าลิมิต cloudlet และพิมพ์ชื่อของ Env ตัวแรกของคุณตัวอย่างเช่น masterbase
รอสักครู่เพื่อให้ Env ถูกสร้างขึ้น - ในทำนองเดียวกันให้สร้าง Env ขึ้นมาใหม่ด้วย MariaDB หรือเพียงแค่ทำการโคลน มาตั้งชื่อว่า slavebase จะอยู่ใน hardnode อื่นซึ่งมีความปลอดภัยและเชื่อถือได้มากขึ้นสำหรับการจัดเก็บข้อมูล
ตอนนี้คุณมี Env 2 ตัวที่เหมือนกันกับทั้งสองฐานข้อมูล
กำหนดค่าฐานข้อมูล Master
มากำหนดค่า master base กันเลย
- คลิกปุ่ม Config สำหรับฐานข้อมูล master
- ไปที่ไฟล์ my.cnf และเพิ่มคุณสมบัติต่อไปนี้ตามที่แสดงด้านล่าง:
server-id = 1
log-bin = mysql-bin
binlog-format = mixed
เราใช้รูปแบบ “mixed” binlog (binlog-format = mixed) เพื่อให้สามารถจำลองการทำงานด้วย foreign keys ได้
หมายเหตุ : อย่าใช้รูปแบบ “statement” binlog มิฉะนั้นคุณจะได้รับข้อผิดพลาดในภายหลัง!
- Save การเปลี่ยนแปลงและ Restart MariaDB เพื่อใช้พารามิเตอร์ที่กำหนดค่าใหม่
- คลิกปุ่ม Open in Browser สำหรับ MariaDB, Ruk-Com จะส่งอีเมลถึงคุณพร้อมข้อมูลรับรองไปยังฐานข้อมูลเพื่อเข้าสู่ระบบโดยใช้ข้อมูลรับรองเหล่านี้
- ไปที่แท็บ User accounts แล้วคลิก Add user account
- ระบุ name และ password สำหรับผู้ใช้การจำลองแบบ slave
ตอนนี้เลื่อนลงและทำติ๊กเครื่องหมายที่ replication client และ replication slave ตรงส่วนของ administration privileges
คลิก Go ที่อยู่ด้านล่างของหน้า
- สลับไปที่แท็บ Status เพื่อให้แน่ใจว่าการจำลองถูกกำหนดค่าอย่างถูกต้อง
ให้ความสนใจกับค่า Log File และ Position เนื่องจากจะต้องใช้ในภายหลังเพื่อตั้งค่าฐานข้อมูล Slave
กำหนดค่าฐานข้อมูล Slave
กลับไปที่แดชบอร์ด Ruk-Com และกำหนดค่าฐานข้อมูล Slave
- คลิกปุ่ม Config สำหรับ Slavebase Env
- ไปที่ไฟล์ my.cnf และเพิ่มสตริงต่อไปนี้:
server-id = 2
slave-skip-errors = all
เราอนุญาตให้ slave base ข้ามข้อผิดพลาดทั้งหมดจาก master (slave-skip-errors = all) เพื่อไม่ให้หยุดการทำงานของ normal slave ในกรณีที่เกิดข้อผิดพลาดบน master base
หมายเหตุ : ไม่แนะนำให้ใช้การข้ามนี้ในระหว่างขั้นตอนการพัฒนาเนื่องจากช่วยในการค้นหาและแก้ไขข้อบกพร่อง อย่างไรก็ตามในการใช้งานจริง (เมื่อโค้ดของคุณได้รับการทดสอบแล้ว) จะช่วยหลีกเลี่ยงการไม่ซิงโครไนซ์สำหรับปัญหาเล็กน้อยใน master node
- จากนั้นเปิดไฟล์ /etc/phpMyAdmin/config.inc.php และใส่ต่อท้ายด้วยโค้ดถัดไป:
$cfg['AllowArbitraryServer'] = true;
- Save การเปลี่ยนแปลงและ Restart เซิร์ฟเวอร์ฐานข้อมูล slave เพื่อใช้พารามิเตอร์คอนฟิกูเรชันใหม่
- มากำหนดค่าเซิร์ฟเวอร์ฐานข้อมูล slave ผ่าน Web SSH client แบบบิวท์อิน เชื่อมต่อกับฐานข้อมูลของคุณโดยใช้ข้อมูลประจำตัวจากอีเมลที่ได้รับหลังจากการสร้างโหนด
mysql -u root -p
- ให้รายละเอียดการจำลองแบบของ master
CHANGE MASTER TO
MASTER_HOST='node275500-masterbase.jelastic.com',
MASTER_USER='slave',
MASTER_PASSWORD='passw0rd',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=853;
อย่าลืมแทนที่ค่าของตัวเลือกในตัวอย่างด้านบนด้วยข้อมูลที่ถูกต้อง:
- MASTER_HOST – URL หรือ IP การจำลองแบบของ master
- MASTER_USER – ผู้ใช้การจำลองแบบ
- MASTER_PASSWORD – รหัสผ่านของผู้ใช้การจำลอง
- MASTER_LOG_FILE – ไฟล์ log ของ master (ดูขั้นตอนสุดท้ายของส่วนการกำหนดค่า master)
- MASTER_LOG_POS – ตำแหน่ง log ของ master (ดูขั้นตอนสุดท้ายของส่วนการกำหนดค่า master)
- ตอนนี้คุณสามารถเริ่มการจำลองแบบ slave ด้วยคำสั่งที่เหมาะสม:
start slave;
เคล็ดลับ : หากคุณต้องการให้แน่ใจว่าทุกอย่างได้รับการกำหนดค่าอย่างถูกต้องให้เข้าสู่ระบบในส่วนของฐานข้อมูล slave สำหรับแอดมิน และไปที่แท็บ Status
ตรวจสอบผลลัพธ์
เราต้องตรวจสอบให้แน่ใจว่าการจำลองแบบ master-slave ใช้งานได้กับฐานข้อมูลของเราแล้ว
- มาสร้างฐานข้อมูลใหม่ (เช่น Ruk-Com) ใน master base ของเรา
- ไปที่ slave base และคุณจะเห็นว่าฐานข้อมูลใหม่ถูกจำลองสำเร็จแล้ว
การเชื่อมต่อกับ Master-Slave
นี่คือ 2 ตัวอย่างของการเชื่อมต่อกับฐานข้อมูล master และฐานข้อมูล slave จากแอปพลิเคชัน Java และ PHP
- ตัวอย่างเช่นคุณสามารถดูโค้ดของแอปพลิเคชัน Java ของคุณซึ่งเชื่อมต่อกับฐานข้อมูล master และฐานข้อมูล slave Database_config.cfg:
master_host=jdbc:mysql://mariadb-master-host/mysql
master_username=root
master_password=abcABC123
slave_host=jdbc:mysql://mariadb-slave-host/mysql
slave_username=root
slave_password=abcABC123
driver=com.mysql.jdbc.Driver
Dbmanager.java:
package com.jelastic.test;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DbManager {
private final static String createDatabase = "CREATE SCHEMA IF NOT EXISTS jelastic";
private final static String showDatabases = "SHOW DATABASES";
public Connection createMasterConnection() throws IOException, ClassNotFoundException, SQLException {
Connection masterConnection;
Properties prop = new Properties();
prop.load(new FileInputStream(System.getProperty("user.home") + "/database_config.cfg"));
String master_host = prop.getProperty("master_host").toString();
String master_username = prop.getProperty("master_username").toString();
String master_password = prop.getProperty("master_password").toString();
String driver = prop.getProperty("driver").toString();
Class.forName(driver);
masterConnection = DriverManager.getConnection(master_host, master_username, master_password);
return masterConnection;
}
public Connection createSlaveConnection() throws IOException, ClassNotFoundException, SQLException {
Connection slaveConnection;
Properties prop = new Properties();
prop.load(new FileInputStream(System.getProperty("user.home") + "/database_config.cfg"));
String slave_host = prop.getProperty("slave_host").toString();
String slave_username = prop.getProperty("slave_username").toString();
String slave_password = prop.getProperty("slave_password").toString();
String driver = prop.getProperty("driver").toString();
Class.forName(driver);
slaveConnection = DriverManager.getConnection(slave_host, slave_username, slave_password);
return slaveConnection;
}
public boolean runSqlStatementOnMaster() {
boolean execute = false;
Statement statement = null;
try {
statement = createMasterConnection().createStatement();
execute = statement.execute(createDatabase);
} catch (IOException ex) {
Logger.getLogger(DbManager.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(DbManager.class.getName()).log(Level.SEVERE, null, ex);
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return execute;
}
public List<String> runSqlStatementOnSlave() {
List<String> stringList = new ArrayList<String>();
Statement statement = null;
ResultSet resultSet = null;
try {
statement = createSlaveConnection().createStatement();
resultSet = statement.executeQuery(showDatabases);
while (resultSet.next()) {
stringList.add(resultSet.getString(1));
}
} catch (IOException ex) {
Logger.getLogger(DbManager.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(DbManager.class.getName()).log(Level.SEVERE, null, ex);
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return stringList;
}
}
- การเชื่อมต่อกับฐานข้อมูล master และฐานข้อมูล slave สำหรับแอปพลิเคชัน PHP
<?php
/* Master settings */
$master_server = "xx.xxx.x.xx";
$master_username = "root";
$master_password = "abcABC123";
/* Slave settings */
$slave_server = "xx.xxx.x.xx";
$slave_username = "root";
$slave_password = "abcABC123";
$link_to_master = mysqli_connect(
$master_server,
$master_username,
$master_password,
'mysql');
if (!$link_to_master) {
printf("Unable to connect master database server. Error: %s\n", mysqli_connect_error());
exit;
}
$link_to_slave = mysqli_connect(
$slave_server,
$slave_username,
$slave_password,
'mysql');
if (!$link_to_slave) {
printf("Unable to connect slave database server. Error: %s\n", mysqli_connect_error());
exit;
}
print("
Creating database with name Jelastic on Master node ");
$result = mysqli_query($link_to_master, 'CREATE DATABASE JelasticX');
sleep (3);
print("
Checking if created database was replciated to slave ");
if ($result = mysqli_query($link_to_slave, 'SHOW DATABASES LIKE "JelasticX"')) {
$result_text = mysqli_fetch_array($result);
print ("
Replicated database is ".$result_text[0]);
}
mysqli_close($link_to_master);
mysqli_close($link_to_slave);
?>
ตอนนี้คุณมีการจำลองฐานข้อมูลของคุณเองในระบบคลาวด์แล้ว ขอให้สนุกไปกับมัน!