1. Bibliothèque
  2. TCP ו-UDP
  3. צלילה לעומק TCP

Mis à jour il y a 1 mois

סגרת חיבור TCP. בדקת netstat. החיבור עדיין שם, מסומן TIME_WAIT. המתנת. הוא עדיין שם. אלפים מהם, לפעמים — שקעים שאמורים היו להיות מתים, מתמשכים כרוחות רפאים בטבלת החיבורים שלך.

זה לא באג. TIME_WAIT הוא TCP שמסרב לשכוח. במשך שישים שניות לאחר שסגרת חיבור, TCP זוכר שהוא היה קיים — כי ייתכן שהרשת עדיין לא קיבלה את ההודעה.

מה TIME_WAIT הוא בעצם

כאשר חיבור TCP נסגר, הצד שיוזם את הסיום נכנס ל-TIME_WAIT לאחר השלמת לחיצת היד הארבע-שלבית. השקע נשאר מוקצה בטבלת החיבורים של הליבה, ומונע שימוש חוזר מיידי באותה רביעייה בדיוק — כתובת מקומית, פורט מקומי, כתובת מרוחקת ופורט מרוחק.

משך הזמן הוא 2MSL — פי שניים מה-Maximum Segment Lifetime. MSL הוא הזמן המרבי התיאורטי שמנת TCP יכולה לשרוד ברשת לפני שנזרקת, בדרך כלל 30 שניות. לכן TIME_WAIT נמשך 60 שניות ברוב המערכות, אם כי חלקן משתמשות ב-30 או 120.

במהלך TIME_WAIT, השקע כמעט אינו צורך משאבים — אין חוצצים, אין מצב יישום. הוא פשוט תופס ערך בטבלת החיבורים של הליבה וחוסם שימוש חוזר באותה רביעייה ספציפית.

מדוע TCP מסרב לשכוח

TIME_WAIT קיים משתי סיבות, שתיהן עוסקות במניעת בלבול.

בעיית ה-ACK האבוד

סגירת חיבור TCP מסתיימת עם ACK. אם אותו ACK אחרון יאבד, הצד המרוחק ישלח מחדש את ה-FIN שלו. ללא TIME_WAIT, המערכת שלך כבר הייתה הורסת את מצב החיבור. היא הייתה מגיבה ל-FIN שנשלח מחדש עם RST, ומשאירה את הצד המרוחק מבולבל לגבי האם החיבור אכן נסגר.

על ידי הישארות ב-TIME_WAIT, המערכת שלך יכולה לאשר כראוי FINs שנשלחו מחדש. שני הצדדים מסכימים שהחיבור מת. אין עמימות.

בעיית המנה הנודדת

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

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

TIME_WAIT מונע זאת על ידי סירוב לעשות שימוש חוזר בשילוב כתובת/פורט עד שכל מנה נודדת אפשרית פגה. שתי MSLs מבטיחות שכל מנה מהחיבור הישן מתה.

מתי TIME_WAIT הופך לבעיה

TIME_WAIT הוא נורמלי. ראיית אלפי שקעי TIME_WAIT ב-netstat פשוט אומרת שהמערכת שלך הייתה עסוקה בסגירת חיבורים. זה בסדר גמור.

זה הופך לבעיה כאשר נגמרים לך הפורטים.

כל שקע TIME_WAIT תופס פורט ארעי אחד. רוב המערכות מציעות כ-28,000 פורטים ארעיים (בדרך כלל 32,768 עד 60,999). אם תיצור 28,000 חיבורים לאותו יעד תוך 60 שניות, תמצה את מרחב הפורטים. חיבורים חדשים ייכשלו עם "cannot assign requested address."

זה פוגע ב:

  • לקוחות HTTP שמפציצים נקודת קצה API בודדת
  • מאזני עומס המעבירים נפחי תעבורה גבוהים
  • שרתי פרוקסי
  • יישומים עם מאגר חיבורים שבור

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

ניהול TIME_WAIT

tcp_tw_reuse (Linux)

הפרמטר net.ipv4.tcp_tw_reuse של הליבה מאפשר שימוש חוזר בשקעי TIME_WAIT עבור חיבורים יוצאים חדשים כאשר חותמות זמן TCP מוכיחות שהחיבור החדש הוא חדש באמת. זה בטוח — חותמות הזמן מונעות קבלת מנות ישנות — ומבטל בפועל את מיצוי הפורטים עבור לקוחות.

SO_REUSEADDR

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

מאגר חיבורים

הפתרון האמיתי הוא בדרך כלל אדריכלי: הפסק ליצור ולהרוס חיבורים. HTTP keep-alive, ריבוב HTTP/2, מאגרי חיבורי מסד נתונים — כולם נמנעים מ-TIME_WAIT על ידי שימוש חוזר בחיבורים במקום לסגור אותם.

חיבור מתמשך אחד עדיף על אלף חיבורים קצרי חיים.

מתי לדאוג

שקעי TIME_WAIT קיימים: נורמלי.

שקעי TIME_WAIT מונעים חיבורים חדשים: בעיה.

עבור שרתים המקבלים חיבורים נכנסים, TIME_WAIT כמעט ולא משנה. לקוחות משתמשים בפורטי מקור שונים, כך שאין התנגשות. פורט ההאזנה של השרת לעולם אינו נכנס ל-TIME_WAIT.

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

השקעים שנשארים בפלט ה-netstat שלך אינם רוחות רפאים שרודפות את המערכת שלך. הם TCP שנזהר — זוכר חיבורים בדיוק מספיק זמן כדי לוודא שהרשת אכן התקדמה.

שאלות נפוצות על TIME_WAIT

מדוע TIME_WAIT הוא 60 שניות ולא קצר יותר?

המשך הוא 2MSL — פי שניים מה-Maximum Segment Lifetime. MSL מייצג את הזמן הארוך ביותר שמנה יכולה תיאורטית לשרוד ברשת. המתנה לכפליים מאותו משך מבטיחה שכל מנה מהחיבור הישן פגה לפני שניתן לעשות שימוש חוזר בפורט. משכים קצרים יותר היו מסכנים קבלת מנות ישנות בחיבורים חדשים.

האם אני יכול פשוט להשבית TIME_WAIT?

לא. לא ניתן להגדיר את TIME_WAIT לאפס כי הוא בסיסי לערבויות האמינות של TCP. ניתן להפחית את השפעתו עם tcp_tw_reuse או מאגר חיבורים, אך ביטולו לחלוטין יפגע ביכולת TCP למנוע פגיעה בנתונים ממנות מעוכבות.

האם השרת או הלקוח נכנס ל-TIME_WAIT?

הצד שיוזם את הסגירה — שולח את ה-FIN הראשון — נכנס ל-TIME_WAIT. עבור HTTP/1.0 ללא keep-alive, שרתים בדרך כלל סוגרים ראשונים, לכן השרתים צוברים TIME_WAIT. עבור HTTP מודרני עם keep-alive, לקוחות לעתים קרובות סוגרים חיבורים בטלים, לכן הלקוחות צוברים TIME_WAIT.

מדוע אני רואה שקעי TIME_WAIT אפילו עם מאגר חיבורים?

מאגרי חיבורים בסופו של דבר סוגרים חיבורים בטלים, וסגירות אלו יוצרות שקעי TIME_WAIT. זה נורמלי. המטרה של מאגר אינה אפס TIME_WAIT — זו הפחתת תחלופת חיבורים מספיק כדי ש-TIME_WAIT לעולם לא ימצה את הפורטים.

Cette page vous a-t-elle été utile ?

😔
🤨
😃