הקדמה
אני מניח שרובכם, אם אי פעם ניהלתם חנות אונליין רצינית, מכירים את הרגע הזה: יום מכירות גדול, הגולשים זורמים, ופתאום האתר מתחיל לזחול. בודקים את השרת והמעבד דווקא בסדר. בודקים עוד קצת – ומגלים שמסד הנתונים (MySQL) הוא זה שנחנק. כל בקשה של גולש הופכת לעשרות שאילתות, וכולן רצות לאותו שרת אחד ומסכן.
בדיוק בשביל הסיפור הזה קיים ProxySQL שכבת פרוקסי חכמה שיושבת בין האפליקציה למסד הנתונים, ומנהלת את התעבורה במקום פשוט להעביר אותה. במאמר הזה נסביר איך אנחנו משתמשים בו כדי לשמור על חנויות איקומרס מהירות ויציבות, גם ברגעים הכי עמוסים.
אז מה ProxySQL בעצם עושה?
בקצרה הוא מתחזה למסד הנתונים. האפליקציה חושבת שהיא מדברת עם MySQL רגיל, אבל בפועל היא מדברת עם ProxySQL, וזה כבר מחליט מה לעשות עם כל שאילתה: לאן לשלוח אותה, האם להחזיר תשובה מהזיכרון, ואפילו האם לשנות אותה בדרך.
זה נשמע פשוט, אבל השליטה הזאת פותחת המון אפשרויות. נעבור עליהן אחת אחת.
1. פיצול קריאה/כתיבה על גבי רפליקציה
אחת הנקודות שהכי הרבה אנשים מפספסים: רוב הפעילות מול מסד הנתונים באתר איקומרס היא קריאה, לא כתיבה. גולש שמדפדף בקטלוג, מסנן מוצרים, פותח דף מוצר, קורא ביקורות כל אלה קריאות (SELECT). הכתיבות (הזמנה, עדכון מלאי, הרשמה) הן חלק קטן יחסית מהתעבורה.
אז למה שכל הקריאות האלה יעמיסו על אותו שרת שמטפל גם בכתיבות?
כאן נכנסת רפליקציה מבנה שבו יש שרת Master אחד שמקבל את הכתיבות, ושרת (או כמה) Replica / Slave שמחזיקים עותק מסונכרן של המידע ומשמשים לקריאות. ProxySQL יודע, לפי חוקים שאנחנו מגדירים, לנתב:
- שאילתות כתיבה (
INSERT, UPDATE, DELETE) ← ל-Master - שאילתות קריאה (
SELECT) ← ל-Replicas
היתרון ברור: את עומס הקריאות אפשר לפזר על פני כמה שרתים ולהוסיף עוד לפי הצורך, בזמן שה-Master מתפנה לעשות את מה שרק הוא יכול לעשות לכתוב. במקום שרת אחד שנחנק, יש מערך שמתחלק בעבודה.
2. לא כל קריאה שווה ולמה חשוב לזהות אילו קריאות נשארות ב-Master
עד כאן הסיפור נשמע ורוד, אבל יש כאן מלכוד שחייבים להכיר: הרפליקציה הסטנדרטית של MySQL היא אסינכרונית.
מה זה אומר? כשה-Master מקבל כתיבה, הוא מאשר אותה מיד ורק אחר כך מעביר אותה ל-Replicas. בפועל יש עיכוב קטן (Replication Lag) בדרך כלל מילישניות, אבל תחת עומס הוא יכול לגדול. וזה יוצר בעיה קלאסית באיקומרס:
לקוח מוסיף מוצר לעגלה (כתיבה ל-Master) ומיד נכנס לדף העגלה (קריאה). אם הקריאה הזאת הלכה ל-Replica שעוד לא הספיקה להתעדכן – הלקוח יראה עגלה ריקה. חוויה הרסנית.
לכן חלק חשוב מהעבודה הוא מיפוי מדויק של השאילתות: אילו קריאות הן "רגישות לעדכניות" וחייבות ללכת ל-Master (עגלה, צ'קאאוט, מלאי בזמן אמת), ואילו קריאות סובלות בקלות עיכוב זעיר (קטלוג, דף מוצר, ביקורות) ויכולות ללכת ל-Replicas. ProxySQL מאפשר להגדיר בדיוק את החוקים האלה לפי תבנית השאילתה.
רגע, ולמה בכלל אסינכרוני ולא קלאסטר?
שאלה מצוינת. יש פתרונות סינכרוניים (כמו Galera Cluster) שבהם כל כתיבה מאושרת רק אחרי שכל הצמתים קיבלו אותה וכך אין Lag בכלל. אבל זה בא במחיר: כל כתיבה מחכה לכל הצמתים, מה שמאט את הכתיבות ומגדיל את הרגישות ללטנציה ברשת. ככל שמוסיפים צמתים, הכתיבה נעשית איטית יותר, לא מהירה יותר.
רפליקציה אסינכרונית, לעומת זאת, כמעט לא פוגעת בביצועי הכתיבה ומאפשרת להוסיף Replicas לקריאה בקלות ובזול. עבור איקומרס, שבו כזכור רוב הפעילות היא קריאה, זה בדרך כלל האיזון הנכון: ביצועי כתיבה מלאים, יכולת scaling מצוינת לקריאות, ואת בעיית ה-Lag פותרים בחוכמה עם ProxySQL בדיוק כמו שתיארנו.
3. Query Cache – שאילתות שאפילו לא יוצאות החוצה
עכשיו לחלק שאנחנו במיוחד אוהבים. חלק גדול מהשאילתות באתר חוזרות על עצמן שוב ושוב עם אותה תוצאה בדיוק רשימת הקטגוריות, מוצרים מומלצים בעמוד הבית, באנרים, הגדרות. אין שום סיבה שכל גולש יגרום להרצה מחדש של אותה שאילתה במסד הנתונים.
מיפינו את השאילתות האלה, ולכל תבנית כזאת הגדרנו Cache ב-ProxySQL עם זמן תפוגה (TTL) מתאים. מרגע שהתוצאה נמצאת ב-Cache, ProxySQL מחזיר אותה ישירות מהזיכרון – השאילתה בכלל לא יוצאת אל שרת מסד הנתונים.
וכאן טריק ארכיטקטוני יפה: ProxySQL מותקן אצלנו על כל שרת ווב בנפרד. המשמעות היא שכשיש Cache Hit, התשובה מגיעה מהזיכרון המקומי של אותו שרת ווב עצמו בלי אף קפיצה ברשת אל שרת הדאטהבייס. פחות עומס על ה-Master ועל ה-Replicas, ופחות תעבורה ברשת הפנימית.
4. חיבור דרך Socket במקום TCP/IP
בגלל שה-ProxySQL יושב מקומית על שרת הווב, האפליקציה מתחברת אליו דרך Unix Socket ולא דרך TCP/IP.
ההבדל אולי נשמע טכני וזניח, אבל כשמדובר באלפי חיבורים בשנייה הוא מצטבר: חיבור TCP/IP דורש handshake, ניהול פורטים ומעבר דרך ה-network stack גם כשהכול על אותה מכונה. חיבור דרך Socket מדלג על כל זה ומדבר ישירות דרך מערכת ההפעלה. פחות latency לכל חיבור, פחות overhead, וחיסכון שמורגש בסקייל.
5. יתרונות נוספים שאפשר ליישם
מעבר לבסיס, ProxySQL נותן ארגז כלים שלם שאפשר להפעיל לפי הצורך:
- Connection Pooling – מנגנון חכם לפתיחה וסגירה של חיבורים למסד הנתונים. במקום שכל בקשה תפתח חיבור חדש (יקר) ותסגור אותו, ProxySQL מתחזק "בריכה" של חיבורים פתוחים ומחזיר אותם לשימוש חוזר. זה לבדו מוריד עומס משמעותי מ-MySQL תחת תעבורה גבוהה.
- שינוי שאילתות On the Fly – אפשר לתפוס תבנית שאילתה ולשנות אותה תוך כדי תנועה: לחסום שאילתה כבדה שמפילה את המערכת, לתקן שאילתה בעייתית של תוסף, או לנתב שאילתה מסוימת ליעד אחר – בלי לגעת בקוד של האפליקציה. מציל חיים ברגעי חירום.
- פיצול בין כמה שרתי Master (Sharding) – כשחנות גדלה מאוד, אפשר לפצל את המידע בין כמה שרתי Master מאחורי הקלעים, ו-ProxySQL מנתב כל שאילתה לשרת הנכון. האפליקציה ממשיכה לחשוב שהיא מדברת עם מסד נתונים אחד – כל המורכבות מוסתרת בשכבת הפרוקסי.
- High Availability – אם Replica נופלת, ProxySQL מזהה ומפסיק לנתב אליה אוטומטית; אם ה-Master מתחלף, אפשר להגדיר ניתוב מחדש בלי downtime לאפליקציה.
סיכום
ProxySQL הוא לא עוד "עוד רכיב" במערכת הוא שכבת בקרה חכמה שמאפשרת לנו לקחת מסד נתונים שנחנק תחת עומס ולהפוך אותו למערך מבוזר, מהיר ועמיד. פיצול קריאה/כתיבה, Cache מקומי שחוסך שאילתות שלמות, חיבור דרך Socket, ניהול חיבורים חכם ושינוי שאילתות תוך כדי תנועה כל אלה מצטברים להבדל אמיתי בחוויית הגולש, ובעיקר בשורה התחתונה של חנות איקומרס.
אצלנו ב-SPD זה חלק מהתשתית שאנחנו בונים ללקוחות שדורשים ביצועים גבוהים במיוחד לקראת ימי המכירות הגדולים, שבהם כל מילישנייה נספרת.


