במשך השנים יצא לי להתעסק המון עם רפליקציה (Replication) של MySQL ופתרונות של איזון עומסים (Load Balancing) ואל-כשל (Failsafe) ל-MySQL (על שני האחרונים אסביר במאמר אחר). לאחרונה גם יצא לי להבין מכמה חברים שחסר תיעוד בעברית אז החלטתי לעשות מעשה ולכתוב מאמר קצר בנושא. במאמר זה אעשה סקירה קצרה על הפתרון ומדריך קצר כיצד להקים רפליקציה Master-Master כזו במספר צעדים פשוטים.

 ידע נדרש: MySQL ועוד קצת MySQL.ישנם שני סוגי רפליקציה של MySQL. הראשון הינו פשוט והוא מכונה Master-Slave. סוג זה של רפליקציה מאפשר לכתוב לבסיס נתונים אחד ולקרוא מבסיס נתונים אחר. פתרון זה מאפשר לחלק את העומסים בין הקריאות לכתיבות ולסנכרן בין שתיהם, מה-Master, שהוא הבסיס נתונים האקטיבי (Active Database), אל ה-Slave, שהוא הבסיס נתונים הפסיבי (Passive Database). הסנכרון מתבצע בצורה בינארית ובגלל זה יעילות העדכון והמהירות שלו. ד"א, בסוגריים רשמתי את המינוחים בעולמות הרפליקציה של Oracle ו-PostgreSQL.

הסוג השני של רפליקציה הינו Master-Master. במקרה זה אין Slave וכל שינוי מתעדכן בצורה אוטומטית בבסיס נתונים האחר. למעשה, בפתרון הזה כל בסיס נתונים מדמה שהוא ה-Master של השני ולהיפך - כל בסיס נתונים מדמה שהוא ה-Slave של השני. כך כל שינוי לאחד מהבסיסי נתונים יעבור לשני בצורה הדדית. אם אתם שואלים מה קורה כאשר מבצעים פעולת הוספה בו-זמנית על אותה טבלה שיש לה שדה AUTO INCREMENT, תקבלו תשובות בהמשך (רמז מקדים: מסומן בבולט).

רקע

קונפיגורציה

דבר ראשון קצת מידע על הסביבה:

  • המסטר הראשון server1 עם IP שמספרו: 192.168.0.100.
  • המסטר השני יקרא server2 עם IP שמספרו 192.168.0.110.
  • הבסיס נתונים שיעשה בו שימוש הינו db_mm.

איך זה עובד

כל אחד השרתים ישתמש בלוג בינארי (Binary Log) להעביר את המידע לשרת השני. הלוג בינארי מכיל "אירועים" שהתרחשו שמתארים את השינויים שבוצעו לבסיס נתונים כגון הוספת שורות לטבלה, יצירת טבלה ועוד. כל שינוי שיבוצע באחד מהבסיסי נתונים ישלח באמצעות לוג זה לשרת השני וזה מבוצע בצורה הדדית.

לעבודה

Server1

ניכנס ל-server1 ונקנפג ב-my.cnf את ההגדרות הבאות:

log-bin = /var/log/mysql/mysql-bin.log
server-id=1
binlog-do-db = db_mm
replicate-do-db = db_mm
replicate-same-server-id = 0
auto-increment-increment = 2
auto-increment-offset = 1
relay-log = /var/log/mysql/slave-relay.log
relay-log-index = /var/log/mysql/slave-relay-log.index
expire_logs_days = 10
max_binlog_size = 500M

בהגדרות לעיל הגדרנו את server1 כ-Slave. עכשיו נעבור ל-MySQL ונגדיר את ההרשאות של server1 כ-slave. אתחלו את ה-service של MySQL וכנסו ל-MySQL console עם יוזר root ולהריץ את הפקודות הבאות:

CREATE DATABASE db_mm;

GRANT REPLICATION SLAVE ON *.* TO 'user1'@'%' IDENTIFIED BY 'verystrongpassword!';
FLUSH PRIVILEGES;

 

לאחר מכן ננעל את הטבלאות שלא יתבצע שינויים ונשתמש בסטטוס של ה-Slave בשביל הגדרה בשרת השני (server2)

FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;

+------------------+----------+----------------+------------------+
| File | POSITION | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+----------------+------------------+
| mysql-BIN.000004 | 355 | db_mm | |
+------------------+----------+----------------+------------------+

SERVER2

ניכנס ל-server2 ונעדכן את ה-my.cnf שלו בצורה הבאה:

