- ביוניקס ולינוקס נהוג לומר "everything is a file", אך זה למעשה לא מדויק.
- בפועל, קיימים מגוון סוגי קבצים, אמצעי אחסון פיזיים, ומערכות קבצים בעלות ממשקים שונים.
- לינוקס מספקת שכבת אבסטרקציה (VFS) כדי להציג למשתמש ממשק אחיד ונוח לעבודה מול מערכות קבצים שונות החולקות מבנה דומה.
המעבד אינו ניגש ישירות לדיסקים; הכל מנוהל דרך מערכת ההפעלה בהתאם להיררכיית הזיכרון. ניתן לתאר זאת כפירמידה: החל מאוגרים (Registers) ומטמונים (Caches) הקרובים למעבד, דרך הזיכרון הראשי (DRAM), ועד לאמצעי האחסון הפריפריאליים כגון כונני SSD, דיסקים מגנטיים (HDD) וקלטות גיבוי. ככל שיורדים בפירמידה זו, רכיבי הזיכרון זולים יותר ליחידת אחסון, איטיים יותר וגדולים יותר בנפחם.
- כונן דיסק קשיח (HDD = Hard Disk Drive) הוא התקן אחסון עמיד (Non-Volatile).
- המידע נותר על הדיסק גם ללא מתח (למשל, לאחר כיבוי המחשב).
- הדיסק בנוי בצורה מכנית מפלטות (Platters), ראשי קריאה/כתיבה, רצועות (Tracks) וסקטורים.
- זמן הגישה לנתונים בכונן זה מורכב מ"זמן חיפוש" בו הראש מגיע לרצועה הנכונה, ו"השהיה סיבובית" שהיא ההמתנה לסיבוב הפלטה כך שהמידע יעבור מתחת לראש.
- פריט טריוויה: רוחב דיסק שולחני סטנדרטי הוא 3.5 אינץ' מסיבות היסטוריות – כוננים אלו תוכננו להחליף כונני תקליטונים (Floppy) ישנים באותו תא.
- מבחינת מערכת ההפעלה, הדיסק הוא למעשה מערך של סקטורים.
- סקטור = 512 בתים רציפים המתחילים בכתובת פיזית מיושרת.
- למרות שהדיסק פועל ביחידות של סקטורים, מערכת ההפעלה מנהלת את הקבצים ביחידות גדולות יותר הנקראות בלוקים (Blocks), בדרך כלל בגודל 4KB.
הערה: למה מנהלים בלוקים של 4KB? מכיוון שזהו גודל הדף (Page / Frame) במערכת הזיכרון הווירטואלי. העברת מידע בין הדיסק לזיכרון מתבצעת באופן קבוע, ולכן נוח ויעיל יותר למערכת ההפעלה לעבוד עם שני הרכיבים באותה יחידת מידה.
כונני SSD (Solid State Drives) הם כוננים ללא חלקים מכניים, המבוססים על זיכרון Flash.
- הזיכרון בהם מחולק ל"דפים" ו-"יחידות מחיקה".
- מגבלה מרכזית: לא ניתן לכתוב מידע מחדש על גבי מידע קיים. כדי לעשות זאת, חובה למחוק יחידה שלמה תחילה. בנוסף, ישנה הגבלת מחזורי מחיקה אפשריים לפני שהתא נשחק.
- משום כך, נעשה שימוש במבנה לוגי מיוחד ובמנגנוני איסוף זבל כדי לפנות בלוקים באופן אופטימלי, מה שנעשה מאחורי הקלעים על ידי הבקר של ה-SSD.
- הקריאה בכוננים אלו טובה באופן משמעותי מ-HDD, במיוחד קריאה סדרתית בזכות מנגנוני הבאה מראש (Prefetching) ומקביליות בקריאה ממספר שבבים בו-זמנית.
- הדיסק מבטיח למערכת ההפעלה שפעולת כתיבה של סקטור בודד היא אטומית. הוא נכתב לדיסק בשלמותו או לא נכתב כלל.
- אין אטומיות ביחידות גדולות יותר: כתיבה של בלוק בגודל 4KB שדורשת 8 סקטורים עלולה להיקטע באמצע (למשל, בגלל נפילת מתח) - מה שיגרום לתוצאת "כתיבה חלקית".
- בגלל המבנה המכני של הדיסק, גישה סדרתית לסקטורים סמוכים מהירה משמעותית (בערך פי 100) מגישה אקראית למקומות מפוזרים בדיסק.
הערה: נהוג להבדיל שסקטור הוא יחידה של חומרת הדיסק, בעוד בלוק הוא יחידת העבודה הלוגית של מערכת ההפעלה.
- קובץ מוגדר בפשטות כמערך של בתים.
- סוגי קבצים (Magic Numbers): בשונה ממערכות כמו DOS/Windows שבהן זיהוי סוג הקובץ נעשה לפי הסיומת (כמו
.txtאו.exe), ב-UNIX נעזרים לרוב ב"מספר קסם" (Magic Number) המופיע בתחילת הקובץ (נניח%PDFאו#!). גישה זו אמינה יותר, אולם היא דורשת דגימה (קריאה ממשית) מתוך הדיסק אל הזיכרון גם אם רק רצינו לברר את סוגו. - האינטראקציה עם קבצים בלינוקס נעשית באמצעות סט של קריאות מערכת, ביניהן:
creat; // יצירת קובץ חדש
open; // פתיחת קובץ קיים (או יצירת חדש)
read; // קריאה מקובץ פתוח
write; // כתיבה לקובץ פתוח
close; // סגירת קובץ פתוח
unlink; // מחיקת קישור לקובץ (מחיקת הקובץ אם נמחק הקישור האחרון)
sync; // כתיבת נתונים ממטמון הדפים שב-RAM אל הדיסק הפיזי
fsync; // זהה ל-sync, עבור קובץ ספציפי (לפי FD)- מתארי קבצים (FD) מול שמות קבצים: לרוב, עדיף להשתמש בפעולות על מתאר הקובץ (FD) מרגע פתיחתו ולא בשמו של הקובץ כל פעם מחדש. שמות קבצים עלולים להשתנות או להצביע למקום אחר בזמן הריצה (סכנת סנכרון המכונה Time of Check to Time of Use), ואילו ה-FD חסין לכך משום שהוא "נעול" על הקובץ הפתוח הרלוונטי.
- עקביות סדרתית (Sequential consistency): לפי הגדרות העקביות, מערכת קבצים לרוב מבטיחה אטומיות בפעולות כתיבה כלפי קוראים מקבילים: ברגע שמתבצעת כתיבה לקובץ, קוראים אחרים יראו או את המצב שלפני הקריאה או את המצב הקודם, אך לא שמירה לא רציפה.
לכל קובץ נשמר מידע נוסף (Metadata) במבנה נתונים הנקרא inode.
ה-inode מכיל בין היתר את התכונות הבאות:
- Inode Number - מזהה ייחודי לקובץ במערכת הקבצים.
- גודל הקובץ - בבתים.
- הרשאות גישה (Permissions) - למי מותר לקרוא (r), לכתוב (w) ולהריץ (x) את הקובץ.
- קיימות גם מערכות התומכות ברשימות בקרת גישה (ACL) שמאפשרות הגדרת הרשאות פרטניות יותר לכל משתמש מעבר לרובד הבסיסי, אך זה אינו חלק מתקן POSIX המחייב, מה שלעתים יוצר בעיות ניידות (Portability) בין מערכות דמויות UNIX.
- חותמות זמן (Timestamps) - מתי נוצר, שונה, או נקרא לאחרונה.
- מיקום בדיסק - מצביעים לסקטורים / בלוקים בדיסק המכילים את המידע.
הערה: ה-inode אינו שומר את שם הקובץ כי לאותו קובץ יכולים להיות מספר שמות שונים באמצעות קישורים. שם הקובץ (ליתר דיוק, שם הקישור) נשמר בתיקיה המכילה אותו.
- תיקייה (Directory) היא סוג מיוחד של קובץ, אשר התוכן שלו הוא למעשה מערך רשומות.
- כל רשומה מהווה מיפוי מהצורה:
מספר Inode$\rightarrow$ שם קובץ. - כל תיקייה מכילה תמיד שתי רשומות שמורות:
-
.(נקודה) - מצביעה לתיקייה הנוכחית. -
..(שתי נקודות) - מצביעה לתיקיית האב.
-
הערה: בתיקיית השורש
/, הרשומה..מצביעה לעצמה (תיקיית השורש). כמות הקישורים הקשיחים המינימלית לכל תיקייה ביוניקס היא תמיד 2 (השם שלה מתיקיות האב + הקישור הפנימי.), והמקסימום עולה עם כל תת-תיקייה שנוצרת ומפנה אליה בחזרה דרך...
- התיקיות יוצרות היררכיה בכך שהן מצביעות לקבצים ותיקיות נוספות.
- לינוקס מארגנת את הכל למבנה עץ יחיד.
- שורש העץ הוא התיקייה ששמה
/. - ההתייחסות לקבצים נעשית לפי נתיבים:
-
נתיב אבסולוטי - למשל
/usr/bin/python. -
נתיב יחסי - תלוי בתיקייה השוטפת, למשל
../documents/file.txt.
-
נתיב אבסולוטי - למשל
-
פתרון נתיבים (Path resolution /
namei): מערכת ההפעלה מעבדת את הנתיב רכיב אחרי רכיב. כדי להגיע לקובץ בקצה, היא מחפשת בכל תיקייה שרשומה בדרך. זמן הריצה של חיפוש זה חסום מלמטה על ידי$O(n)$ בגלל החיפוש בתוך בלוקי הנתונים של כל תיקייה בדרך בניסיון לאתר את השם הכתוב.
- ניתן ליצור או להסיר תיקיות עם הפקודות (וקריאות המערכת המקבילות):
mkdir dir_name # יצירת תיקיה
rmdir dir_name # הסרת תיקיה (רק אם היא ריקה)- תהליך הקריאה/כתיבה לתיקיות מוגבל:
- לא ניתן להשתמש ב-
read/writeבקובץ מסוג תיקייה באופן ישיר, כיוון שמערכת ההפעלה מסתירה את מימוש המבנה של התיקייה. עץ הקבצים בכל מערכת קבצים פועל קצת אחרת. - ניתן לקרוא את תוכן התיקייה אך ורק בעזרת קריאת המערכת
getdentsשמחזירה רשומות. - ניתן לכתוב לתיקייה אך ורק בעקיפין, באמצעות יצירת קובץ או קישור חדשים בתוכה.
- לא ניתן להשתמש ב-
קיימות שתי שיטות לקשר יחדיו שם קובץ אל קובץ קצה:
- קישור קשיח (Hard Link) - מבוסס על שיתוף Inode:
ln src_file dst_link
- מהווה "שם נרדף" ישיר לקובץ. הקישור יוצר רשומה בתיקיה שמצביעה על אותו Inode של התוכן.
- כתיבה לקישור תשפיע ישירות על הקובץ המקורי.
- מחיקת קישור מקטינה את ה"מונה" (
link count) שבתוך ה-Inode.- תכולת הקובץ תימחק סופית מהדיסק אך ורק כאשר מונה הקישורים יגיע לאפס.
- קישור רך / סימבולי (Soft / Symbolic Link) - מבוסס על Inode חדש:
ln -s src_file dst_link
- מהווה קובץ חדש כשלעצמו (עם Inode משלו), בו נכתב הנתיב לקובץ המטרה.
- במערכות מודרניות כמו
ext4, אם נתיב היעד קצר יחסית (עד 60 בתים), המחרוזת של הנתיב נשמרת ישירות בתוך ה-Inode עצמו (נקרא Inlined) במקום שתשמר בבלוק נתונים חדש. שיטה זו חוסכת I/O בגישות בהמשך וכן מקום בדיסק.- כמו בקשיח, כתיבה דרך הקישור תשפיע על המקור.
- מחיקת קובץ הסימלינק (בד"כ באמצעות
rm) פשוט תמחק אותו כרגיל. אם קובץ המקור נמחק, הסימלינק הופך ל"שבור".- ניתן ליצור קישור סימבולי לנתיב שבכלל אינו קיים כרגע.
| תכונה | קישור קשיח (Hard Link) | קישור רך (Soft Link) |
|---|---|---|
| הצבעה לתיקיות | לרוב לא אפשרי ❌ (חריג יורחב בהמשך) | אפשרי ✅ |
| חציית מערכות קבצים | לא אפשרי (מספרי inode אינם גלובליים) ❌ | אפשרי (ניתן לקשר בין דיסקים שונים) ✅ |
| קישור שבור | לא יכול להיות "שבור" ❌ | יכול להיות "שבור" (קובץ המטרה לא קיים) ✅ |
| מעגליות | מונע מעגלים ❌ | עלול ליצור מעגלים במערכת הקבצים ✅ |
הסיבה העיקרית שמערכת ההפעלה אוסרת על יצירת קישורים קשיחים לתיקיות היא מניעת מעגלים ובעיות מבניות בעץ הקבצים:
חריג לנוהל (Time Machine): למרות האיסור, ישנן מערכות בעלות מימוש ייחודי כמו HFS+ של Apple, אשר כן מתירות למערכת ההפעלה לגזור קישורים קשיחים לתיקיות מטעמי תחזוקה, על מנת לתמוך במנגנוני גיבוי אחורנית קלילים כמו Time Machine מבלי לשכפל נתונים.
- בלבול קשרי המשפחה: לא ניתן להגדיר תיקיית אב אחת ויחידה. למשל, הדוגמה הבאה יוצרת קישור לתיקיית האב בתוך התיקיה עצמה:
cd /A
ln /A loopכעת /A היא תיקיית האב של loop, אך כך גם /A/loop.
- אינסוף מסלולים ורקורסיה: פעולות שסורקות את עץ התיקיות עלולות להיקלע ללולאה אינסופית, למשל בעת בנייה או הדפסה של נתיבים:
/A/loop
/A/loop/loop
/A/loop/loop/loop
...הערה: הבעיה הזו קיימת טכנית בקישורים רכים שמצביעים לתיקיות. לינוקס מתמודדת איתה באמצעות מנגנונים שמגבילים את עומק המעבר על קישורים סימבוליים וזיהוי מעגלים תוך כדי ריצה כדי להימנע מרקורסיה אינסופית.
כדי להבין לעומק כיצד קבצים ותיקיות נשמרים בפועל, נבדוק כיצד בנויה מערכת קבצים בצורה מפושטת. מסגרת זו (VSFS) נועדה לדמות את המבנה של מערכת הקבצים המקורית ב-UNIX, וכך להמחיש מושגי יסוד:
- מבני נתונים: כיצד המידע מאורגן על הדיסק מבחינה פיזית ולוגית.
- אופני גישה: כיצד קריאות מערכת (
open,read,write) משתמשות במבנים אלו "מאחורי הקלעים".
מערכת הקבצים ממומשת כולה בתוכנה. נבנה אותה ב-5 שלבים מדורגים, מהרמה הבסיסית ביותר של מבנה הדיסק ועד למנגנוני ניהול המידע:
הדיסק מורכב חומרתית מיחידות אחסון קטנות מאוד הנקראות סקטורים (512 בתים כל אחד). עם זאת, ברמת ניהול מערכת ההפעלה - התעסקות עם מיליוני חלקים זעירים היא פעולה שיכולה לגזול משאבים וניהול כבד.
לכן, מערכת ההפעלה מאגדת סקטורים ומנהלת את הדיסק בבלוקים של 4KB (4096 בתים). גודל זה נבחר בכוונה כדי להיות תואם לגודל הדפים בזיכרון הווירטואלי, מה שמייעל משמעותית את המעבר של נתונים בין הדיסק (אחסון) לזיכרון הראשי (RAM).
לצורך הדוגמה, נניח שהדיסק שלנו הוא קטן במיוחד, ומכיל 64 בלוקים בסך הכל.
- חלוקה זו מקנה לדיסק שלנו גודל כולל של:
$64 \times 4KB = 256KB$ .
מטרת העל של דיסק היא לאחסן מידע של המשתמשים (מסמכי טקסט, קטעי וידאו, תוכנות וכו'). זהו המידע הגולמי, ולשם כך המערכת יוצרת אזור מרכזי שנקרא אזור הנתונים (Data Region).
- במערכת VSFS שיצרנו, נקדיש את מרבית הדיסק - 56 בלוקים - לטובת אזור הנתונים (זה אומר ש-8 הבלוקים הנותרים יוקדשו למבני ניהול פנימיים "מעל" ולמטא-דאטא).
- ככלל אצבע, השאיפה של כל מערכת קבצים בעולם האמיתי היא להקדיש אחוז ניכר ככל הניתן מנפח הדיסק לטובת אזור הנתונים.
מידע כשלעצמו לא מספיק. אם נאחסן סתם כך רצף של ביטים באזור הנתונים בבלוק אקראי, מערכת ההפעלה לא תוכל לדעת לאיזה קובץ הוא בדיוק שייך, אילו הרשאות יש עליו, מה הגודל שלו וכו'. עבור מידע מנהלתי זה (Metadata) נשמר המבנה שנקרא inode.
- כל קובץ חי במערכת חייב שיהיה לו בדיוק
inodeאחד המקושר אליו. - ה-inodes מאורגנים על הדיסק במערך רציף הנקרא "טבלת Inodes", שתתפוס במערכת VSFS שלנו את רוב מה שנשאר: 5 בלוקים (מתוך ה-8 הנותרים).
- גודל כל
inodeבודד יהיה128 Bytes. הוא כולל מצביעים ישירים שאומרים איזה בלוקים ב-Data Region בדיוק שייכים אליו.
שאלה: מהו מספר הקבצים המקסימלי האפשרי במערכת VSFS שיצרנו? תשובה: נחשב כמה Inodes יכולים טכנית להיכנס לתוך אותם 5 בלוקים. ידוע כי כל בלוק שוקל
$4096B$ וידוע כי כל Inode שוקל$128B$ :$\frac{5 \times 4096B}{128B} = 160$ Inodes. מכיוון שכל קובץ דורש Inode אחד בלבד לניהול שלו, סך הכל ניתן לייצג במערכת זו עד 160 קבצים במקביל.
עכשיו שיש לנו תשתית לנתונים ותשתית לניהול התכונות (Inodes), מערכת ההפעלה צריכה דרך לדעת מהר - אילו מהם פנויים ולמי מותר לכתוב רגע זה?
במקום לעבור על כל הדיסק או לסרוק את כל אזור הנתונים או טבלת ה-Inodes בכל פעם שצריך מקום, VSFS משתמשת בשתי מפות יעילות - מערכי ביטים (Bitmaps). אלו פשוט רצפים של ביטים שבהם: 0 מציין משאב פנוי, ו-1 מציין שמדובר בבלוק שכבר כותבים/קראו ממנו משאב תפוס.
- נעשה שימוש ב-Bitmap לאזור הנתונים (יקבל בלוק אחד שלם).
- ועוד Bitmap לטבלת ה-Inodes (ויקבל בלוק אחד שלם).
שאלה: האם בלוק אחד לכל מערך ביטים הוא מספיק? תשובה: בהחלט, ולמעשה יש בו אפילו בזבוז שטחים עצום (Overkill). בלוק של
4KBמכיל לא פחות מ-32,768 ביטים! זאת אומרת שהוא מסוגל באופן תיאורטי לייצג מפה עבור מעל ל-32,000 אובייקטים פנויים או תפוסים. במערכת VSFS שלנו יש כזכור רק 56 בלוקים לנתונים (56 ביטים בשימוש) ו-160 Inodes למעקב. בכל זאת, VSFS מעדיפה לטובת "פשטות המימוש" ולשרוף בלוק שלם במלואו עבור כל אחת מהמפות.
הגענו לבלוק האחרון במסגרת שלנו - למעשה, זהו בדרך כלל הבלוק הראשון (בלוק 0) בדיסק: מצפון לכולם יושב ה-Superblock (הסופר-בלוק). זהו "מרכז הבקרה" של הדיסק הכולל את "תעודת הזהות" וכללי התשתית ההכרחיים על מערכת הקבצים כולה. מידע זה יכלול בין היתר:
- מהו גודלה הכולל של מערכת הקבצים? (הכמות הכוללת של בלוקי נתונים וInodes).
- באיזה מספר בלוק מתחילה רשמית טבלת ה-Inodes.
- מהו הכתובת של ה-Inode השייך לתיקיית השורש העליונה (
/) כדי שנוכל להתחיל לנווט בעץ.
לפני שניתן לקרוא קבצים מהדיסק בפעם הראשונה (בפעולה הנקראת mount), מערכת ההפעלה מוכרחה לקרוא תחילה את הסופר-בלוק במלואו לתוך הזיכרון הראשי (RAM) על מנת להבין איך לגשת ולקרוא את מבני הקבצים ושאר הדיסק.
שאלה: פעמים רבות הסופר-בלוק יגובה על ידי מערכת ההפעלה במספר רב של עותקים רזרביים ברחבי הדיסק. מה הסיבה לכך? תשובה: לצורכי יתירות ועמידות בפני שגיאות. הסופרבלוק מכיל התוויה קריטית של מבנה הדיסק. אם נתון ה-Superblock ייפגם או יימחק (Data Corruption), הדיסק יהפוך ל"מת" - לא יהיה ניתן לעגן או לקרוא מתוכו דבר, בהיעדר המפות ומיקומי ההתחלה הדרושים כדי לאתר את המידע. לגבות עותקים שלו זהו ביטוח חובה!
מערכת ההפעלה לינוקס מאפשרת להוסיף מערכות קבצים שונים (מדסקים או התקנים חיצוניים) ולשלב אותם לתוך עץ היררכיה מרכזי ויחיד.
הרכבה וניתוק מתבצעות על ידי קריאות המערכת mount ו-unmount ודורשות הרשאות מנהל מתאימות.
- נקודת הרכבה (Mount Point): ההרכבה מתבצעת על גבי תיקייה קיימת (לרוב ריקה) בעץ הנוכחי. מרגע זה, ההתקן החיצוני "מורכב" על התיקייה הזו.
- הסתרת קבצים זמנית: לאחר ההרכבה, לא ניתן לגשת לקבצים או לתיקיות שהיו במקור תחת תיקיית ההרכבה. הם כביכול "מוסתרים" מתחת למערכת החדשה.
- ניתוק (Unmount): לאחר ניתוק ההתקן, התיקייה המקורית שלנו חוזרת למצבה הקודם וניתן לגשת שוב לקבצים שהיו בה.
- הרכבות מקוננות ("כמו מחסנית"): אם הרכבנו מספר מערכות קבצים על אותה נקודת הרכבה אחת אחרי השנייה, בכל ניתוק של מערכת נחזור למערכת הקבצים שהייתה שם רגע לפני ההרכבה שלה.
- ריבוי נקודות הרכבה: לינוקס מאפשרת לקחת את אותה מערכת קבצים פיזית ולהרכיב אותה במספר נקודות הרכבה שונות במקביל בעץ. זה מאפשר גישה לאותו מידע חיצוני במספר paths במקביל.
נניח ששורש העץ / מנוהל על ידי מערכת הקבצים המרכזית במחשב (מסוג ext4).
אנו רוצים להרכיב התקן Disk-On-Key שאליו חובר המחשב.
תיקיית ההרכבה תיבחר להיות /mnt/usb, והיא תשמש למעשה כתיקיית השורש של מערכת הקבצים שעל ה-USB. תחת מצב זה, ניתן יהיה לגשת למידע של ההתקן פשוט על ידי נתיב דוגמת /mnt/usb/my_photos.
מערכת ההפעלה מאתרת קבצים לפי ה-inode שלהם. בהינתן מספר Inode, מנוע הקבצים יודע לחשב בדיוק היכן הוא יושב על הדיסק הפיזי.
הסקטור שבו נמצא ה-inode מחושב באמצעות שתי נוסחאות פשוטות:
- חישוב הכתובת הפיזית בבתים:
- מציאת הסקטור: מחלקים את הכתובת שמצאנו בגודל של סקטור:
לאחר שמערכת ההפעלה קראה את הסקטור הזה משטח האחסון ומצאה את ה-inode, יש בידיה את כל המידע והמצביעים הנדרשים כדי להמשיך ולקרוא את הנתונים בפועל.
קובץ בסופו של דבר מורכב מבלוקים שמפוזרים על הדיסק. הדרך הפשוטה ביותר לדעת אילו בלוקים שייכים לקובץ היא לפזר מצביעים בתוך ה-inode עצמו (כל מצביע הוא בסך הכל מספר של בלוק נתונים באזור הנתונים).
- מצביעים ישירים (Direct Pointers): לדוגמה, סוג inode הבסיסי של
ext2שומר 12 מצביעים ישירים.
מגבלת גודל: מה המגבלת גודל לקובץ שניתן לכסות באותם מצביעים ישירים? כיוון שבלוק סטנדרטי מונה 4KB, הגודל המקסימלי במצביעים אלו יהיה בלבד:
$12 \times 4KB = 48KB$ .
הפתרון לקבצים גדולים - מצביעים לא-ישירים (Indirect Pointers): כדי להתגבר על מבנה ה-inode הקטן ולשמור קבצים גדולים בהרבה מ-48KB, הוסיפו מנגנון מדורג. מערכת הקבצים שומרת מצביעים נוספים בבלוקים רגילים באזור הנתונים (האזור הרחב ביותר במערכת):
- מצביע לא-ישיר (Indirect Pointer): מצביע שנמצא ב-inode ומוביל לבלוק אחר באזור הנתונים. כל מה שהבלוק הזה מכיל הם רק מצביעים ישירים נוספים.
- מצביע לא-ישיר כפול (Double Indirect): מצביע ב-inode שמוביל לבלוק שמכיל מצביעים לא ישירים. כל אחד מהם מצביע לבלוק עם מצביעים ישירים, והם בתורם לחלקות הקובץ המקוריות.
-
מצביע לא-ישיר משולש (Triple Indirect): מדרגה נוספת (מצביע
$\leftarrow$ בלוק מצביעים לא ישירים כפולים$\leftarrow$ בלוק מצביעים לא ישירים רגילים$\leftarrow$ בלוק מצביעים ישירים$\leftarrow$ נתונים).
עם התפתחות מערכות הקבצים המודרניות (כמו בעדכוני ext4), התברר כי למצביעים ישירים ולא-ישירים ישנה תקורה מסוימת כשהקבצים תופסים חלקי נתונים פנויים ארוכים ברצף.
במקום לשמור מצביע נפרד לכל בלוק ובלוק בנפרד (מה שידרוש גם הרבה גישות כדי לבדוק ולחלוף עליו), ה-Inode המודרני שומר צמדים של רצפים, מה שנקרא Extents: (מצביע להתחלת הרצף, אורך הרצף).
- יתרון: משפר משמעותית גישה סדרתית, מצמצם את גודל הרשומות והמצביעים.
- חיסרון: הדבר דורש מהמערכת או מהקרנל מנגנון שחוזה מראש (Predict/Preallocate) את המרחב הרציף המבוקש. כמו כן, אם קובץ נרשם עם אורכים שהוא מעולם לא השלים, הוא עשוי ליצור פרגמנטציה פנימית או לבזבז שטחים במקרי קיצון.
סטטיסטיקה מרכזית וחשובה שעמדה במבחן המציאות בארכיטקטורות ומכתיבה את תכנון מצביעי ה-Inode הנ"ל: השונות בין כמות למסה בדיסק. מסתבר שכ-90% מסך הקבצים הקיימים במערכת הם קטנים מאוד (נמוכים מ-16KB ונתמכים כמעט רק על ידי מצביעים ישירים). לעומת זאת באותו המחשב - כ-90% מנפח הדיסק התפוס פיזית שייך לקבוצה זעירה של כ-10% קבצים ענקיים במיוחד (אלו שדווקא נשענים על מצביעים לא ישירים רבים ורשימות מקושרות).
כעת נניח כי מערכת הקבצים VSFS עגונה ומורכבת בדיסק. בשלב זה, רק ה-Superblock כבר נמצא נקרא לתוך הזיכרון הראשי (RAM) במהלך פעולת ה-mount. כל שאר הנתונים (הקבצים, התיקיות, ה-inodes התופסים אותם) עדיין נמצאים בדיסק.
נבחן סדרות פעולות שגרתיות ונעקוב אחר החישתן למערכת הקבצים (מספר הגישות והקריאות לפיזיות מול הדיסק).
בקריאת קוד העוקבת אחר פתיחה וקריאה של הקובץ הבא:
int fd = open("/foo/bar", O_RDONLY);
read(fd, buffer, 4096);
read(fd, buffer, 4096);
read(fd, buffer, 4096);אבחנה מוקדמת: פתיחת קובץ קיים לצורך קריאה לא מערבת כלל גישה ל-Bitmaps, שכן אין הקצאה של משאבים חדשים.
שלבי פעולת ה-open (סריקת המסלול לפתיחה):
כדי לפתוח את /foo/bar, המערכת חייבת לוודא הרשאות גישה בסדר היררכי מהשורש ועד לקובץ עצמו:
- עיון ב-inode של תיקיית השורש (
/): כתובתו ידועה מראש (מה-Superblock בזיכרון). המערכת קוראת את ה-inode מהדיסק. - חיפוש התיקייה
fooבשורש: המערכת קוראת את בלוקי הנתונים של השורש מהדיסק (שהם למעשה רשומות המיפוי), ומחפשת כניסה עבורfoo. הכניסה הנמצאת תחזיק את מספר ה-inode של התיקייהfoo. - עיון ב-inode של
foo: המערכת קוראת את ה-inode שלfooמהדיסק, ובודקת שלמשתמש יש הרשאת גישה לתיקייה. - חיפוש הקובץ
barבתוךfoo: המערכת קוראת את בלוקי הנתונים של תיקייתfooומאתרת את כניסתו של הקובץbarכדי לקבל את מספר ה-inode שלו. - עיון ב-inode של
bar: השלב האחרון – קריאת ה-inode שלbarעצמו מתוך הדיסק ואימות הרשאות הקריאה הסופיות. הפונקציה מחזירה את מתאר הקובץ (fd).
הערה חשובה לגבי חותמת זמן: באלגוריתם הסטנדרטי והבסיסי של VSFS, המערכת לא מעדכנת את חותמת הזמן (Timestamp) של התיקיות לאורך המסלול (
/ואזfoo), אפילו שהיא מבצעת קריאה ממשית לנתונים שלהן. מערכות קבצים מתקדמות יותר עשויות להתנהג אחרת (למשלatime).
שלבי פעולת ה-read (3 הפעמים בדוגמה):
קריאת תוכן הקובץ מתבצעת כעת בעזרת ה-fd:
- מיקום הבלוק: קריאת ה-inode של
barכדי לאתר איזה בלוק נתונים מהווה את החלק המבוקש. - קריאת הנתונים: קריאה ישירה מדיסק של בלוק הנתונים אל ה-buffer של המשתמש.
- עדכון מטא-דאטא: כתיבה חזרה ל-inode של
barכדי לעדכן את חותמת הזמן של "הגישה האחרונה" (Last Access Time) לקובץ זה פנימית.
- התהליך אורך לפי כמות הפעמים שנידרש לקרוא בלוקים.
כעת נרד לפרטים של פעולת יצירה (Creative) כתיבה.
int fd = open("/foo/bar", O_CREAT | O_WRONLY | O_TRUNC);
write(fd, buffer, 4096);
write(fd, buffer, 4096);שלבי פעולת ה-open ביצירת קובץ חדש:
זוהי חזרה על כל השלבים בסעיף ה-Read הקודם, עד ההגעה לתיקיית היעד (foo), פלוס התהליך המחייב הקצאה למערכת הקבצים:
- גישה ל-Inode Bitmap: קריאת ה-Bitmap מהדיסק כדי לאתר Inode פנוי לקובץ החדש.
- סימון תפוסות (Allocated): המערכת מסמנת את ה-inode ב-Bitmap כ"תפוס" (1) וכותבת בחזרה את ה-Bitmap לדיסק להתעדכן.
-
אתחול ה-inode לחומרה:
ה-inode הוא גודל קטן יותר מסקטור הדיסק הפיזי הרגיל (128 בתים לעומת 512). על כן, למערכת אין ברירה אלא לקרוא מהדיסק את הסקטור השלם המכיל את אזור ה-inode שהוקצה, להלביש עליו את אתחול ה-inode החדש של הקובץ, ולכתוב בחזרה (Write-back) את השארית השלמה לדיסק המוקצה.
-
רישום הקובץ בתיקייה (Directory Entry): שנוי תוכן בלוק הנתונים של התיקיה
fooעל ידי כתיבה, והוספת צמד הרשומה (שםbar$\rightarrow$ מספר Inode החדש). -
עדכון התיקייה: קריאה וכתיבה מחדש גם ל-inode של
fooעצמו כדי לעדכן את חותמות הזמן והשינויים בתוכנו.
שלבי פעולת ה-write לקובץ חדש (על כל קריאה):
- גישה ל-Data Bitmap: קריאת ה-Bitmap המסמן אילו בלוקים באזור הנתונים פנויים.
- הקצאת הבלוק לשימוש: סימונו ב-Bitmap כ"תפוס" וכתיבת ה-Bitmap המעודכן בחזרה אל הדיסק.
- יצירת החוליה ההכוונה: קריאה של Inode של הקובץ
bar, כתיבת השיוך של בלוק הנתונים החדש לתוך מצביע ב-Inode שלו, ושמירה של שינוי מטא-הנתונים חזרה על הדיסק. - כתיבה בפועל (The Payload): רק לבסוף, לכתוב על גבי הדיסק את המידע הנחוץ שמסתתר בתוך ה-Buffer ישירות לאזור הנתונים.
כפי שניתן לראות בקלות לעיל, פעולות קריאות המערכת הפשוטות ביותר גוררות כמות אדירה של גישות (I/O) לדיסק כדי לעדכן את מבני הנתונים (רק יצירת הקובץ וחיפושו לבד נתמכו בכ-10 גישות ארוכות לדיסק טרם הספקנו לכתוב ביט מידע אחד).
כיוון שזמן חיפוש ותגובה (Seek / Latency Access) של דיסקים הינו צוואר הבקבוק המהותי, מערכת ההפעלה בלינוקס שומרת ומנהלת מערכי משנה של מטמון פנימי בתוך הזיכרון החכם (RAM):
- מטמון דפים (Page Cache): שומר פיסות של מידע נבחר שנקרא מתוך אזור הנתונים באופן תדיר במרכז מטמון דפים. זה חוסך לגשת חזרה לקבצי מידע שלא השתנו.
- מטמון אינודים (Inode Cache): עבור המידע הרציף של טבלת ה-inodes, כך שלמשל תיקיית השורש
/וחבריה לא תיקרא מהדיסק שוב ושוב עבור כל נתיב במחשב. - חלקי מטמונים ומבנים תדירים נוספים נכתבים לטובת ה-Bitmaps ואחרים. זהו הבסיס לביצועים חזקים של מערכת ההפעלה בעבודה מול אמצעי אחסון מכניים.
FAT הוא שם כולל למשפחת מערכות קבצים שפותחה במקור על ידי חברת מיקרוסופט עבור מערכת ההפעלה הגרפית DOS. המערכת קרויה למעשה על שם מבנה הנתונים המרכזי והיחיד שבו היא משתמשת - במקום לעבוד עם Inodes כמו ב-Linux, היא עושה שימוש בטבלת הקצאת קבצים (File Allocation Table).
- בגלל הפשטות והקלות היחסית של יישומה במערכות חלשות, היא אומצה במהרה והפכה לסטנדרט עבור כוננים ניידים שונים.
- גם היום, מערכת הקבצים מבוססת-FAT עדיין נמצאת בשימוש יום-יומי עצום ונרחב ביותר בהתקני זיכרון הבזק ניידים - דוגמת כונני דיסק-און-קי וכרטיסי MicroSD.
נשתמש ב-FAT כדוגמה חלופית לאיך ניתן לממש ולשמור קבצים בדיסק ללא שימוש ב-Inodes.
כזכור, בעולם של VSFS ו-UNIX למדנו כי מצביעי הבלוקים של כל קובץ חיים בתוך ה-inode שלו.
לעומת זאת, מערכת הקבצים FAT מוותרת על פריקתן של מאגר נתונים ומאחסנת את בלוקי הקבצים בצורה של רשימה מקושרת.
כל הרשימות המקושרות הללו של כלל הקבצים במחשב נשמרות בצורה מרוכזת בטבלת ה-FAT. טבלה זו ממוקמת תמיד בתחילת הדיסק הפיזי.
מבנה הדיסק הוא:
| superblock | FAT | data region |
|---|
- הערות למבנה: FAT היא טבלה גלובלית אחת. כל קבצי המערכת שמורים בה, והיא בעצם "מדביקה" יחד את כל הבלוקים של קובץ לידי יחידה אחת משמעותית של ידע, ומבדילה אותו מקבצים אחרים.
טבלת ה-FAT מתפקדת גם כ"מפת ביטים" (Bitmap) וגם כ"טבלת מיפוי". היא שומרת כניסה (Entry) נפרדת עבור כל בלוק בדיסק. עבור כל כניסה בטבלה, התוכן מגדיר מיהו הבלוק הבא בשרשרת השייך לאותו הקובץ. משמעות הערכים בטבלה:
- מספר חיובי: מצביע שמפנה מידית למספר של הבלוק הבא השייך לאותו קובץ ברשימה.
FF: זהו עוגן מיוחד המסמן שורת סוף - כלומר, זהו הבלוק האחרון ברשימה עבור הקובץ הנתון.0: מספר המייצג שזהו בלוק פנוי לגמרי שניתן למלא אליו מידע חדש (תחליף מושלם ל-Bitmaps).-1: מסמן שזהו בלוק פגום ואין להשתמש בו לאחסון בשל סכנת איבוד נתונים.
תיקיות ב-FAT הם קבצים רגילים אשר מכילים רשומות מסוג:
| filename | metadata | starting block |
|---|---|---|
| ... | ... | ... |
| ... | ... | ... |
| ... | ... | ... |
-
כל רשומה מכילה את ה-metadata על הקובץ.
- המשמעות: ה-inode כאילו מוטמע בתוך הרשומה.
-
לכן מערכות קבצים מסוג FAT לא תומכות בקישורים קשים.
בעולם התעשייה וחוות השרתים, דיסק קשיח בודד אינו מספיק מכמה סיבות:
- קיבולת מטרה: יש גבול לנפח שניתן לדחוס לתוך רכיב מכני יחיד.
- אמינות (Reliability): דיסק קשיח הוא רכיב מכני המועד לבלאי טבעי ולקריסה. אחסון מידע קריטי על דיסק בודד מהווה נקודת כשל בודדת (Single Point of Failure). מעריך הזמן בין תקלות (MTTF - Mean Time To Failure) לדיסק בודד אינו מספק.
- ביצועים (Performance): רוחב הפס של הקריאה והכתיבה וזמני ההשהיה (Seek / Rotational) המוכרחים בדיסק בודד יוצרים צווארי בקבוק משמעותיים בקצב העיבוד.
כדי לפתור בעיות אלו, נולדה ארכיטקטורת RAID. הרעיון המרכזי הוא לקחת מספר כוננים קשיחים פיזיים (בלתי תלויים לחלוטין) ולאגד אותם יחד ברמת החומרה או התוכנה, כך שיפעלו כמקשה לוגית אחת גדולה ומשותפת. מערכת הפעלה אינה צריכה לדעת שהיא עובדת מול עשרות דיסקים – בקר ה-RAID מסתיר את המימוש, ומציג בפניה "דיסק וירטואלי" יחיד ומהיר.
היתרון של RAID נמדד ביכולתו לספק יתירות (Redundancy) המסייעת להתאוששות מאובדן נתונים, ופעולות I/O במקביל שמשפרות ביצועים. במהלך השנים פותחו מספר "רמות" (Levels) של RAID, המייצגות פשרות (Trade-offs) שונות בין ביצועים, מקום מבוזבז (Overhead) ויכולת שרידות.
הדרך הפשוטה ביותר לאגד דיסקים, ממוקדת נטו בשיפור ביצועים וקיבולת.
- אופן הפעולה (Striping): מחלקים את תזרים הנתונים לבלוקים (הנקראים Chunks או Stripes). במקום לכתוב לפי הסדר קובץ שלם בדיסק אחד, הנתונים מחולקים ונכתבים במקביל למספר דיסקים שונים.
- יתרון ביצועים: מכיוון שמפזרים העבודה מול דיסקים שונים לחלוטין שמסוגלים לעבוד כל אחד עצמאית, אנו מקבלים פוטנציאל הכפלה תיאורטי של רוחב הפס ורמת המקביליות – ביצירת פעולות קריאה/כתיבה גם יחד.
- קיבולת: ניצולת של 100% מסך הדיסקים במערך.
- החיסרון המכריע: אין יתירות! ישנה 0 יתירות. למעשה, האמינות פוחתת ביחס לדיסק בודד בהרבה – ברגע שכונן בודד אחד במסגרת ה-RAID-0 קורס, כל בלוק שכתוב בו אובד, וכתוצאה מכך הקבצים שמפוזרים דרכו נהרסים וישנה השחתת מידע במערך כולו מן הלקות של הרכבה.
מתעדפת יציבות מוחלטת והימנעות מוחלטת לאובדן מידע ככל הניתן.
- אופן הפעולה (Mirroring): כל קובץ, בלוק או פיסת נתון שנכתבת מהמערכת תועתק בהכרח באופן סימטרי לחלוטין לשני דיסקים או יותר ("השתקפות" מושלמת שנוצרת בזמן-אמת כל פעם).
- יתרון שרידות ואמינות: רמת העמידות היא הגבוהה ביותר. המערך ישרוד אובדן של כוננים, כל עוד אלו שנשארו חיים עדיין מחזיקים לפחות מראה מלאה אחת ואחרונה של כלל הקבצים. במקרה קריסת דיסק עקב פגם נחליפו והכל מועתק אוטומטית שוב. זמן התאוששות קצר ביותר.
- ביצועים: הקריאה מרוויחה – נדגום פנויים מבין כונני התמונות במקביל. הכתיבות – עלולות לעלות שכן בכל שינוי מידע על השרת לבצע מנגנון כתיבה מרובה בכל התמונות בו-זמנית.
- החיסרון הקריטי (קיבולת ועלות): בזבוז מזעזע של שטח אחסון. השלכת חצי נפח הדיסקים תמיד לגיבוי פסיבי מתמיד ללא הצדקת מידע ייחודי נוסף. (ניצולת לכל היותר 50% בלבד).
הערה לגבי RAID-2 ו-RAID-3: רמות אלו חילקו את המידע ברזולוציה של ביטים ובתים (בהתאמה) במקום בבלוקים שלמים. הן דרשו סנכרון מכני מדויק, כך שכל הדיסקים יסתובבו יחד באותו הקצב בדיוק (Lockstep). עקב המורכבות החומרתית והיעדר הגמישות, תצורות אלו כמעט ואינן בשימוש כיום ("almost never used").
ניסיון לאזן את הטריידאוף שבין "חיסכון במקום" לפיזור לבין תצפיות אמינותיות, בעזרת חישוב לוגיקה אלגברית – Parity (זוגיות). מיושם בתצורה של מערך משולב.
- אופן הפעולה: משתמש בפריסת פסים בדומה ל-RAID-0 לשאר הדיסקים, אבל מציידת דיסק אחד ויחיד נפרד שישמש במיוחד ורק לאחסון בלוקי "הזוגיות". חלוקת הזוגיות נקבעת לרב ברמת פיסת הנתון תוך שימוש באופרטור הלוגי המהיר ⨁ (XOR – Exclusive OR) משאר שורות הבלוקים מהדיסקים ברחבי שכבות המערך באותה הרצועה.
- יתרון הקיבולת והיתירות: המערך חסין בפני הפלה וכשל של הדיסק אחד ויחיד בלבד באותו זמן. גם אם דיסק הנתונים נהרס, חישוב XOR מתמטי הפוך בין שאר הדיסקים החיים ועל בלוק הזוגיות שיושב על הדיסק המאובטח יכול לשחזר בדיוק רב אילו קבצים אבדו שם! במקביל, מאבדים רק את גודל נפחו של אותו דיסק הזוגיות הבודד, מה שלפחות מאפשר שמירה על רוב השטח הרחב בניצולת (ולא חצי כמו ב-Mirroring).
- הבעיה הרצינית (The Small Write Problem): למרות שיש שיפור בנפח על חשבון ביצועי שחזור משוערים, קיים צוואר-בקבוק יסודי: כל עדכון זעיר בקובץ ספציפי בכונן אחד מהשאר, מחייב שינוי תואם ואקטיבי בדיסק ה"זוגיות" באותו השלב כדי שהתלולית תיוותר נאמנה. מכאן עולה שבמערכת פעילה ועמוסה ב"כתיבות קטנות" מצד המשתמשים השונים במקביל, למרות שכל כונן חופשי לכשלעצמו, כולם ייאלצו להמתין בתור לכונן אחד (דיסק ה-Parity) תמיד, אשר אליו תמוקצענה כלל משימות הכתיבת הזוגיות השגרתית שתחנוק את קצבו.
בא לפתור בצורה חכמה ואופטימלית את עקשן צוואר-הבקבוק המתואר ב-RAID-4, והפך בשל כך לסטנדרט התעשייתי.
- אופן הפעולה: במקום לייעד "דיסק יחיד" הסופג את כלל פעולות הזיכוך (הזוגיות), המערכת מחלקת כעת את בלוקי או רצועות החישוב של הזוגיות באופן מבוזר (Distributed) על פני כל הדיסקים במערך ברוטציה מחזורית וסימטרית. (למשל, עבור שורה 0 דיסק 4 שומר זוגיות, שורה 1 – דיסק 3 שומר זוגיות וחוזר חלילה).
- יתרונות: שימרנו את החסינות החשובה לפגם דיסק בודד כמו ב-RAID-4 ביעלות זהה של מקום וקיבולת, אך השארנו מאחור את צוואר-הבקבוק וניתן לבצע כעת עדכוני "כתיבה קטנה" במקביל ולנצל היטב את תכונות ה-I/O הסדירות.
זהה בבסיסה ל-RAID-5 (פיזור מחזורי על כל הדיסקים), רק שבמקום בלוק זוגיות אחד לשורה, נוצרים ומפוזרים חישובי Parity באופן מוכפל בעזרת אלגוריתמים מעט סבוכים יותר אל שני בלוקים לא-תואמים אחרים בסדרה (כך לכל רצועה יש שני דיסקים במעורב הסופגים את אחריות הקיבולת הזוגית על ידם).
- היתרון הייחודי: מערך RAID-6 ימשיך את פעילותו התקינה והיציבה אפילו כשמתרחש התרחיש המורכב בו שני כוננים שונים קורסים ונופלים בו-זמנית! זאת לעומת RAID-5 שקורס בכשל משולב. זה חיוני מאוד למערכים גדולים במיוחד כאשר עד להגעת ההחלפה או במהלך השחזור האיטי (הגובה זני עבודה) עלול לעבור זמן בו דיסק נוסף נגוע בסבירות נופל במפתיע.
עקרונות ה-RAID עדיין תקפים בעולם הענן, אך הם "נמתחים" לקנה מידה של אשכולות מבוזרים בהיקפים עצומים (עשרות אלפי שרתים, פטה-בייטים ועד אקסה-בייטים). לכן, הדילמה המרכזית מתורגמת לשתי אסטרטגיות עיקריות לאמינות וליתירות:
-
Replication (שכפול מלא):
- רעיון בסיסי: שמירה של עותקים זהים של הנתונים במספר צמתים/מתקנים. זהו שיקוף בקנה מידה גדול, בדומה ל-RAID-1 אך על פני רשת ומיקומים גיאוגרפיים שונים.
- יתרונות: פשטות תפעולית, קריאות מהירות (אפשר לקרוא מהעותק הקרוב/הפנוי), וזמן התאוששות קצר במקרה כשל.
- חסרונות: עלות אחסון גבוהה מאוד. עבור עמידות חזקה, נהוג להחזיק מספר עותקים (למשל 2–3), מה שמייצר בזבוז נפח מהותי והגדלת עלויות.
-
Erasure Coding (קודי מחיקה):
-
רעיון בסיסי וסימון (
$n+k$ ): המערכת מיוצגת מתמטית כ-$n+k$, כאשר$n$ מייצג את בלוקי הנתונים (Data), ו-$k$ מייצג את בלוקי היתירות (Redundancy, למשל בעזרת אלגוריתם Reed-Solomon). מערכת כזו מסוגלת לסבול בדיוק$k$ כשלים במקביל. -
יעילות הנפח: בניגוד לשכפול, כאן "מבזבזים" רק
$\frac{k}{n+k}$ מנפח המערך על יתירות (לדוגמה, מערך RAID-5 נחשב תצורת$n+1$ , ומערך RAID-6 הוא$n+2$ ). - יתרונות: חיסכון משמעותי בנפח לעומת שכפול.
-
חסרונות בולטים ומונחים מקצועיים:
-
קריאה מופחתת (Degraded Reads): כאשר חסר בלוק נתונים, יש לקרוא
$n$ בלוקים אחרים כדי לחשב אותו מחדש (XOR/אלגברה), מה שגורר קפיצה בזמני ההשהיה (Latency). -
תעבורת תיקון (Repair Traffic): העברת אותם
$n$ בלוקים ברשת אל המכונה שמבצעת את חישוב השחזור יוצרת עומס רוחב-פס משמעותי. - בעיית הכתיבה הקטנה: קיימת גם כאן (הפתרון המקובל בתעשייה הוא פשוט לעבוד עם בלוקים גדולים מאוד).
-
קריאה מופחתת (Degraded Reads): כאשר חסר בלוק נתונים, יש לקרוא
-
רעיון בסיסי וסימון (
בפועל: מערכות ענן משלבות בין שתי השיטות. שכפול מלא משמש לרוב לנתונים חמים ופעולות בזמן אמת, וקודי מחיקה משמשים לשכבות אחסון חסכוניות עבור נתונים פחות נגישים.