پالت فرمان

دنبال فرمانی برای اجرا بگردید…

ZarynZaryn
مفاهیم اصلی·۳ دقیقه مطالعه

قطعه‌بندی بر پایهٔ محتوا

فایل‌های بزرگ ناهمگون تغییر می‌کنند: ویرایشی کوچک و محلی نزدیک ابتدای فایل نباید انتقال دوبارهٔ کل فایل را لازم کند. zev این مشکل را با قطعه‌بندی بر پایهٔ محتوا حل می‌کند که روی یک پنجرهٔ غلتان با هش Gear ساخته شده است؛ همان خانوادهٔ الگوریتمی که ابزارهایی مثل `restic` و `borg` به کار می‌برند، و به‌طور مستقل در Zig و فقط با کتابخانهٔ استاندارد پیاده شده است. ## ویژگی اصلی یک قطعه‌بند مبتنی بر محتوا فایل را بر پایهٔ محتوای خود فایل، نه فاصله‌های ثابت بایتی، به تکه‌هایی با طول متغیر تقسیم می‌کند. وقتی ویرایشی کوچک انجام می‌شود، فقط قطعه‌هایی که با آن ویرایش تماس دارند تغییر می‌کنند؛ هر مرز قطعه در جاهای دیگر فایل دقیقاً سر جایش می‌ماند، چون مرز تابعی از بایت‌های نزدیک است، نه یک شمارندهٔ بایت. این ویژگی پیش از هر کار یکپارچه‌سازی، مستقل اثبات شد: قطعه‌بندی یک فایل واقعی ۱٫۷ مگابایتی و درج ویرایشی ۹۳ بایتی نزدیک ابتدایش، ۹۶٫۵٪ بایت‌های فایل را (به حساب قطعه) بایت‌به‌بایت بدون تغییر گذاشت. یک مدل ذخیره‌سازی فایل‌کامل برای همین ویرایش یک‌خطی باید ۱۰۰٪ فایل را دوباره ذخیره می‌کرد. ## قطعه‌ها چگونه شناسایی و ذخیره می‌شوند هر قطعه با BLAKE3 هش می‌شود (مطابق شیوهٔ هویت اشیای خود سرور؛ نگاه کنید به [ذخیره‌سازی با نشانی‌دهی محتوایی](/docs/fa/content-addressing)) و به‌صورت یک شیء معمولی با همان هش ذخیره می‌شود. یک مانیفست (فهرست مرتب هش قطعه‌هایی که فایل اصلی را بازمی‌سازند) هم کنارش با کلید هش کل فایل ذخیره می‌شود. این طراحی عمداً افزایشی است: فایل قطعه‌بندی‌شده همچنان به‌صورت یک شیء کامل و معمولی هم ذخیره می‌شود. هر مسیر خواندن موجود که یک شیء، یک هش و یک فایل کامل انتظار دارد بدون تغییر کار می‌کند. قطعه‌بندی صرفاً بهینه‌سازی‌ای است که زیر کار قرار گرفته و برای هر چیزی که صراحتاً آن را نخواهد نامرئی است. ## هنگام ارسال واقعاً چه می‌شود 1. کلاینت یک فایل بزرگ (بالاتر از یک آستانهٔ اندازه) را محلی قطعه‌بندی می‌کند. 2. از سرور می‌پرسد کدام هش قطعه‌ها را هنوز ندارد (`POST .../objects/have`). 3. فقط قطعه‌های ناموجود را بارگذاری می‌کند. 4. از سرور می‌خواهد کل فایل را از قطعه‌ها بازسازی کند (`POST .../objects/reconstruct`)؛ سرور خودش هش فایل را از قطعه‌ها دوباره به دست می‌آورد و اگر با ادعا یکی نباشد چیزی ذخیره نمی‌کند. اندازه‌گیری‌شده روی یک فایل واقعی حدود ۱٫۷ مگابایتی با ۹۲ قطعه پس از یک ویرایش یک‌خطی واقعی: **۱ قطعهٔ تازه بارگذاری شد، ۹۱ قطعه از قبل موجود بود.** ## هنگام دریافت چه می‌شود همان ایده، برعکس و دسته‌ای. کلاینت هر چه را ندارد با چند درخواست می‌خواهد (`POST .../objects/batch`، هر بار تا ۲۵۶ شیء، چهار درخواست هم‌زمان). شیءهای کوچک کامل می‌آیند. فایلی که قطعه‌قطعه ذخیره شده به شکل فهرست قطعه‌هایش می‌آید: کلاینت هر قطعه را در حافظهٔ محلی قطعه‌ها (که ارسال‌ها و دریافت‌های پیشین پرش کرده‌اند) جست‌وجو می‌کند، فقط قطعه‌های ناموجود را می‌خواهد (آن هم دسته‌ای، و قطعه‌ای که در چند فایل مشترک است فقط یک بار)، فایل را می‌سازد و پیش از نوشتن روی دیسک بررسی می‌کند که هش نتیجه درست باشد. هر شیء و هر قطعه با نامش، یعنی هش بایت‌هایش، سنجیده می‌شود. اندازه‌گیری‌شده روی همان فایل واقعی، با دریافت همان ویرایش یک‌خطی در مخزنی که نسخهٔ قبلی را داشت: **۱ قطعه از شبکه دریافت شد، ۹۱ قطعه از حافظهٔ محلی.** zev پس از دریافت این را نشان می‌دهد: ```text Fetched: 3 (3 in 2 request(s)), already had: 4 Large files: 1 chunk(s) downloaded, 91 reused from earlier pulls ``` ## یک بده‌بستان عملیاتی واقعی که بهتر است بدانید قطعه‌بندی پهنای باند را با تعداد درخواست معاوضه می‌کند. یک ارسال تنهای فایلی ۹۲ قطعه‌ای می‌تواند بیش از ۹۰ درخواست HTTP جدا باشد (دریافت‌ها با خواستن دسته‌ای قطعه‌ها از این پرهیز می‌کنند). این واقعاً با محدودیت نرخ درخواستی که برای ترافیک معمول API طراحی شده تداخل دارد؛ محدودیتی که برای الگوهای مصرف معمول اندازه شده با یک ارسال بزرگ قطعه‌بندی‌شده تمام می‌شود. سرور zev دقیقاً به همین دلیل به نقطه‌های پایانی مربوط به قطعه‌ها (`/have`، `/reconstruct`، بارگذاری و دریافت تک‌قطعه‌ها) سهمیهٔ نرخ جداگانه و بسیار بالاتری می‌دهد، تا همگام‌سازی انبوه قطعه‌ها هرگز با سهمیه‌ای که بقیهٔ API را محافظت می‌کند رقابت نکند یا آن را تمام نکند.