پرش به محتوای اصلی
پرش به محتوای مقاله

Walgit میزبانی مخازن عظیم Git را به فضای ذخیره‌سازی ابری منتقل کرد

·۳ شهریور ۱۴۰۵۹ دقیقه مطالعه۱ بازدید
لوگوی وال‌گیت: ابزار خط فرمان برای مدیریت والپیپر با گیت‌هاب
لوگوی وال‌گیت: ابزار خط فرمان برای مدیریت والپیپر با گیت‌هاب
اشتراک‌گذاری
واقعاً چه چیز جدید است؟

جایگزینی کامل دیتابیس‌های محلی و مکانیزم‌های Replication با استفاده از CAS در S3/GCS برای مدیریت وضعیت مخازن Git؛ به گونه‌ای که سرور کاملاً Stateless شده و حجم مخزن می‌تواند از حجم دیسک سرور بیشتر باشد.

تصور کنید مخزنی از کدها دارید که آن‌قدر حجیم است که به طور سنتی برای جلوگیری از تأخیرهای فاجعه‌بار در شبکه، به گران‌ترین درایوهای NVMe و منطق پیچیده تکثیر داده (Replication) نیاز دارد. Walgit که در ۲۴ اوت ۲۰۲۶ منتشر شد، با تبدیل سرور به یک حافظهٔ موقت (Cache) یک‌بارمصرف و انتقال منبع حقیقت به فضای ذخیره‌سازی اشیاء (Object Store)، این نیازهای سخت‌افزاری را به‌طور کامل حذف می‌کند. این ابزار در واقع پیاده‌سازی زبان Rust از معماری است که شرکت Cursor در مقاله «Git در هر مقیاسی» (سیستم Continuity) توصیف کرده بود؛ با این تفاوت که Walgit را برای اجرا روی ماشین‌هایی بهینه کرده‌اند که حتی از حجم مخزنی که سرویس می‌دهند، کوچک‌تر هستند.

سال‌هاست که صنعت با مشکل «فایل‌های بسته‌بندی‌شده» (Packfiles) دست‌وپنجه نرم می‌کند؛ بلوک‌های باینری عظیمی که باعث می‌شوند عملیات Git شبیه به یک گشت‌وگذار تصادفی (Random Walk) در گیگابایت‌ها داده باشد. طبق گزارش‌های فنی، میزبان‌های سنتی مثل GitHub از سیستمی به نام Spokes استفاده می‌کنند تا این فایل‌ها را روی دیسک‌های محلی نگه دارند. این روش نیازمند یک سیستم commit سه مرحله‌ای در میان یک مجموعه کپی ثابت، یک پایگاه‌داده که هر مخزن را به ماشین‌های خاصش نگاشت می‌کند و ناوگانی از سرورهای «حیوان خانگی» (Pet Servers) است تا سازگاری داده‌ها را حفظ کنند. این معماری باعث می‌شود مقیاس‌پذیری بسیار گران شود و از نظر عملیاتی صلب و غیرمنعطف باشد.

همان‌طور که در تحلیل‌های پیشین ما درباره‌ی بهینه‌سازی زیرساخت‌های ذخیره‌سازی داده اشاره کردیم، حذف وضعیت (Statelessness) کلید مقیاس‌پذیری در ابر است. Walgit دقیقاً همین فلسفه را پیاده می‌کند. به‌جای تکثیر فایل‌های pack بین سرورها، از یک «لاگ پیش‌نویس» (Write-Ahead Log یا WAL) استفاده می‌کند که در یک باکت سازگار با S3 ذخیره می‌شود. در این سیستم، هر Push یک شیء تغییرناپذیر (Immutable) است و سیستم تنها زمانی «زنده» یا فعال می‌شود که یک مانیفست بسیار کوچک از طریق عملیات Compare-and-Swap (CAS) به‌روزرسانی شود. این CAS در واقع همان مکانیزم اجماع (Consensus) است؛ در اینجا هیچ انتخاب لیدری وجود ندارد، هیچ حد نصابی (Quorum) تعریف نشده و هیچ سرور اصلی (Primary) در کار نیست. این رویکرد به مدیریت بهینه وضعیت در مقیاس بالا شباهت دارد، مشابه آنچه در سیستم Shepherd برای کاهش هزینه بازگردانی وضعیت فایل‌سیستم‌ها مشاهده کردیم.