server-id = 2
replicate-same-server-id = 0
auto-increment-increment = 2
auto-increment-offset = 2
replicate-do-db = db_mm
binlog-do-db = db_mm
log-bin= /var/log/mysql/mysql-bin.log
relay-log = /var/log/mysql/slave-relay.log
relay-log-index = /var/log/mysql/slave-relay-log.index
expire_logs_days = 10
max_binlog_size = 500M

נאתחל את שרת ה-MySQL ועכשיו server2 מוגדר כ-Slave.
עכשיו נצטרך לשפוך את המידע מה-DB ב-server1 ל-server2. אם זהו בסיס נתונים חדש צור אותו, אם זה בסיס נתונים קיים, פשוט בצע dump מ-server1 והעבר אותו ל-server2 בשלב זה.

נגדיר את server2 כ-Slave של server1:

GRANT REPLICATION SLAVE ON *.* TO 'user2'@'%' IDENTIFIED BY 'verystrongpassword!';

FLUSH PRIVILEGES;

עכשיו נצטרך להגדיר את server1 כ-Master של server2. ניכנס ל-MySQL console ב-server2 ונריץ את הפקודות הבאות:

STOP SLAVE;
CHANGE MASTER TO MASTER_HOST='192.168.1.100',
MASTER_USER='user1',
MASTER_PASSWORD='verystrongpassword!',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000004',
MASTER_LOG_POS=355;
START SLAVE;

שימו לב כי פרטי הפקודה CHANGE MASTER נלקחו מתוך הפקודות שביצענו ב-server1 קודם לכן.

נוכל לבדוק עכשיו מה מצב ההגדרה של ה-Slave ב-server2:

SHOW SLAVE STATUS\G
...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...

יש לוודא שקיבלתם את הארגומנטים הנ"ל עם הערך Yes. במידה והם מוגדרים כ-No. ישנה בעית תקשורת בין השרתים.

עכשיו נעשה זאת להיפך וניקח את פרטי ה-Master של server2 אל server1:

SHOW MASTER STATUS;
+------------------+----------+---------------+------------------+
| File | POSITION | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+---------------+------------------+
| mysql-BIN.000002 | 106 | db_mm |                                  |
+------------------+----------+---------------+------------------+

חזרה ל-SERVER1

הראינו את ה-MASTER STATUS של server2 כדי להגדיר אותו להיות ה-Master של server1. אז בואו נחזור ל-server1 נריץ את הפקודות הבאות ב-MySQL console:

UNLOCK TABLES;
RESET SLAVE;
STOP SLAVE;
CHANGE MASTER TO MASTER_HOST='192.168.0.110',
MASTER_USER='user2',
MASTER_PASSWORD='verystrongpassword!',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000002',
MASTER_LOG_POS=106;

START SLAVE;

ושוב נבדוק SLAVE STATUS ב-server1 אם הוא הוגדר כהלכה:

SHOW SLAVE STATUS\G
...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...

שוב יש לוודא שיש Yes בשני הארגומנטים הנ"ל.

שארית דבר

ולשאלתכם איך בדיוק מתמודדים עם יצירת שורה בו זמנית בטבלה עם AUTO_INCREMENT פשוט שימו לב לארגומנטים שמובלטים ב-my.cnf לעיל:

replicate-same-server-id = 0
auto-increment-increment = 2
auto-increment-offset = 1 or 2 (depend on server id)

מה שאלה מגדירים למעשה הם הקפיצות של שדות ה-Auto Increment כך שהקפיצה תהיה ב-2 בכל פעם (auto-increment-increment) במקום ב-1 בברירת מחדל, ובהתאם הוא נותן לכל server משתנה offset (במקרה שלנו 1 ל-server1 ו-2 ל-server2) וכך מתמודדים עם בעיה של collisions בשדות אלו.

אם תרצו להגדיר אך ורק Master-Slave נצטרך פשוט להגדיר רק בצד אחד Master ללא Slave ובצד השני להגדיר אך ורק Slave ללא הגדרה של Master. במילים אחרות יש לבצע אך ורק CHANGE MASTER TO בשרת אחד ובשרת השני יש לבצע אך ורק GRANT REPLICATION SLAVE.

מקווה שנהניתם. אנא תנו בתגובות אם נעזרתם או אם יש לכם שאלות.

בחלק הבא אסביר איך עושים חלוקת עומסים (Load Balancing) ואל-כשל (Failsafe) של רפליקציה זו.

הוספת תגובה

0
  • לא נמצאו תגובות