חלוקת עומסים ואל-כשל של MySQL

לאחר החלק הראשון בסדרה בנושא רפליקציה של MySQL, חלק זה לוקח צעד אחד קדימה את האופטימיזציה ושיפור הביצועים של MySQL ומסביר על חלוקת עומסים, אל כשל והתאוששות מנפילה.
הרכיב שבו נשתמש לחלוקת עומסים הינו MySQL-Proxy. רכיב זה משמש בעיקר לחלוקת עומסים בארכיטקטורת Master-Master או Master-Slave, אך לא רק.

MySQL Proxy הינו רכיב פשוט אך מתוחכם של MySQL, שיושב בין הקליינט לשרת(ים) המסוגל לנטר, לנתח, ולחלק את התקשורת של MySQL לכמה שרתים שונים. מכיוון שהרכיב גמיש מאוד ניתן באמצעותו:

  • חלוקת עומסים
  • אל-כשל
  • ניתוח שאילתות
  • עדכון וסינון שאילתות
  • ועוד הרבה (מכיוון שהרכיב מבוסס שפת Lua ניתן בקלות להרחיבו).
מכיוון שאנחנו בהמשך למאמר המקורי שבו הוגדר רפליקציה Master-Master אנחנו נראה כיצד הרכיב משתלב בארכיטקורה זו. הרכיב עצמו יותקן על שרת נפרד משני שרתי ה-Master שהוגדרו במדריך הקודם. שם השרת הינו mango וה-IP שלו יהיה 192.168.0.200.
שימו לב כי בניגוד למקרה שלנו, ניתן אף להתקין את הרכיב גם על שרת שיושב עליו MySQL. הפרוקסי פשוט יפעל על פורט אחר.
נתקין את הרכיב בקלות (רוב ההפצות מכילות אותו כחבילה רגילה):
# on gentoo
emerge mysql-proxy
# on fedora
rpm -i mysql-proxy
ניתן להפעיל את הפרוקסי ישירות משורת הפקודה אבל ברוב ההפצות הוא מגיע כ-service ואנו נשתמש ב-service זה (הרבה יותר נוח).
נצטרך לערוך את קובץ ההגדרות שלו (mysql-proxy.cnf) שיושב בד"כ היכן שיושב קובץ ההגדרות של MySQL (שהוא my.cnf):

# MySQL Proxy's configuration file (mysql-proxy.cnf)
# This file must be 0660 or more restrictive
# otherwise mysql-proxy will refuse to load
[mysql-proxy]
keepalive = true
log-backtrace-on-crash = true
plugins = proxy
proxy-address = :4040
proxy-backend-addresses = 192.168.0.100:3306,192.168.0.110:3306
proxy-read-only-backend-addresses=192.168.0.110:3306,192.168.0.100:3306
proxy-fix-bug-25371 = false
proxy-skip-profiling = false
log-level = message
log-file = /var/log/mysql/mysql-proxy.log
pid-file = /var/run/mysql-proxy.pid