معماری بدون وضعیت (Stateless)

از آنجا که باکت ابری منبع حقیقت است، هر ماشینی که فایل اجرایی Walgit را داشته باشد، می‌تواند هر مخزنی را سرویس دهد. هیچ انتخاب لیدری و هیچ وضعیت محلی‌ای وجود ندارد که اهمیت داشته باشد. اگر تمام نمونه‌های در حال اجرا را خاموش کنید، تنها «گرم بودن» حافظهٔ موقت را از دست می‌دهید، اما هیچ داده‌ای حذف نمی‌شود.

ثبات داده‌ها بدون نیاز به هماهنگی (Coordination) پیچیده حفظ می‌شود، زیرا هر درخواست خواندن ابتدا یک GET مشروط از مانیفست می‌گیرد. اگر پاسخ ۳۰۴ باشد، به این معناست که سرور می‌تواند از کپی محلی خود سرویس دهد؛ اما اگر پاسخ ۲۰۰ باشد، این امر باعث فعال شدن فرآیند اعمال ورودی‌های جدید از لاگ می‌شود.

  • مانیفست: یک فایل کوچک protobuf (manifest.pb) که به عنوان نقطه خطی‌سازی (Linearization point) عمل می‌کند. این فایل توالی head، مجموعه packهای فعال، اشاره‌گر checkpoint و تنظیمات را ردیابی می‌کند و از طریق CAS بازنویسی می‌شود.
  • لاگ: ورودی‌های تغییرناپذیر (log/<seq>.pb) شامل عملیات PUSH, COMPACT, CHECKPOINT و SETTINGS که منشأ و تاریخچه کامل هر تغییر را فراهم می‌کند. هر push و repack در این سیستم تا هر نقطه‌ای قابل بازپخش (Replayable) است.
  • ذخیره‌ساز: پشتیبانی درجه اول از AWS S3، Google Cloud Storage (GCS) و ذخیره‌سازهای سازگار با S3 مانند MinIO، R2، Ceph و rustfs. همچنین یک ذخیره‌ساز در حافظه (In-memory) برای تست‌ها فراهم شده است.
  • ساختار WAL: باکت داده‌ها را در مسیر repos/<owner>/<repo>/ سازماندهی می‌کند که شامل مانیفست، لاگ، بسته‌های آدرس‌دهی شده بر اساس محتوا (.pack, .idx, .rev, .bitmap, .commit-graph) و اشیاء LFS است. همچنین checkpoints/<seq>/ (شامل اسنپ‌شات‌های ref تاشده و موجودی packها) و leases/ برای Mutexهای بین-نمونه‌ای با TTL ذخیره می‌شوند.

حل چالش مونو-ریپو (Monorepo)

