تصور کنید مخزنی از کدها دارید که آنقدر حجیم است که به طور سنتی برای جلوگیری از تأخیرهای فاجعهبار در شبکه، به گرانترین درایوهای 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 مراجعه کنید.




گفتگو