"התקפת לב" (או חוסר ב heartbeat)..

pattos

New member
מה strace

זה java, יש כלים ייעודיים לזה (jconsole/jstack וכו')
ויותר פשוט להקליט את התקשורת עם tcpdump מאשר לחכות שהיא תתרחש
 

choo

Active member
לגבי כלים יעודיים - טוב לדעת. לגבי הקלטת tcpdump - תלוי בקצב

 

TakeCtrl

New member
הtrace לא יגיד לך כלום , כיוון שמדובר בחוסר של משהו

תראה בלוג שסה"כ לא קיבלנו בזמן הודעה מהשרת השני ולכן זרקנו אותו..
 

choo

Active member
trace בשני הצדדים יעזור "לחתוך" את המדבר לשניים

&nbsp
הוא יעזור לראות האם ההודעה נשלחה מהלקוח בכלל, האם ההודעה הגיעה לשרת (אבל הטיפול בה נכשל) או שכלל לא התקבלה על ידי האפליקציה.
&nbsp
בסופו של דבר, הוא מחפש אריה במדבר, והוא זקוק למספריים, זכוכית מגדלת, קופסת גפרורים ופינצטה
 

TakeCtrl

New member
לי בכל מקרה אין trace... כי מעולם לא קיבלתי שום דבר שיחולל

&nbsp
אותו ,
כמו כן, אני אפילו לא מחכה לטפל בהודעה כדי לעשות reset לheartbeat מספיק שאני משתחרר מהread וכבר אני עוצר timeout. כך שאפילו ההודעה יכולה להיות לא תקינה, זה לא משנה, העיקר שקיבלתי משהו.
&nbsp
גם בצד השני אין trace (אם כי יש אזכור במקום אחד לEOFException, אבל רק פעם אחת), כנראה בולעים שם חלק מהExceptions מחליפים אותם בהודעות..
 

choo

Active member
אי אפשר להוסיף trace? הקוד אינו שלך? או שהבעיה לא משתחזרת?

&nbsp
היכולת לשחזר את הבעיה בסביבת debug הוא חצי מהדרך לפתרון בעיות מהסוג הזה.
 

TakeCtrl

New member
אתה מדבר על trace level log או stack trace? :)

הבעיה לא משתחזרת, כמו תמיד במקרים כאלה של תזמון ,זה כמעט בלתי אפשרי לשחזר את זה..
היו לנו מצב אצל אחד הלקוחות שהמערכת שלנו לא הייתה מקבלת כמעט כלום בזמנים מסויימים ורק כשאחד מכוחותינו היה שם פיזית הוא גילה שהם מעבירים ברשת גיבויים מפלצתיים שהיו חונקים את הfirewall , מספיק ששמו את השרתים שלנו במקום אחר וזה עבד..
אצל כמעט כל התקשורת עובדת על tcp/udp..
 

user32

Well-known member
מנהל
היתה לנו בעיה דומה במשחק רשת

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

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

TakeCtrl

New member
ולקוות שהלוגים לא ילכו לאיבוד ולא יהיה לך בעיות ביצועים

(כי אנחנו משתמשים עדיין בLog4j).
 

user32

Well-known member
מנהל
כן אבל לזה יש מליון פתרונות סטנדרטיים ופשוטים

לוג סלקטיבי, לוגר נפרד, לוג עם סינון, appenders שונים שאפשר גם לממש לבד. לא חסר.

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

choo

Active member
בדיוק בשביל זה המציאו "לוג בינארי מקוצר בזכרון"

&nbsp
אתה לא חייב לשפוך את הלוג החוצה על בסיס קבוע. אתה יכול לשמור תור מעגלי של הודעות לוג (שמור אותן בצורה בינארית באורך קבוע, לניהול קל), ששומר את ה-X הודעות האחרונות בצורה מפורטת (הגעה של בתים ברשת, מתי כובה הטיימר וכדומה, כולל מספרים סידוריים), כלכל הודעה מוצמד timestamp. שמור לוג מקביל גם בלקוח, וכתוב קוד בתוכנת השרת שכשהודעה כזו הולכת לאיבוד, היא מדפיסה את הלוג הבינארי לקובץ חיצוני באופן חד פעמי (כדי שלא לדרוס את הלוג המקורי שוב ושוב), ושולחת הודעה לתוכנת הלקוח לבצע את אותו הדבר.
&nbsp
אחרי השיחזור הבא של התקלה, תוכל לקבל מידע נוסף.
&nbsp
מעבר לזה, על פי התאור שלך אתם רגישים לעומסים ברשת - לפיכך אפשר לנהל מעקב אחרי "איכות השרות" ברשת בצורה פשוטה - בכל הודעה שהלקוח שולח, שומרים את השעה בלקוח. בשרת בודקים מתי ההודעה הגיעה, ואם הודעה מגיעה באיחור גדול יותר מ-X - מוציאים אוונט. צריך מדי פעם לבצע סינכרון שעונים בין שני השרתים - אלא אם שניהם מסונכרנים בקביעות מול שרתי ntp אמינים.
&nbsp
בשורה התחתונה - הרעיון הוא לייצר לעצמכם כלים שיאפשרו לכם לדבג בעיות, ולא להשאר חסרי אונים מולן.
 