سرویس‌دهی به مخزنی که از دیسک سرور بزرگ‌تر است، بزرگ‌ترین چالش ماشین‌های کوچک است. Walgit این مشکل را با مکانیزم‌های زیر حل می‌کند:

  • خواندن از راه دور: استفاده از HTTP range requests برای سرویس‌دهی به refها و صفحات وب برای بسته‌هایی (Packs) که هرگز روی دیسک نمونه جا نمی‌شوند. این قابلیت اجازه می‌دهد سرور به عنوان یک خواننده راه دور روی HTTP عمل کند.
  • ذخیره‌سازی ترکیبی: برای افزایش سرعت، کامیت‌ها و درخت‌ها (Trees) را به صورت محلی نگه می‌دارد (بسته تاریخچه)، در حالی که Blobهای حجیم را در باکت ابری رها می‌کند.
  • Bundle-URI: کلون‌های جدید به‌صورت فایل‌های استاتیک از باکت یا CDN سرویس می‌شوند. باندل‌ها بر اساس بازه‌های زمانی تقویمی (کامل‌های هفتگی، زنجیره‌های روزانه و ساعتی) به عنوان یک تابع خالص از WAL ساخته می‌شوند. یک کلون جدید، جدیدترین نسخه کامل به علاوه زنجیره را دانلود کرده و تنها برای باقی‌مانده از سرور درخواست می‌کند. برای به‌روزرسانی‌ها (Catch-ups)، دقیقاً اسلات‌های از دست رفته دانلود می‌شوند. دو لیست برای هر مخزن نگهداری می‌شود: bundles/list برای کلون‌ها و bundles/catchup برای fetchها.
  • خانواده‌های بدون بلوک (Blobless): پشتیبانی از --filter=blob:none برای کاهش بیشتر ردپای داده‌ها در کلاینت و سرور.
  • پشتیبانی از Smart HTTP: سازگاری با نسخه‌های v0/v2 پروتکل Git Smart HTTP، شامل ls-refs با پیشوندها، fetch با فیلتر/shallow/deepen/sideband-all و receive-pack (با پشتیبانی از به‌روزرسانی‌های اتمیک، حذف‌ها، تگ‌ها، push options و report-status-v2). همچنین از مخازن sha1 و sha256 پشتیبانی می‌کند.

ابزارهای مدیریتی و سیاست‌گذاری

