עודכן לפני חודש
הנה אמת שמנוגדת לאינטואיציה בנוגע לרשתות: האמינות של TCP יכולה לגרום לדברים להיות גרועים יותר.
כשאתם בשיחת וידאו וחבילה המכילה 20 מילישניות של אודיו אובדת, TCP ישלח אותה מחדש. אותה חבילה עשויה להגיע 200 מילישניות מאוחר יותר. עד אז, כבר אמרתם עוד שלוש מילים. להשמיע את האודיו הישן הזה עכשיו יהיה מוזר, מבלבל, חסר הגיון. המסירה ה"אמינה" הפכה את השיחה לגרועה יותר מכפי שהייתה אילו החבילה פשוט הייתה נעלמת.
בזמן אמת, מידע ישן אינו מידע מאוחר — הוא מידע שגוי. המיקום שלכם לפני 200 מילישניות הוא שקר לגבי מיקומכם כעת.
זו הסיבה שמשחקים, VoIP וסטרימינג וידאו כולם דוחים את הערבויות של TCP. הם בוחרים ב-UDP — פרוטוקול שכמעט אינו מבטיח דבר — מפני שהם זקוקים לחופש להיות חכמים לגבי מה לאבד.
שלושת החטאים של TCP כנגד זמן אמת
TCP מבצע שלוש עבירות המחריבות חוויות זמן אמת:
עיכוב שידור חוזר. כאשר חבילה אובדת, TCP שולח אותה מחדש. המידע המשודר מחדש מגיע מאוחר מדי כדי להיות רלוונטי, אך TCP שולח אותו בכל זאת, ומבזבז זמן ורוחב פס על מידע שכבר הפך מיושן.
חסימת ראש התור. TCP מוסר מידע בסדר. אם חבילה 47 אובדת, TCP מחזיק חבילות 48, 49 ו-50 כבנות ערובה עד שניתן לשדר מחדש את 47 — גם כשהיישום זקוק נואשות למידע החדש יותר הזה ממש עכשיו. החבילה האבודה חוסמת את התור.
בקרת עומס אגרסיבית. כשTCP מזהה אובדן חבילות, הוא מניח שיש עומס וקוצץ את קצב השליחה שלו. ביישומי זמן אמת, הדבר גורם לאיכות לקרוס בדיוק כשהרשת נמצאת תחת לחץ. היישום אינו יכול לשמור על שחרור הדרגתי חלק; TCP דוחף אותו מהצוק.
UDP אינו מבצע אף אחד מחטאים אלה. הוא מספק מספרי פורטים לריבוב, סיכום ביקורת לזיהוי שגיאות, ולא יותר מכך. חבילות מגיעות בכל סדר שהרשת בוחרת. חבילות אבודות נשארות אבודות. הריקנות הנראית הזו היא מתנתו של UDP: שליטה מלאה מוחזרת לידי היישום.
משחקים: ניבוי במקום שלמות
בירי מגוף ראשון תחרותי, 50 מילישניות יכולות לקבוע אם הירייה שלכם נרשמת לפני או אחרי זו של היריב. משחקים שולחים עדכוני מיקום 20, 30, אפילו 60 פעמים בשנייה. אם עדכון אחד אובד, העדכון הבא כבר בדרכו. לשדר מחדש את עדכון מיקום 47 אין כל טעם כשעדכונים 48, 49 ו-50 כבר הגיעו עם מידע חדש יותר.
מנועי משחקים פותרים אובדן חבילות באמצעות ניבוי — לא שידור חוזר.
ניבוי צד לקוח מאפשר לכם לראות תגובות מיידיות לפעולות שלכם. כשאתם לוחצים קדימה, הדמות שלכם זזה מיד על המסך — הלקוח מנבא מה שהשרת יאשר. כשעדכון הסמכות מהשרת מגיע, המשחק מפשר את ההבדלים, מצמיד את הדמות למיקום האמיתי או מתקן בצורה חלקה את המסלול.
אינטרפולציה מסתירה מידע חסר. כשעדכון מיקום אובד, המשחק אינו קופא או גמגם. הוא מניע בצורה חלקה את הדמות בין מיקומים ידועים, גולש ממקום שבו הייתה לפני 100 מילישניות למקום שבו היא נמצאת עכשיו. החבילה החסרה הופכת לבלתי נראית.
פיצוי פיגור גורם לזיהוי פגיעות להרגיש הוגן. כשאתם יורים על מטרה נעה, השרת אינו בודק היכן היא נמצאת כעת — הוא חוזר אחורה למקום שבו הייתה מנקודת המבט שלכם, תוך התחשבות בזמן ההשהייה של הרשת שלכם. מה שראיתם וירית אליו — הוא מה שהשרת מאמת.
משחקים גם מתעדפים בחוסר רחמים. אירועים קריטיים — ירי, מות שחקנים, לכידת יעדים — נשלחים מספר פעמים או משתמשים באישורים ברמת היישום. עדכונים קוסמטיים כמו אפקטים חזותיים נשלחים פעם אחת ונשכחים. אם הגיעו — מצוין. אם לא — המשחק ממשיך. לא כל מידע ראוי לאותה התייחסות.
VoIP: פרדוקס מאגר הג'יטר
שיחות קוליות מתמודדות עם אתגר שונה. פערים קצרים באודיו מקובלים — המוח האנושי מסוגל להשלים הברות חסרות בצורה מפתיעה. אך עיכוב הורס שיחה. כשההשהייה החד-כיוונית עולה על 150 מילישניות1, שיחות הופכות מתישות. מתחילים לדבר אחד על השני, עוצרים בצורה מביכה, ומאבדים את הקצב הטבעי של הדיבור.
מערכות VoIP מקדדות אודיו לחבילות המייצגות 10-40 מילישניות של דיבור. כל חבילה עצמאית. אם חבילה 47 אובדת, חבילה 48 עדיין מכילה אודיו תקין לפרוסת הזמן הבאה. TCP היה מחזיק את חבילה 48 עד שידור חוזר של 47. UDP מוסר את 48 מיד.
אך ישנה בעיה נוספת: ג'יטר. חבילות שנשלחו ברווח של 20 מילישניות עשויות להגיע ברווח של 5 מילישניות, ואז 50, ואז 15. תנודתיות זו תגרום לגמגום מתמיד — אודיו שמאיץ ומאט ללא הרף.
הפתרון הוא פרדוקסלי ביופיו: מאגר הג'יטר מוסיף בכוונה עיכוב כדי להסיר עיכוב.
מאגר ג'יטר מחזיק חבילות נכנסות 20-80 מילישניות לפני שמשמיע אותן. חבילות שמגיעות מוקדם ממתינות. חבילות שמגיעות מאוחר (אך בתוך חלון המאגר) עדיין מצליחות. המאגר משחרר אודיו בקצב אחיד ויציב, מפצה על תנודות העיתוי ברשת עצמה. אתם מחליפים עיכוב קטן וקבוע בביטול הגמגום.
כשחבילות אובדות לגמרי — מגיעות לאחר שגם סבלנות מאגר הג'יטר פגה — VoIP משתמש בהסתרת אובדן חבילות. גישות פשוטות חוזרות על החבילה האחרונה התקינה או משמיעות שקט. אלגוריתמים מתוחכמים מנתחים את האודיו הקודם כדי לסנתז את התוכן החסר, ומחלצים גובה צליל וטון ליצירת צלילים סבירים. קודקים מודרניים כמו Opus עושים זאת כל כך טוב שאובדן של פחות מ-5% לרוב אינו נתפס כלל.
מערכות VoIP גם מסתגלות ללא הרף. הן מנטרות את התנאים ומתאימות את עצמן בזמן אמת — מכווצות את מאגר הג'יטר כשהרשת יציבה, מרחיבות אותו כשהג'יטר גדל, מפחיתות קצב העברה מ-64kbps ל-32kbps אם האובדן מזנק. ההתאמה המתמדת הזו אפשרית רק מפני ש-UDP מאפשר ליישום לשלוט בגורלו שלו.
סטרימינג וידאו: הקרבה סלקטיבית
סטרימינג וידאו חי משלב את הרגישות לזמן ההשהייה של VoIP עם דרישות רוחב פס עצומות. קול זקוק ל-20 עד 100 קילוביטים לשנייה. וידאו זקוק ל-500 קילוביטים עד 10 מגה-ביטים ומעלה. ולוידאו יש תלויות פנימיות מורכבות שחסרות לקול.
קודקי וידאו דוחסים על ידי קידוד ההבדלים בין פריימים. פריים מפתח (I-frame) מכיל תמונה שלמה — יקר לעיבוד אך עצמאי לחלוטין. פריימים חזויים (P-frames ו-B-frames) מקדדים רק את מה שהשתנה מאז הפריים הקודם — זולים לעיבוד אך תלויים. אבד פריים מפתח — וכל פריים שמסתמך עליו הופך לפגום. אבד פריים חזוי — והנזק מוגבל.
זה יוצר היררכיה של חשיבות. מערכות סטרימינג מיישמות הגנת שגיאות בלתי שוויונית: פריימי מפתח מקבלים יתירות נוספת, שידור תכוף יותר, ולפעמים אפילו שידור חוזר סלקטיבי. פריימים חזויים הם ניתנים לוויתור יותר. כשיש לאבד חבילות, המערכת בוחרת אילו אובדנות פוגעות פחות.
סטרימינג בקצב ביטים אדפטיבי מרחיב את הפילוסופיה הזו לרמות איכות. יישומים מנטרים אובדן חבילות ורוחב פס זמין, ועוברים בין קידודים תוך כדי תנועה. אם התנאים מתדרדרים, הזרם יורד מ-1080p ב-5 מגה-ביטים ל-720p ב-2 מגה-ביטים, ואולי אל 480p ב-1 מגה-ביט. משתמשים מעדיפים רזולוציה מופחתת על פני עצירות מתמדות. היישום מוותר בכוונה על איכות כדי לשמר רציפות.
RTP (פרוטוקול תעבורה בזמן אמת) מספק את השלד לכל זה. שוכב מעל UDP, RTP מוסיף מספרי רצף וחותמות זמן מבלי לכפות אמינות. המלווה שלו, RTCP, נושא משוב על איכות וסנכרון. יחד הם נותנים ליישומי הסטרימינג את המידע הדרוש להם כדי להסתגל בצורה חכמה.
חלק ממערכות הסטרימינג אפילו מיישמות שידור חוזר סלקטיבי — אך חכם יותר מ-TCP. אם חבילת פריים מפתח נעלמת ונותרות עוד 50 מילישניות מתקציב ההשהייה, היישום מבקש אותה ספציפית. עבור חבילות פחות קריטיות, או כשהזמן קצר, הוא ממשיך הלאה. היישום מחליט מה שווה להמתין לו.
תפקיד הרשת
יישומים מטפלים באובדן ובתנודתיות בצורה מבריקה, אך הפחתת הבעיות הללו ברמת הרשת עדיין מועילה. מנגנוני Quality of Service (QoS) יכולים לתעדף תעבורת זמן אמת על פני העברות בתפזורת.
סימוני DiffServ אומרים לנתבים אילו חבילות חשובות ביותר. חבילות VoIP המסומנות ב-EF (Expedited Forwarding) מקבלות תור עדיפות, ומפחיתות את הזמן שהן מבלות בהמתנה מאחורי העברות קבצים גדולות. כשמוגדר מקצה לקצה, הדבר משפר משמעותית את איכות הזמן האמת.
אך הנה המציאות: QoS מקצה לקצה דורש שיתוף פעולה מכל רשת בנתיב. נתב ביתי מוגדר בצורה מושלמת אינו מועיל אם ספק האינטרנט מתייחס לכל התעבורה באופן שווה. זו הסיבה שיישומים חייבים להתמודד עם מסירה לקויה — הם אינם יכולים להניח שהרשת תהיה ידידותית.
הדפוס העמוק יותר
UDP נותן ליישומים מתנה רדיקלית: החופש להגדיר מהי אמינות עבור הצרכים הספציפיים שלהם.
עבור משחקים, אמינות פירושה המצב העדכני ביותר — לא כל מצב. עבור VoIP, אמינות פירושה זרימה רציפה — לא מידע שלם. עבור סטרימינג, אמינות פירושה איכות אדפטיבית — לא איכות קבועה.
TCP כופה הגדרה אחת של אמינות — כל בית, בסדר, מובטח. הגדרה זו משרתת בצורה מושלמת את העברות הקבצים ואת דפי האינטרנט. אך כשתפיסה אנושית מניעה את הדרישות, כש-50 מילישניות קובעות אם חוויה מרגישה טובה או שבורה, הערבויות של TCP הופכות לאילוצים.
היישומים החשובים ביותר לאופן שבו אנו חווים את האינטרנט — המשחקים שאנו משחקים, השיחות שאנו מנהלים, הזרמים שאנו צופים בהם — כולם פועלים על UDP. הם מקבלים שחלק מהמידע יאבד ובוחרים להיות חכמים לגבי זה. הבחירה הזו, והמערכות המתוחכמות שנבנו סביבה, היא הסיבה שזמן אמת עובד בכלל.
שאלות נפוצות על UDP ביישומי זמן אמת
מדוע משחקים פשוט לא משתמשים ב-TCP עם פסקי זמן קצרים יותר?
שידור חוזר של TCP מוטבע בפרוטוקול ברמת מערכת ההפעלה — יישומים אינם יכולים להתאים אישית אותו. גם עם פסקי זמן אגרסיביים, TCP עדיין אוכף מסירה בסדר (הגורמת לחסימת ראש התור) ובקרת עומס (הגורמת לקריסת הקצב תחת לחץ). משחקים צריכים לדלג לגמרי על מידע אבוד — לא לקבל אותו מאוחר — וTCP פשוט אינו מסוגל לכך.
כמה אובדן חבילות יכולים יישומי זמן אמת לסבול?
זה משתנה בין יישום ליישום. VoIP עם קודקים מודרניים מתמודד עם 5% אובדן עם כמעט ללא הידרדרות מורגשת. משחקים יכולים להסתיר אובדן של 1-2% באמצעות אינטרפולציה, אך מתחילים להרגיש "לאגי" מעל 5%. סבולת סטרימינג הוידאו תלויה באילו חבילות אובדות — 5% אובדן אקראי עשוי להיות מקובל, אך אובדן פריים מפתח גורם לפגם נראה לעין עד לפריים המפתח הבא.
מה קורה כשתעבורת UDP מתחרה עם תעבורת TCP?
ל-UDP אין בקרת עומס מובנית, ולכן הוא אינו נסוג אוטומטית כשהרשת עמוסה. הדבר עלול לגרום ל-UDP לדחוק את תעבורת TCP — או לגרום ל-TCP לסגת באגרסיביות, ולתת ל-UDP עוד יותר רוחב פס. יישומי זמן אמת מעוצבים היטב מיישמים הגבלת קצב משלהם כדי להיות אזרחי רשת טובים.
האם ניתן להשתמש ב-UDP ליישומים הזקוקים לחלק מהנתונים בצורה אמינה?
כן. יישומי זמן אמת רבים שוכבים אמינות סלקטיבית מעל UDP. משחקים עשויים לשלוח אירועים קריטיים (כמו "שחקן מת") עם אישורים וניסיונות חוזרים ברמת היישום, תוך שליחת עדכוני מיקום ללא אמינות. ספריות כמו ENet ופרוטוקולים כמו QUIC מספקים גישה היברידית זו.
מדוע המשחק שלי מפגר גם על חיבור מהיר?
רוחב פס (מהירות) וזמן השהייה (עיכוב) הם שני דברים שונים לחלוטין. חיבור מהיר יכול להעביר כמויות גדולות של נתונים אך לא בהכרח להעביר אותם מהר. משחקים בעיקר זקוקים לזמן השהייה נמוך — זמני הלוך-ושוב קצרים לשרת. חיבור של 1 Gbps עם פינג של 100ms ירגיש גרוע יותר למשחקים מחיבור של 50 Mbps עם פינג של 20ms.
מקורות
האם דף זה היה מועיל?