TakeCtrl

New member
הבעיה גם שצריך לבדוק את הכלים האלה אם הם מציפים את זה :)

זה נשמע נחמד, יכול להיות שהייתי עושה את זה גם אלמלא כמה בעיות.
&nbsp
העובדה שצריך לשנות את השרת השני היא בעייתית, (כלומר להוסיף פרמטרים לממשק איתנו), בתור דוגמא הם עדיין עובדים מול השרת שלנו בממשק API של 10 גרסאות אחורה (לפני כמה שנים), כלומר עבור כל הודעה שהם שולחים הXML שלהם צריך לעבור טרנפורמציה עד 10 פעמים בDOM (עד ,כי רוב ההודעות לא עברו שינוי) עד לגרסה הנוכחית ואח"כ לעבור טרפורמציה חזרה לגרסה שהשרת משתמש בה. למזלנו הheartbeat והודעות השוטפות בstreaming לא צריכות שינויים.
כל פעם שרוצים שיעדכנו את הAPI שלהם לגרסה יותר מעודכנת הצוות נעמד על הרגליים האחוריות ומתמחר את הזה בזמנים מופרעים עד שיורדים מהם. אני לא יודע עד כמה הם היו פתוחים לשינויים כאלה.
שנית, מה זה ייתן לנו, נגיד שיוצא event על זה שיש lag, יוצא event, בהנחה שמישהו מקשיב לו, הרי זה בדיוק מה שקורה עם heartbeat, ברגע שיש סטייה של 30 שניות, אנחנו מנתקים אותם, יוצאת אזעקה, הם מתחברים שוב תוך 7 שניות, וזה חוזר לקדמותו לוגים יכולים לספר רק חלק מהסיפור, כי החור השחור זה TCPdump רק הוא יכול להגיד לנו בוודאות מה קרה אחרי שהשרת שלח הודעה,אנחנו יכולים לשמור הודעות עד מחר, לראות שהם יצאו, לראות שהם לא יתקבלו, אבל תישאל השאלה למה? הם המחשב לא שידר אותם? הכרטיס רשת? הrouter? הכרטיס רשת בצד השני?
בתור דוגמא שנייה יש לי לקוח שהשרת שלנו נפל שם, ולא עלה חזרה (קנינו מוצר שעושה ping לjvm שלנו באותו מכונה , ואם יש לו בעיות הוא מפיל אותו ומעלה אותו שוב), אותו מוצר דיווח שהוא לא קיבל CPU Cycles כבר x פעמים, החברה אמרה שזה מוצר בגרסה ישנה שבמקרים של עומס CPU חזק יכול לגרום לבעיות אפילו בעלייה מחדש ובגרסה חדשה הם תיקנו את זה, אבל אין לי מה להגיד ללקוח למה היה עומס CPU מלכתחילה כי הלוגים לא הצביעו על משהו חריג.
 

user32

Well-known member
מנהל
TCP DUMP לא תופס את המקרה הנפוץ

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

choo

Active member
גישת "אין לי פתרון מלא אז אני לא אעשה כלום" אינה יעילה

&nbsp
לפעמים עדיף פתרון שמכסה חלק מהבעיות, על פני אי פתרון.
&nbsp
לגבי הגורמים האחרים - אחד הדברים שאנחנו השתמשנו בהם במערכת הוא לוג sarשדוגם את מצב המערכת פעם בשניה, ושמירת של הלוג הזה למשך X זמן אחורה. כשיש בעיה, אפשר לראות בדיוק עד כמה המעבדים היו עסוקים, והאם היו עסוקים בטיפול בפסיקות חומרה או תוכנה, ריצה ב-user space או בקרנל, או בהמתנה לדיסק, מצב של זכרונות מטמון משמעותיים בקרנל וכדומה. בנוסף ישנו לוג של צריכת המשאבים של כלל התהליכים במערכת ברמה של .thread. הלוגים הללו, בתוספת עבודת ניתוח, איפשרו לנו לזהות מצבים של חנק משאבים במקרים שונים. הלוגים הללו לא נאספו כבר מהיום הראשון - בכל פעם הוספנו עוד משהו, ובמשך השנים קיבלנו יכולות דיבוג לחלק ניכר מהבעיות הללו. מה שצריך זה לקחת יוזמה, להוסיף בכל פעם כלים נוספים, ולייצר ארסנל של כלים שיעזרו לכם להתמודד עם בעיות מערכתיות כאלו.
 

TakeCtrl

New member
אני מנסה להתמקד במה שאני יכול לשנות...