שימו לב למספר משתנים:
  1. הראשון הינו proxy-backend-addresses. משתנה זה מגדיר את שרתי ה-Master שביניהם ינותבו שאילתות העדכון (insert, delete וכו').
  2. מכיוון שבארכיטקטורה בדוגמא שלנו לא מעורב שרת Slave טהור (שאינו גם Master), הגדרנו את שרתי ה-Master כשרתי ה-Slave בסדר הפוך (proxy-read-only-backend-addresses).
  3. רמת תיעוד לוג – ניתן להגדיר רמת התיעוד בלוג של הרכיב. במידה וישנן תקלות נוכל להגדיר תיעוד לוג ברמת debug.
  4. proxy-address – באיזה פורט יעבוד הפרוקסי.
  5. keepalive מגדיר שאם תהיה נפילה לרכיב עצמו הוא יבצע התאוששות אוטומטית.
נפעיל את הרכיב באמצעות הפעלת הרכיב ונגדיר אותו שיפעל בעליית המערכת (בהפצת ג'נטו):
/etc/init.d/mysql-proxy start
rc-update add mysql-proxy default
עכשיו נגדיר לכל אפליקציה שתשתמש בשרת הפרוקסי (192.168.0.200 במקרה שלנו) עם הפורט המתאים (4040) במקום אחד מהמסטרים שהיו מוגדרים עד עתה.

אז מה הפתרון שקיבלנו?

דבר ראשון, ניתן בקלות להגדיר רפליקציה ללא שינוי קוד של אפליקציה. חוץ מזה, בטח שאלתם מה עוד מגניב??

חלוקת עומסים

דבר ראשון, כל אפליקציה שתפנה לשרת הפרוקסי תופנה לשרת ה-Master הפחות עמוס. החלוקה מתבצעת בהתאם ל-round-robin. לדוגמא אם שרת x פונה לפרוקסי הוא יופנה ל-server1, שרת y פונה לפרוקסי הוא יופנה ל-server2 וכך הלאה. שימו לב כי הרכיב יודע מתי הפניה מסתיימת בכל אחד מפניות, ולכן הוא גם יודע אם אחד השרתים עמוסים בפניות כבדות, זאת כדי להפנות לשרת הפחות עמוס.

אל-כשל

אז חלוקת עומסים יש, מה לגבי אל-כשל? MySQL-Proxy יודע לזהות אוטומטית אם אחד מהשרתים לא זמין (נפל מאיזושהי סיבה), ולנתב את כל השאילתות לשרת שעדיין "נושם". כך נוכל לטפל בינתיים בשרת שנפל בלי Downtime של שנייה אחת. ה-Master שעדיין "חי" יוכל להתעדכן בלי שהאפליקציות יודעות בכלל שהיתה נפילה לאחד השרתים.

התאוששות

יש גם אל-כשל… מגניב! איך מתאוששים ומסנכרנים שרת שנפל??
ופה טמון כל היופי של Master-Master, מכיוון שכל שרת מעדכן את השני בצורה רציפה, ברגע שהשרת שנפל מתאושש, הוא "יתשאל" את השרת שעדיין "חי" מה המצב שלו ואם יש עדכונים מהרגע שהוא נפל (איך בדיוק? קראו על לוג בינארי בחלק הקודם). השרת המתאושש יסתנכרן אוטומטית ללא התערבות המשתמש למצב מדויק שבו נמצא השרת שלא נפל וכך כל הארכיטקטורה תמשיך לעבוד ללא התערבות חיצונית (חוץ מהתאוששות עצמה).
במידה ומדובר ב-Master-Slave ניתן להשיג התאוששות כזו רק במידה ואחד הסלאבים (Slaves) נפל.  במידה וישנו Master יחיד והוא נפל המערכת לא תוכל להתעדכן אלא לבצע שאילתות קריאה בלבד עד שה-Master יתאושש.

שארית דבר

למעשה, השרידות של ארכיטקטורה זו – Master-Master replication עם MySQL מאחוריהם – הינה בעלת שרידות גבוהה מאוד (99%). שרידות גבוהה מזו מושגת אך ורק ע"י MySQL Cluster והיא נדרשת רק כאשר מדובר על נפחים הרבה יותר גדולים. כמה גדולים? כאשר מדובר על טארהבייטים (פייסבוק, גוגל ועוד משתמשים בקלסטרים).
בכל אופן, MySQL Cluster יוסבר במאמר הבא בסדרה.

אל תשכחו לתת בתגובות :-)

8 תגובות על הפוסט “חלוקת עומסים ואל-כשל של MySQL

  1. פינגבאק: רפליקציה של MySQL | oc666 zone

  2. נותן בתגובות!

    MySQL Proxy התחיל לפני כארבע שנים בהבטחה גדולה ובקול תרועה. למרבה הצער הוא אינו מספק את הסחורה. הוא איטי ולא יציב, ולא עובדים עליו בקצב מספק.
    באופן אישי מעולם לא השתמשתי בו. לפני מספר שנים לקוח שלי השתמש בו והתאכזב מאוד. זה אמנם היה מזמן, אבל המצב היום לא השתנה:
    אף אחד לא משתמש ב-MySQL Proxy בתור כלי HA.
    כמובן ש"אף אחד" זה קצת קיצוני לומר, אבל במהות זה נכון. כבר שנים שלא שמעתי שממש מנסים אותו. לעולם אין מרצים עליו. אין מי שבא ומספר "זה הכל שאתו אני עובד". אין עליו מאמרים. אין מידע. פשוט לא קורה אתו דבר.
    בעצם, רק מי שמשתמש ב-enterprise monitor מתקין אותו (או גרסה שונה שלו, ליתר דיוק), לצורך בקרה על שאילתות. אבל לא ל-HA. וגם לא ל-load balancing.

    "שרידות גבוהה מזו מושגת אך ורק ע"י MySQL Cluster והיא נדרשת רק כאשר מדובר על נפחים הרבה יותר גדולים. כמה גדולים? כאשר מדובר על טארהבייטים (פייסבוק, גוגל ועוד משתמשים בקלסטרים)."

    שתי הערות חשובות מאוד, משום שהפסקה הזו מטעה:
    - יש ויש כלים אחרים שנותנים שרידות דומה או יותר גבוהה. Heartbeat, DRBD, Galera, MHA
    - MySQL Cluster בנפחים גדולים? בהצלחה. אין כזו חיה. פייסבוק וגוגל אינם משתמשים בקלסטרים אלא ברפליקציה (מאיפה המידע המוטעה?)
    Cluster אמור לעבוד במגבלות זכרון פיזי. יותר מכמה עשרות GB זו קונפיגורציה בעייתית מאוד.
    Cluster, כמו Proxy, הם שמות שקל מאוד להתרשם מהם ולהתלהב, אך המציאות ממש לא דומה.

  3. הי, שלומי
    תודה רבה על הביקורת.
    MySQL Proxy הינו מוצר טוב ביותר. אף-על-פי-כן, כמובן שאם החבר'ה של MySQL משפרים אותו, בגלל היכרותם עם MySQL יש להם יתרון. אבל, מכיוון ש-MySQL הינו מוצר פתוח, קל לתחזק מוצרים נלווים אליו כמו MySQL-Proxy.
    את הפרוקסי התקנתי לאחרונה על ארבע סביבות שונות (עם מסטר-סלייב ומסטר-מסטר) לכן החלטתי לכתוב עליו. עד עתה (במשך יותר משנה) לא היו תקלות (אבל בטח מחר תהיה אחת :)
    בקשר לפייסבוק, ישנה הרצאה של אחד המהנדסים בפייסבוק בנושא. אמצא את ההרצאה ואפרסם אותה.

    נ.ב.
    שלומי היתה לך אחלה הרצאה באוגוסט פינגווין ולמדתי ממנה הרבה…

  4. היי,
    תודה רבה. אתה זה שהשתעל כל הזמן? (סתם, סתם)
    אני שמח לשמוע ש-proxy עובד לך יפה. זה מעניין, משום שאתה הראשון מזה שנים שאני שומע שעובד איתו.

    לגבי פייסבוק – לצערי אין כאן טעות. פייסבוק עובדים על רפליקציה רגילה, sharded. הם אינם עובדים עם mysql cluster. לא לנתונים הגדולים, על כל פנים. לא ידוע לי שהם בכלל עובדים עם cluster, אתפלא אם כן – הנפשות הפועלות שם מעולם לא הזכירו את זה.
    cluster הוא מוצר נישתי, נוצר ע"י תעשיית הטלקום ונמצא בשימוש בעיקר אצלם, ומחזיק כמות מאוד מצומצמת של מידע. למרות חידושים ושיפורים בשנה האחרונה, המוצר לא ממש השתנה מבחינת הקונספט שלו והייעוד שלו.

  5. נשמע מעניין מאוד,
    כדי להבין בבירור,
    בעצם על פעם שאני כותב שאילתה לשרת הנוכחי שלי,
    הוא רושם אותה בכלי שרתי הרפליקציה?
    וכאשר אני לוקח נתונים הוא לוקח מהשרתים המוגדים את השרת המצב היותר טוב?
    יש מגבלה לכמות השרתים שניתן לעשות בניהם את הקישור הזה?

    תודה,
    ושמחתי להכיר את הבלוג הנוכחי :)

  6. הי רומן
    אתה רושם את כל השאילתות לפרוקסי והוא יודע לנתב את השאילתא בהתאם (כתיבה למסטר, קריאה לסלייב).
    במידה ויש כמה מסטרים, הוא ינתב את שאילתת הכתיבה למסטר הפחות עמוס. אותו דבר קורה עם סלייבים ושאילתות קריאה.
    ניתן לבצע רפליקציה על מספר רב של שרתים. ראיתי דוגמאות למספר מסטרים (בד"כ 2) שלכל מסטר יש כמה סלייבים (2-3 בד"כ).

כתיבת תגובה

האימייל שלך לא יוצג באתר. (*) שדות חובה מסומנים

*

תגי HTML מותרים: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">