علاوه بر موتور ذخیره‌سازی، Walgit شامل یک مجموعه کامل از ابزارهای مدیریتی است. این سیستم دارای یک رابط کاربری وب مبتنی بر React برای مرور درخت‌ها، Blobها و Diffها و همچنین یک صفحه وضعیت (Health page) برای WAL است. این بخش توسط یک API جی‌سون (که عمدتاً برای خواندن است) در مسیر /{owner}/{repo}/api/* و یک SDK بدون وابستگی به نام repos.js تغذیه می‌شود. پاسخ‌های طولانی API پیشرفت عملیات را به صورت Server-Sent Events (SSE) استریم می‌کنند.

برای نیازهای سازمانی، سیستمی به نام policy.json تعریف شده است. این سیستم به مدیران اجازه می‌دهد قوانینی را برای هر مخزن تعیین کنند، از جمله:

  • مرجع‌های محافظت‌شده (Protected refs)
  • مجوزهای گروهی
  • الزام به Fast-forward-only
  • لیست‌های دور زدن (Bypass lists)

همانی‌طور، یک پل وب‌هوک (Webhook bridge) وجود دارد که لاگ WAL را دنبال کرده و رویدادهای ref را POST می‌کند. این عملیات با استفاده از یک کرسر بادوام در events/cursor.json تضمین می‌کند که هر رویداد دقیقاً یک‌بار برای هر (مخزن، توالی، ref) ارسال شود. LFS از طریق Batch API و انتقال پایه پشتیبانی می‌شود، به طوری که اشیاء در باکت ذخیره شده و برای مخازن وارد شده (Imported)، امکان خواندن از سرورهای LFS بالادستی فراهم است. در این راستا، ابزارهایی که با ساختار Git سازگار هستند می‌توانند تحلیل‌های دقیق‌تری ارائه دهند، مشابه آنچه در ابزار Avouch برای کاهش نویز در تحلیل‌های ایستا پیاده شده است.

استقرار و نگهداری

استقرار این سیستم به گونه‌ای طراحی شده که تقریباً آنی باشد. کاربر تنها یک فایل باینری را اجرا کرده و آن را از طریق فایل پیکربندی walgit.toml به یک باکت متصل می‌کند و شروع به push می‌کند. برای مثال، یک پیکربندی پایه، آدرس listen، public_url و گزینه auto_create_on_push = true را تعریف می‌کند.

پیکربندی اجازه می‌دهد نقش‌های خاصی برای سرور تعریف شود:

  • serve: مدیریت Git، API، رابط کاربری، باندل‌ها و LFS.
  • maintain: مدیریت نقاط بازرسی (Checkpoints)، باندل‌ها، فشرده‌سازی (Compaction) و عملیات fsck/repair.
  • events: مدیریت پل وب‌هوک.

احراز هویت انعطاف‌پذیر است و از چندین حالت پشتیبانی می‌کند:

  • None: همه ناشناس هستند و دسترسی نوشتن دارند (برای آزمایش‌های loopback).
  • Token: توکن‌های استاتیک تعریف شده در پیکربندی یا متغیرهای محیطی (مانند WALGIT_TOKEN_ME) که از طریق Authorization: Bearer یا HTTP Basic ارسال می‌شوند.
  • OIDC: یکپارچگی با هر صادرکننده OpenID Connect (مانند Google، Entra، Okta، Auth0، Keycloak، Dex، GitLab). این حالت از ورود از طریق مرورگر، ID tokens و توکن‌های دسترسی صادر شده توسط walgit پشتیبانی می‌کند. این سیستم بدون وضعیت است و از HMAC با یک session_secret و access_token_ttl استفاده می‌کند.

راه‌اندازی برای توسعه‌دهندگان در یک دستور idempotent خلاصه شده است: sh -c "$(curl -fsSL 'https://git.example.com/services/public/install.sh')". این دستور یک Git credential helper (برای Git ≥ 2.46) نصب می‌کند که authtype=Bearer را مدیریت کرده و transfer.bundleURI را برای کلون‌های سریع‌تر فعال می‌کند.

مکانیزم‌های داخلی و قابلیت اطمینان

نگهداری سیستم توسط یک «حلقه نگهداری» (Maintainer loop) انجام می‌شود که وضعیت مطلوب را از روی پیکربندی و WAL محاسبه می‌کند. این حلقه مسئول مدیریت نقاط بازرسی (اسنپ‌شات‌های ref تاشده)، فشرده‌سازی هندسی (Geometric compaction)، بازسازی پایه‌ها (Base rebuilds) و ممیزی‌های اتصال (Connectivity audits) است. از آنجا که خروجی‌ها تابع خالص (Pure function) لاگ WAL هستند، سیستم خودبه‌خود ترمیم می‌شود؛ هر آرتیفکت حذف‌شده به‌سادگی و به‌طور یکسان بازسازی می‌شود.

هنگام یک Push، Walgit ابتدا بسته (Pack) را در یک دایرکتوری موقت (Scratch) با استفاده از git index-pack --fix-thin --rev-index ایندکس می‌کند، اتصال و سیاست‌ها را بررسی کرده و سپس بسته، ایندکس و ورودی لاگ را آپلود می‌کند. در نهایت تلاش می‌کند مانیفست را از طریق CAS به‌روز کند. اگر خطای ۴۱۲ (Precondition Failed) رخ دهد، مانیفست را دوباره خوانده، refها را مجدداً اعتبارسنجی کرده و تلاش می‌کند. Pushهای همزمان در یک نمونه واحد برای کاهش رفت‌وبرگشت‌ها به باکت، در یک CAS گروهی (Group-committed) ادغام می‌شوند. کلاینت تنها پس از تأیید نوشتن توسط باکت، پاسخ «ok» را دریافت می‌کند.

جای‌گذاری (Placement) به‌طور صریح از طریق globs در بخش [placement] پیکربندی می‌شود. در حالی که خواندن در سطح refها در همه جا کار می‌کند، کارهای سنگین مربوط به اشیاء به میزبان‌های خاصی هدایت می‌شوند. برای مثال، یک مونو-ریپو می‌تواند روی میزبان دارای SSD با تنظیم cache.mode = "disk" قرار گیرد، در حالی که سایر مخازن روی ماشین‌های کوچک‌تر باقی بمانند.

جزئیات پیاده‌سازی فنی

Walgit با یک معماری ماژولار در Rust ساخته شده است. منطق هسته برای اطمینان از جداسازی دقیق مسئولیت‌ها بین چندین Crate تقسیم شده است:

  • walgit-proto: تعریف شمای protobuf (wal.proto)، قاب‌بندی لاگ و کلیدهای ذخیره‌ساز.
  • walgit-store: پیاده‌سازی Trait ObjectStore برای مدیریت نسخه‌های CAS، درخواست‌های GET مشروط، درخواست‌های Range و ترکیب (Composition) در بک‌اندهای S3، GCS و حافظه.
  • walgit-git: مدیریت مخازن Bare روی دیسک، منطق receive-pack، جذب بسته‌ها و نگاشت بین refها و packed-refs.
  • walgit-wal: شامل RepoHandle برای مدیریت سطوح همگام‌سازی، کامیت‌های گروهی از طریق publish، نقاط بازرسی و Reader راه دور.
  • walgit-bundle: مدیریت منطق bundle-uri شامل مدیریت اسلات/زنجیره، ترکیب بسته‌ها و سیاست‌های نگهداری.
  • walgit-server: نقطه ورود مبتنی بر Axum که Smart HTTP، LFS، احراز هویت OIDC، حلقه نگهداری و API مبتنی بر SSE را فراهم می‌کند.
  • walgit-config: تجزیه walgit.toml و جایگزینی‌های محیطی با اعتبارسنجی fail-closed.

برای کسانی که از Nginx استفاده می‌کنند، سیستم از X-Accel-Redirect برای تخلیه بایت‌ها (Byte offload) پشتیبانی می‌کند. این قابلیت به Nginx اجازه می‌دهد تا دانلودهای LFS یا باندل‌ها را مستقیماً از باکت با استفاده از S3 presigned URLs یا GCS bearer tokens استریم و کش کند و بدین ترتیب ترافیک سنگین داده را از باینری Walgit دور کند.

مدل هزینه و ناورداها

برای حفظ پایداری در مقیاس بالا، Walgit به چندین ناوردای (Invariant) سخت پایبند است:

  • مانیفست به‌عنوان تنها حقیقت: تنها نقطه ثبت نهایی (Commit point)، CAS مانیفست است. هر چیزی قبل از آن نامرئی است و هر چیزی بعد از آن idempotent و قابل بازپخش است.
  • تغییرناپذیری: تمام اشیاء بر اساس محتوا آدرس‌دهی می‌شوند. تنها مانیفست، لیست باندل‌ها و leases بازنویسی می‌شوند.
  • عدم پذیرش سازگاری نهایی (Eventual Consistency): هر خواندن ابتدا با باکت اعتبارسنجی می‌شود. دیسک محلی و حافظه صرفاً به عنوان کش در نظر گرفته می‌شوند.
  • عملیات طولانی مبتنی بر تسک: هر عملیات کند به عنوان یک تسک با ID منحصربه‌فرد، یک لاگ و یک استریم پیشرفت در نظر گرفته می‌شود. این پیشرفت از طریق sideband 2 (remote: * ...) به Git و از طریق SSE به مرورگر گزارش می‌شود.

مدل هزینه این سیستم توسط تعداد رفت‌وبرگشت‌ها (Round trips) به باکت کنترل می‌شود. هر تغییر در پروتکل با این بودجه سنجیده می‌شود تا اطمینان حاصل شود که با افزایش تعداد refها یا اندازه بسته‌ها، عملکرد سیستم افت نمی‌کند. این امر تضمین می‌کند که سرور حتی زمانی که مخزن زیربنایی بسیار بزرگ‌تر از حافظه یا دیسک فیزیکی ماشین است، پاسخگو باقی بماند.

این تغییر در معماری، اقتصاد میزبانی Git را تغییر می‌دهد. با انتقال لایه اجماع به CAS ذخیره‌ساز اشیاء، Walgit نیاز به یک پایگاه‌داده اختصاصی برای نگاشت مخازن به ماشین‌ها را از بین می‌برد. مدل هزینه اکنون به جای اندازه SSD محلی، با تعداد رفت‌وبرگشت‌ها به باکت اندازه‌گیری می‌شود. برای توسعه‌دهندگان، این به معنای توانایی میزبانی مونو-ریپوهای عظیم روی نمونه‌های ابری ارزان و یک‌بارمصرف، بدون نیاز به مدیریت ناوگانی از سرورهای تخصصی است. در واقع، استفاده از شناسه‌های دقیق برای ردیابی وضعیت، مشابه به‌کارگیری Commit Hash برای جلوگیری از تغییرات خاموش در مدل‌های Llama، تضمین می‌کند که هر نسخه از داده‌ها دقیقاً قابل شناسایی و بازگشت است.

گام بعدی شما

  • اگر با مخازن مونو-ریپوی حجیم در سازمانتان دست‌وپنجه نرم می‌کنید، Walgit را روی یک نمونه کوچک ابری تست کنید تا کاهش نیاز به NVMe را تجربه کنید.
  • مستندات bundle-uri را بررسی کنید تا متوجه شوید چگونه می‌توانید سرعت کلون کردن مخازن را با استفاده از CDN افزایش دهید.
  • برای کاهش هزینه‌های انتقال داده، پیکربندی X-Accel-Redirect را در Nginx فعال کنید.

اما تأثیر این رویکرد «بدون وضعیت» بر سایر ابزارهای DevOps حتی عمیق‌تر است — به تحلیل ما درباره‌ی آینده زیرساخت‌های Stateless مراجعه کنید.

چرا این موضوع مهم است؟

این معماری هزینه میزبانی مخازن عظیم را به‌شدت کاهش می‌دهد زیرا نیاز به سخت‌افزارهای تخصصی و مدیریت پیچیده کلاسترها را از بین می‌برد. اعتبار این رویکرد از پیاده‌سازی مفاهیم Continuity در محیط واقعی نشأت می‌گیرد که اثبات می‌کند مقیاس‌پذیری Git وابسته به سخت‌افزار نیست، بلکه وابسته به معماری دسترسی به داده است.

تأثیر برای ایران

برای تیم‌های توسعه ایرانی که با محدودیت بودجه برای خرید سخت‌افزارهای NVMe گران‌قیمت مواجه‌اند، این ابزار امکان میزبانی مخازن حجیم را روی سرورهای ارزان‌قیمت ابری فراهم می‌کند.

·نگاه ما
تحریریه دات‌هوش

انتقال لایه اجماع (Consensus) از دیتابیس‌های پیچیده به قابلیت CAS در Object Storeها، یک چرخش هوشمندانه در طراحی زیرساخت است. این رویکرد نشان می‌دهد که برای مقیاس‌پذیری در سطح پترابایت، باید به جای تلاش برای مدیریت وضعیت (State) در سرورها، از ویژگی‌های ذاتی ذخیره‌سازهای ابری به‌عنوان لایه هماهنگی استفاده کرد. در واقع Walgit دیسک سرور را از یک «مخزن» به یک «شتاب‌دهنده» تبدیل کرده است.

منابع

این گزارش با خط‌لولهٔ خودکار دات‌هوش از منابع معتبر جهانی تدوین و زیر نظر تحریریه منتشر شده است. روش کار ما

گفتگو

پنج‌شنبه‌های هوش‌محور

بسته‌ی هفتگی دات‌هوش

۵ خبر، ۲ ابزار، ۱ پرامپت در هر شماره. به‌زودی راه‌اندازی می‌شود — هر پنج‌شنبه صبح.

خبر کلیدی
ابزار کاربردی
پرامپت حرفه‌ای
تحلیل پژوهش
به‌زودی
زاویه‌ی ایرانی
به‌زودی
تمرین این هفته
به‌زودی

راهنماهای دات‌هوش

راهنماهای کاربردیِ دات‌هوش برای کار با هوش مصنوعی — از همین‌جا شروع کنید:

دات‌هوش

راهنمای فارسی هوش مصنوعی — با نگاه به ایران

اخبار روزانه، معرفی ابزارها و مدل‌ها، و آموزشِ کار با هوش مصنوعی؛ همیشه با این پرسش که از ایران چه چیزی کار می‌کند و چه چیزی نه.