תהליך קריאת הxml שלנו מsocket קצת דבילי , מכיוון שזה סוקט פתוח כל הזמן, לפני כל הודעה יש 2 byte, שהם מעין header שאומר לך מה גודל ההודעה ואיזה bit לאופציות נוספות.
מכיוון שאי אפשר להאכיל את הstream הזה ישירות לdom parser, מה שקורה באמת הוא שיש לולאה שמעתיקה byte אחר byte מinput ל Output ,(ואחרי כל עדכון עושה reset ל heartbeat), לוקחת את הכל הbyte array הזה חזרה לinput stream חדש ואז מעבירה את זה לParser.
לכל הפחות היה אפשר לקחת לאתחל byte array בגודל הידוע מראש ולעשות קריאה אחת ,על הכל, (יחד עם הגדרה של socketTimeout) .
&nbsp
אבל בנוסף לכך חפרתי קצת...ובהתבסס על זה
http://www.java2s.com/Tutorial/Java...orreadingarbitrarylengthdatainauniformway.htm
&nbsp
יצרתי משהו דומה אצלנו, ואני רוצה להציע אותו לשיפור ביצועים.
&nbsp
בנוגע לקביעת timestamp הצפתי כבר ששני הצוותים יעשו patch שירשום heartbeat כל פעם והעלתי את הבעיות שלל timestamp או מזהה חד ערכי יהיה די בעייתי לאתר את זה, בנוגע לNTP נאמר לי שאין ערובה שלקוחות יהיו מקונפגים עם זה.
&nbsp
לוג sar?
 

choo

Active member
- לקרוא בית אחד כל פעם - עצלות פושעת

&nbsp
אם במקום לקרוא הודעה שלמה בבת אחת (או לפחות ברמה של בלוקים - נניח 4KB בכל קריאה פרט לזנב) קוראים בכל פעם בית אחד - מייצרים הגדלה דרסטית של קריאות מערכת. אם אכן מדובר בקריאה בכל פעם מהסוקט, כולל מעבר לקרנל (להבדיל מקריאה דרך שכבת אבסטרקציה בקוראת מחוצץ בזכרון ופונה לסוקט רק כשהוא מתרוקן) - בפרט במערכת שצריכה לעמוד בעומסים - זה טרוף (הודעה של 1000 בתים תדרוש כמעט פי 1000 system calls מאשר אם היתה נקראת בהודעה אחת) שנובע או מעצלות של מפתחים, או מתוך בורות.
&nbsp
לגבי sar - שוב, רלוונטי אם אתהם רצים על לינוקס או יוניקס כלשהו:
&nbsp
http://linux.die.net/man/1/sar
&nbsp
אם אתם רצים על חלונות - אמור להיות כלי מקביל תחת המסגרת של ה-performance monitor, למיטב ידיעתי
 

TakeCtrl

New member
אולי זה שניהם, אני תמיד מגלה דברים חדשים...

זה מה שמתרחש היום..(זה צריך להתקשר לך לקוד המקורי ולמה כמעט אין שום flow לעדכון הheartbeat,
קוד:
try{

   if (len > 0) {
                int received = 0;

                boolean keepMoving = true;
                while (keepMoving) {
                    int curByte;
                    try {
                        curByte = _in.read();
                        if (curByte >= 0) {
                            _heartBeatValidator.setTimeOut();
                            baos.write(curByte);
                            received++;
                            if (received >= len) {
                                keepMoving = false;
                            }
                        } else {
                            _logger.warn("Negative curByte = " + curByte);
                            keepMoving = false;
                        }
                    } catch (IOException e) {
                        checkConnectivity();
                        keepMoving = false;
                    }
                }


                if (baos.size() > 0) {
                    try {
                        final byte[] msg = baos.toByteArray();
                        final InputStream inputStream = new ByteArrayInputStream(msg);
                        data = XMLUTILS.toDOM(inputStream);
                    } catch (SAXException e) {
                        _logger.warn("Broken data received");

                    }
                }
            }
        } catch (IOException ioex) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                _logger.error("", e);
            }

        }
וזה מה שאני זומם לעשות (כלומר להכניס את זה ישירות לDOM Parser) במקום כל הבלגן ההוא.
כן, אני יודע שהskip בעייתי, בעיקרון זה אמור לשמש רק ל לקריאת XML/
קוד:
public class WrappedInputStream extends FilterInputStream {

    private static final int PACKET_CLOSED = -1;
    private int remaining = PACKET_CLOSED;
    private final DataInputStream fDataInputStream;

    public WrappedInputStream(InputStream stream) throws IOException {
        super(stream);
        fDataInputStream = new DataInputStream(stream);
    }

    @Override
    public int read() throws IOException {
        final boolean wasClosed = readHeader();
        if (!isEmpty()) {
            final byte read = (byte) super.in.read();

            if (isValid(read)) {
                check(wasClosed, 1, read, read);
                return read;
            } else {
                close();
                return -1;
            }

        } else {
            close();
 

choo

Active member
בטוח ש-read מחזיר רק בית בודד?

&nbsp
מה המחלקה של in_ ושל baos ?
 

user32

Well-known member
מנהל
פה זה ג'אווה ג'אווה


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

vinney

Well-known member
איך אתה מקבל את הפעימות?

מהתיאור שלך נשמע שמדובר באיזה סוקט - זה TCP? יש לסוקט איזה timeout ברמת הסוקט? אם נגיד הפעימות שלך והtimeout של הסוקט זה אותו הזמן - יכול להיות מצב של race - מי יגיע יותר מהר, הפעימה שלך או שהסוקט יסגר?
 
למעלה