• בלוג
  • באג ריפורט: בעיית קונפיגורציה ב haproxy

באג ריפורט: בעיית קונפיגורציה ב haproxy

אני רוצה לפתוח פה מדור חדש בבלוג שנקרא "באג ריפורט" - לא, אני לא הולך לדווח לאף אחד על באגים ומקווה שגם אתם לא תדווחו לי על באגים. הכוונה היא לקחת באג שנתקעתי עליו (או שאתם נתקעתם עליו ושיתפתם אותי) ולפרק אותו כדי שלא נצטרך לעשות שטויות כאלה שוב. והיום בבאג ריפורט - בעיית קונפיגורציה ב haproxy שלקח לי הרבה יותר מדי זמן למצוא.

1. מה המשתמשים ראו

משתמשים שנכנסו למערכת בה היתה הבעיה קיבלו את המערכת תקינה בחלק מהזמן, ובחלק אחר מהזמן קיבלו הודעות שגיאה מוזרות עם הקוד 503. לא נראה שיש חוקיות מתי מקבלים תשובה תקינה ומתי שגיאת 503, עבור אותם URL-ים ממש.

2. מה אני ראיתי

הדבר הראשון שעושים כדי לפענח בעיות כאלה הוא להבין מאיזה מערכת ושרת בכלל מגיעה הבעיה. רוב אתרי הווב היום מוחקים את ה HTTP Headers כדי לא להסגיר שום מידע, ולכן הדבר הראשון שאנחנו עושים כשצריך לדבג בעיות מסוג זה הוא לעדכן את הקונפיגורציה של שרתי הווב ודווקא כן לשתול שם בחזרה את ה Headers עם מזהי השרת.

אחרי הפעלה מחדש וצפיה ב curl אפשר היה לראות שמי ששולח את הודעת ה 503 היה haproxy. קצת חיטוט בתיעוד הראה שהאפרוקסי ישלח הודעות 503 אם הוא לא מוצא שרת מתאים להעביר אליו את הבקשה. אבל, אם הוא לא היה מוצא שרת מתאים להעביר אליו את הבקשה היינו צריכים לראות את השגיאה בכל פניה - למה חלק מהפניות כן הצליחו וחלק לא?

3. איפה היתה הבעיה

אקצר לכם את החפירות בקבצי הלוג, השינויים המיותרים בקונפיגורציה והיותר-מדי-שעות של קריאת אותן שורות בקובץ ההגדרה ונקפוץ ישר לבלוק הבעייתי:

backend nginx
        option forwardfor header X-Real-IP
        reqadd X-Scheme:\ https if { ssl_fc }
        server nginx 127.0.0.1:80
        server nginx /var/run/nginx.sock

הבלוג מגדיר את nginx בתור Backend ל Haproxy, אבל מגדיר שתי דרכי גישה ל nginx: גם באמצעות הכתובת 127.0.0.1:80 וגם באמצעות Unix Socket. מאחר ו nginx הקשיב רק על פורט 80 ולא דרך ה socket, כל הבקשות ש Haproxy ניסה לשלוח ל server השני נכשלו.

4. איך היא הגיעה לשם

התחביר של Haproxy שמאפשר להגדיר מספר שרתים בתוך Backend יחיד נועד בשביל שנחלק את העומס בין כמה שרתים. אין שום הגיון לכתוב פעמיים פקודת server שתגיע לאותו שרת רק מנתיב אחר. אפילו אם ה nginx כן היה מקשיב על ה Socket זה היה מיותר - צריך היה למצוא את דרך התקשורת המועדפת ולהישאר איתה.

השערה שלי שפעם זה עבד עם Unix Socket, מישהו החליף את זה ל TCP ואז שם את שורת ה Socket בהערה, ומתישהו (לא ברור מתי) מישהו הוציא מהערה (כנראה בטעות) את שורת ההאזנה ל socket.

5. איך אפשר לשמור שלא נעשה שטויות כאלה שוב

למרות שהבאג נגרם משורה אחת לא נכונה בקובץ קונפיגורציה, הגורמים המערכתיים האמיתיים לתקלה היו רבים:

  1. קבצי הקונפיגורציה לא נשמרו בתוך Source Control כמו הקוד, ולכן קשה היה לדעת מי שינה מה ומתי בקובץ.

  2. מתכנתים השאירו קוד שלא צריכים בהערה, מה שגרם להשארת קוד שלא עובד (אפילו שהיה בהערה) בתוך הקובץ ובמקום זמין.

  3. האפרוקסי לא התלונן בשום מקום (שהצלחתי למצוא) על זה שהוא זורק בקשה כי הוא לא מצליח להגיע ל Unix Socket. מדיניות לוגים טובה יותר אולי היתה מאפשרת לנו לראות את התקלה בזמן אמת ולחסוך זמן חיפוש.