לדלג לתוכן

איך מעצבים פיד חברתי - מקרה בוחן

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

שלב 1 - הבעיה הבסיסית

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

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

שלב 2 - הפתרון - Fan-out on Write

הפתרון הנפוץ הוא להפוך את הבעיה על הראש. במקום לחשב את הפיד בזמן שהמשתמש קורא אותו, מחשבים אותו מראש בזמן שמישהו מפרסם פוסט - זה נקרא Fan-out on Write, כלומר "פיזור בזמן כתיבה".

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

שלב 3 - הבעיה עם המפורסמים

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

שלב 4 - הפתרון ההיברידי

הפתרון בפועל שרוב הרשתות החברתיות הגדולות משתמשות בו הוא גישה היברידית. למשתמשים רגילים, ממשיכים עם Fan-out on Write הרגיל - כתיבה מיידית לתיבות הפיד של העוקבים. אבל למשתמשים עם כמות עוקבים עצומה - חשבונות מפורסמים, מותגים גדולים - לא כותבים לכל התיבות מראש. במקום זה, כשמשתמש רגיל פותח את הפיד שלו, המערכת בודקת בנפרד אם הוא עוקב אחרי חשבונות "גדולים", ומביאה את הפוסטים שלהם בזמן אמת (Fan-out on Read), ומשלבת אותם עם הפיד המוכן מראש.

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

שלב 5 - דירוג הפיד, לא רק סדר כרונולוגי

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

שלב 6 - אחסון והתיישנות

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

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

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

לסיכום

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