اسنپشاتها بکاپ نیستند — و شما هر دو را میخواهید
یک اسنپشات کپیِ لحظهایِ یک volume است که روی همان بسترِ ذخیرهسازیِ همان volumeای زندگی میکند که از آن کپی گرفته. این یک انتقاد نیست، یک توصیف است، و دقیقاً توضیح میدهد اسنپشات در چهکاری عالی است و از چهکاری برنمیآید. هر پلنی اینجا شاملِ اسنپشاتِ ساعتی با نگهداریِ هفتروزه است، بازیابیِ یکی از آنها حدودِ سی ثانیه طول میکشد، و آنها پاسخِ درست به رایجترین رخدادِ منفرد در عملیاتِ سرور هستند: شما ساعتِ چهارِ بعدازظهر یک فایلِ پیکربندی را ویرایش کردهاید و از آن موقع سرویس دیگر بالا نیامده است. برای این نوع شکست، هیچچیزِ دیگری نزدیک هم نیست — از هر ابزارِ بکاپی سریعتر است، همین الان هم دارد اجرا میشود، و هیچ هزینهٔ اضافهای ندارد.
کاری که اسنپشات نمیتواند انجام بدهد این است که از چیزی که رویش ذخیره شده جان سالم به در ببرد. سرنوشتش را با volume، هاست، hypervisor و در بیشترِ طراحیها با اکانت مشترک است. اگر ماشین توقیف شود، اگر اکانت بسته شود، اگر دیتاسنتر روزِ خیلی بدی داشته باشد، اسنپشاتها هم با آن میروند — آنها یک کپی از دادهاند، نه یک کپیِ مستقل. این تمایز روی ارائهدهندهای که عمداً نمیتواند شما را شناسایی کند، انتزاعی نیست: هیچ مسیرِ پشتیبانیای وجود ندارد که سرورتان را از رویِ سوابقِ شخصِ دیگری بازسازی کند، هیچ فرایندِ بازیابیای که به یک شمارهتلفن گره خورده باشد وجود ندارد، و هیچ سابقهٔ صورتحسابی با نامِ حقیقیِ شما وجود ندارد. هرچه برداشتهاید همان چیزی است که دارید.
یک پنجرهٔ هفتروزه هم به آن دو شکستِ کند کمکی نمیکند. فایلی که پنج هفته پیش حذفش کردهاید، مدتها پیش از آنکه متوجه شوید، از همهٔ اسنپشاتها رفته است. خرابیِ بیصدا — اپلیکیشنی که دارد از کار میافتد و ظریفانه دادهٔ اشتباه مینویسد، یک مایگریشنِ بد، کلاینتِ همگامسازیای که وفادارانه یک اشتباه را منتشر میکند — اغلب یک ماه بعد کشف میشود، وقتی که هر نسخهٔ نگهداریشدهای دیگر همان خرابی را در خودش دارد. بکاپهایی با نگهداریِ بلندتر و تاریخچهای واقعی، چیزی هستند که اینها را پوشش میدهند، و دقیقاً به این دلیل پوششش میدهند که آینههایِ پیوستهٔ وضعیتِ فعلی نیستند.
چارچوبی که ارزشِ درونیکردن دارد اینجا قدیمی است و هنوز هم درست است. قاعدهٔ 3-2-1 سه نسخه از داده را میخواهد، روی دو نوعِ متفاوت از ذخیرهسازی، که یکیشان خارج از سایت باشد. ضمیمهٔ مدرن دو رقمِ دیگر اضافه میکند — 3-2-1-1-0 — که در آن، آن یکِ اضافه، نسخهای است که تغییرناپذیر یا آفلاین است، و صفر تعدادِ خطاها در آخرین راستیآزماییِ شماست. این ارقام یک وسیلهٔ کمکِ حافظهاند نه یک استاندارد، اما آن سه ویژگیای را رمزگذاری میکنند که واقعاً اهمیت دارند: استقلال، تغییرناپذیری، و مدرکی که نشان دهد کار میکند. اسنپشاتهای ساعتی یکی از آن سه ویژگی را به شما میدهند.
| شکست | اسنپشاتِ ساعتی | بکاپِ خارج از سایت | چرا |
|---|---|---|---|
| خرابیِ پیکربندی یک ساعت پیش | ایدهآل | بیشازحد | rollbackِ سیثانیهای بهتر از هر بازیابیای است. |
| ارتقایِ بستهٔ بد امروزصبح | ایدهآل | کار میکند | اسنپشات کلِ volume را یکجا برمیگرداند. |
| فایلِ حذفشده، پنج هفته پیش | از دست رفته | پوشش میدهد | نگهداریِ هفتروزه از قبل تمام شده. |
| خرابیِ کند، یک ماه بعد کشف شد | از دست رفته | پوشش میدهد | هر اسنپشاتِ باقیمانده همان خرابی را دارد. |
| نفوذ به هاست، مهاجم با root | در معرضِ خطر | اگر append-only باشد پوشش میدهد | اعتبارنامهٔ روی ماشین به هرچیزی که ماشین حذف کند میرسد. |
| اکانت بسته یا ماشین توقیف شد | از دست رفته | پوشش میدهد | اسنپشات سرنوشتِ زیرساخت را دارد. |
| میخواهید ارائهدهنده عوض کنید | قابلِانتقال نیست | پوشش میدهد | مخزن هرجا بازیابی میشود؛ اسنپشات فقط همینجا. |
آن جدول را بهعنوانِ استدلالی برای اجرایِ هر دو بخوانید، نه برای انتخاب بینِ آنها. اسنپشاتها فرکانس و سرعت را پوشش میدهند؛ بکاپها استقلال و تاریخچه را. هزینهشان از جنسِ متفاوتی است، شکستشان هم به شکلهایِ جدا از هم رخ میدهد، و ترکیبِ این دو بسیار قویتر از دوبرابرکردنِ هرکدام بهتنهایی است.
دو عددی که همهچیزِ دیگر را تعیین میکنند
پیش از اینکه هیچ ابزاری نصب شود، دو رقم را بنویسید. هدفِ نقطهٔ بازیابی (RPO) این است که چهمقدار داده را میتوانید تحمل کنید از دست بدهید، اندازهگیریشده بر حسبِ زمان — اگر آخرین نسخهٔ قابلِاستفاده شش ساعت قدمت داشته باشد، RPOِ شما شش ساعت است و آن شش ساعت کاری که بینِ ایندو انجام شده از دست رفته. هدفِ زمانِ بازیابی (RTO) این است که چهمدت میتوانید تحملِ دردسترسنبودن را داشته باشید درحالیکه دارید از نو میسازید. هر چیزِ دیگری که پاییندستِ اینهاست — زمانبندی، روش، اینکه نسخهٔ دوم کجا زندگی میکند، چقدر خرج میکنید — از دلِ همین دو عدد بیرون میآید، و انتخابِ نرمافزار پیش از انتخابِ این دو، دقیقاً همان راهی است که آدمها به یک پاسخِ پیچیده برای پرسشی میرسند که هیچکس نپرسیده بود.
اگر غیررسمی بپرسید، بیشترِ آدمها میگویند صفر و صفر. این یک بودجه نیست، یک آرزوست، و قیمتی به آن چسبیده که ارزش دارد صریح بیانش کنیم: RPOِ نزدیک به صفر یعنی replicationِ پیوسته بهجایِ کپیهایِ زمانبندیشده، و RTOِ نزدیک به صفر یعنی یک ماشینِ دومِ گرم که از قبل در حالِ اجراست. هردو قابلِساختاند و هردو تقریباً هزینهٔ عملیاتیِ چیزی را که دارید از آن محافظت میکنید دوبرابر میکنند. برایِ اکثریتِ قریببهاتفاقِ بارهایِ کاریِ self-hosted، پاسخهایِ صادقانه جایی بینِ یک ساعت و یک روز برایِ نقطهٔ بازیابی است، و چند ساعت برایِ زمانِ بازیابی، که با یک بکاپِ رمزنگاریشدهٔ زمانبندیشده و یک بازسازیِ مستندشده بهراحتی پوشش داده میشود.
این اعداد برایِ هر مجموعهدادهٔ روی همان ماشین هم فرق میکنند، و همین جزئیات است که آنها را مفید میکند. ایمیل تیزترین مثال است: پیامی که بیست دقیقه پیش رسیده، هیچجایِ دیگری وجود ندارد، نمیشود دوباره تولیدش کرد، و فرستندهاش هم هیچ ایدهای ندارد که باید دوباره بفرستدش — پس یک سرورِ ایمیل نقطهٔ بازیابیای میخواهد که بر حسبِ دقیقه اندازهگیری شود، حتی با اینکه خودِ نرمافزار در یک بعدازظهر دوباره نصب میشود. یک نودِ Bitcoin این را کاملاً برعکس میکند: دادهٔ زنجیره چند صد گیگابایت است که هر peer روی شبکه با کمالِ میل دوباره برایتان میفرستد، پس بکاپگرفتن از آن اساساً هدررفتنِ فضایِ دیسک است، درحالیکه فایلِ کیفپولِ کنارش غیرقابلبازیابی است و ارزشِ محافظت مثلِ یک کلیدِ خصوصی را دارد، چون دقیقاً همان است.
| بارِ کاری | واقعاً غیرقابلجایگزین | RPOِ معقول | RTOِ معقول | شکل |
|---|---|---|---|---|
| سایت یا وبلاگِ شخصی | محتوا، کلیدِ اکانتِ TLS | 24 h | یک روز | مخزنِ شبانه، بازسازی از رویِ یادداشتها |
| سرورِ ایمیل | maildir، کلیدهایِ DKIM، نامهایِ مستعار | 15 min | 2–4 h | افزایشیِ مکرر، ماشینِ دوم در حالتِ آمادهباش |
| Nextcloud یا همگامسازیِ فایل | دایرکتوریِ داده، پایگاهداده، پیکربندی | 6–24 h | یک روز | dumpِ شبانه در حالتِ نگهداری |
| homeserverِ Matrix | Postgres، کلیدِ امضا، مخزنِ رسانه | 1–6 h | چند ساعت | dumpِ ساعتیِ پایگاهداده، رسانهٔ شبانه |
| نودِ Bitcoin یا Lightning | کیفپول، وضعیتِ کانال، macaroons | چند دقیقه (وضعیتِ کانال) | چند ساعت | دادهٔ زنجیره دوباره sync میشود؛ فقط از کلیدها بکاپ بگیرید |
| sandboxِ توسعه | معمولاً هیچچیز | N/A | N/A | فقط اسنپشات هم پاسخِ قابلِدفاعی است |
آن ردیفِ آخر ارزش دارد بلند گفته شود، چون راهنمایی دربارهٔ بکاپ انگیزهٔ آشکاری دارد که این را نگوید. بعضی ماشینها اصلاً به بکاپ نیاز ندارند. یک build agent که کلِ وضعیتش از یک مخزنِ git میآید، یک sandboxِ یکبارمصرف، یک reverse proxyِ بدونِوضعیت که پیکربندیاش در کنترلِ نسخه زندگی میکند — برایِ اینها، اسنپشاتهایِ ساعتیای که همراهِ پلن میآید یک پاسخِ کامل و قابلِدفاع است، و مقدارِ درستِ مهندسیِ بکاپ، هیچ است. دانستنِ اینکه کدامیک از سرورهایتان در آن دستهاند، بیشتر از بکاپگرفتنِ بدِ همهشان ارزش دارد.
چهچیزی را باید کپی کرد — و آن تلِ بهمراتب بزرگتری که باید نادیده گرفت
غریزه این است که کلِ دیسک را image بگیرید، و روی یک ماشینِ مجازیِ اجارهای آن غریزه اشتباه است. سیستمعامل یکبارمصرف است: یک instanceِ تازه اینجا با میانهای در حدودِ چهلویک ثانیه provision میشود، و نصبِ دوبارهٔ بستهها از رویِ یک میرورِ توزیع، سریعتر و قابلِاعتمادتر از بازیابیشان از نسخهٔ خودتان است. آنچه یکبارمصرف نیست مجموعهای بهطرزِ شگفتآوری کوچک است، و انضباطِ نامبردنِ صریحِ آن مجموعه بیشترِ کار است — بکاپی که میتوانید در یک پاراگراف توصیفش کنید، همان چیزی است که میتوانید تأییدش کنید، درحالیکه یک imageِ کلِدیسک چیزی است که فقط به آن امیدوارید.
مجموعهٔ غیرقابلجایگزین معمولاً چهار چیز است. اول، دادهٔ اپلیکیشن: maildir، دایرکتوریِ داده، مخزنِ رسانه، پوشهٔ آپلودها. دوم، پایگاهدادهها، که رفتارِ ویژهٔ خودشان را میخواهند و بخشِ بعدی به آنها میپردازد. سوم، رازها — و این همان دستهای است که آدمها فراموشش میکنند تا وقتی که گران تمام شود. کلیدهایِ خصوصیِ TLS و کلیدِ اکانتِ ACME، کلیدهایِ هاستِ SSH اگر ترجیح میدهید مجبور نشوید fingerprint را روی هر کلاینت دوباره اعتماد کنید، کلیدِ امضایِ DKIM که بدونِ آن ایمیلِ شما در احرازِ هویت شروع به شکستخوردن میکند، کلیدهایِ خصوصیِ WireGuard، و مهمتر از همه کلیدِ خصوصیِ onion service، که خودِ آدرسِ .onion است: آن را از دست بدهید و آدرس برایِ همیشه رفته، بدونِ هیچ رجیستریای در هیچکجا برایِ شکایتبردن. چهارم، آن مشتِ فایلهایِ زیرِ /etc که واقعاً تغییرشان دادهاید، بهعلاوهٔ واحدهایِ systemd، ورودیهایِ cron و مجموعهقوانینِ فایروال که رفتارِ ماشین را همانطور که هست شکل میدهند.
تلی که باید نادیده گرفته شود بسیار بزرگتر است و وقتی بیانش کنیم، بیشترش بدیهی است. شبهفایلسیستمهایی مثلِ /proc، /sys و /dev نمایی از کرنلاند، نه داده. کشهایِ بسته، ایمیجهایِ کانتینر، محیطهایِ مجازی و دایرکتوریهایِ وابستگی، همهشان در عرضِ چند ثانیه از رویِ یک lockfile دوباره قابلِساختاند. لاگهایِ فراترِ از سیاستِ نگهداریِ شما نویزی هستند که بد deduplicate میشوند و هر اجرایِ بعدی را متورم میکنند. و مجموعهدادههایِ بزرگی که میتوان دوباره همگامسازیشان کرد — وضعیتِ بلاکچین، یک میرورِ عمومی، یک کتابخانهٔ رسانهای که میتوانید دوباره ripاش کنید — بهجایِ یک پیشفرض، سزاوارِ یک تصمیمِ صریحاند: بکاپگرفتن از سیصد گیگابایت دادهٔ زنجیره هرماه پولِ واقعی هزینه دارد، فقط برایِ اجتنابِ از یک همگامسازیِ مجدد که میتوانستید مجانی اجرایش کنید، درحالیکه سرویس افتِکیفیت دارد اما هنوز کار میکند.
بخشی که تقریباً همه رویش کمسرمایهگذاری میکنند، پاسخ به «به داخلِ چهچیزی بازیابی کنیم؟» است. داده بدونِ یک مقصد، یک بازیابی نیست. اگر روشی که سرورتان با آن ساخته شده فقط در حافظهٔ شما و یک تاریخچهٔ شل که از آنوقت گمش کردهاید وجود داشته باشد، زمانِ بازیابیِ شما نامحدود است، مهم نیست مخزن چقدر خوب باشد. راهحل ارزان و کسلکننده است: مراحلِ provisioning را بهشکلِ یک اسکریپت یا یک runbookِ متنِساده نگه دارید، آن را داخلِ مخزنِ بکاپ بگذارید تا همراهِ داده بازیابی شود، و هروقت ماشین را تغییر دادید بهروزش کنید. حتی صد خط یادداشت — بستهها، نسخهها، مکانِ فایلهایِ پیکربندی، رکوردهایِ DNS، ترتیبی که سرویسها باید در آن راهاندازی شوند — یک هفتهٔ بد را به یک بعدازظهرِ بد تبدیل میکند.
یک نکتهٔ ظریف که ارزش دارد برایِ هرکسی که رمزنگاریِ کاملِ دیسک را اجرا میکند اشاره شود: هدرِ LUKS و اسلاتهایِ کلیدش هم بخشی از مجموعهٔ غیرقابلجایگزینِ شما هستند. یک هدرِ خراب، یک دیسکِ کاملاً سالم را به نویزِ تصادفی تبدیل میکند، هدر فقط چند مگابایت است، و بکاپگرفتن از آن هیچ هزینهای ندارد. آن را بههمان دقتی که گذرواژه را نگه میدارید نگه دارید — هرکس هردویشان را داشته باشد، دیسک را دارد.
پایگاهدادهها: فایلی که کپی میکنید، پایگاهداده نیست
این رایجترین راهی است که یک بکاپِ در غیرِ اینصورت شایسته، در نهایت بیارزش از آب درمیآید. یک موتورِ پایگاهداده وضعیت را در حافظه نگه میدارد، در یک لاگِ write-ahead یا redo، و در فایلهایِ دادهای که پیوسته در حالِ تغییرند. کپیکردنِ آن فایلها درحالیکه موتور در حالِ اجراست، آنها را در لحظاتِ متفاوتی ثبت میکند — صفحهٔ چهارمِ یک جدول از پیش از یک تراکنش، صفحهٔ پنجم از بعدِ آن — و نتیجه مجموعهای از فایلهاست که هرکدام بهتنهایی سالماند اما رویِهم ناسازگار. بخشِ ظالمانهاش این است که چنین کپیای معمولاً بازیابی میشود. بالا میآید، به پرسشها پاسخ میدهد، و خرابی هفتهها بعد بهشکلِ یک ایندکسِ خراب یا یک ردیفی که محدودیتی را نقض میکند که موتور قسم میخورد اعمالش کرده، سر برمیآورد. بکاپی که با سروصدا شکست میخورد، بهمراتب بهتر از بکاپی است که بیصدا شکست میخورد.
رویکردِ درست به موتور بستگی دارد و در هر مورد بهخوبی مستند شده. برایِ MariaDB و MySQL، یک dumpِ منطقیِ گرفتهشده درونِ یک تراکنشِ واحد و سازگار، برایِ هرچیزی تا چند ده گیگابایت درست است؛ فراترِ از آن، Mariabackup درحالیکه سرور در حالِ اجراست یک کپیِ فیزیکیِ زنده انجام میدهد. برایِ PostgreSQL، pg_dump یک اسنپشاتِ منطقیِ قابلِحمل به شما میدهد، و pg_basebackup ترکیبشده با لاگهایِ write-ahead آرشیوشده، point-in-time recovery به شما میدهد — یعنی توانِ بازیابی تا ساعتِ 14:32 بهجایِ بازیابی تا هروقتی که آخرین dump اتفاقاً اجرا شده بود. برایِ SQLite، از بکاپِ آنلاینِ داخلی یا VACUUM INTO استفاده کنید؛ اجرایِ cp روی یک فایلِ زندهٔ پایگاهداده دقیقاً همان اشتباهی است که بالاتر توضیح داده شد، و SQLite موتوری است که آدمها بیشتر از همه این اشتباه را در آن مرتکب میشوند، چون شبیهِ یک فایلِ معمولی بهنظر میرسد.
سازگاری بینِ پایگاهداده و فایلهایی که توصیف میکند نیمهٔ دومِ مشکل است، و همان نیمهای است که مشخصاً نرمافزارهایِ file-sync و فروم را گاز میگیرد. پایگاهداده میگوید فایلی در فلان مسیر وجود دارد؛ فایلسیستم جایی است که بایتها واقعاً زندگی میکنند؛ اگر ساعتِ 02:00 از پایگاهداده dump بگیرید و ساعتِ 02:40 دایرکتوریِ داده را کپی کنید، هر چیزی که در این فاصله ساخته شده یا بهشکلِ بایتهایی بدونِ هیچ ردیفی وجود دارد، یا بهشکلِ یک ردیف بدونِ هیچ بایتی. اپلیکیشنهایی که یک حالتِ نگهداری ارائه میدهند — Nextcloud بارزترینش است — این را با امتناعِ کوتاه از نوشتن، درحالیکه هردو ثبت میشوند، حل میکنند. جایی که این قابلِقبول نیست، یک اسنپشاتِ فایلسیستم یا volume که در یک لحظهٔ واحد گرفته شده، یک جفتِ سازگار به شما میدهد که با خیالِ راحت از رویش کپی بگیرید، که همان ترفندی است که اسنپشاتهایِ ساعتی از آن استفاده میکنند.
یک جزئیاتِ عملیاتیِ کوچک بلافاصله هزینهٔ خودش را جبران میکند: dumpها را فشردهنشده بنویسید و بگذارید ابزارِ بکاپ فشردهسازی را انجام بدهد. هم restic و هم borg با content-defined chunking کارِ deduplicate را انجام میدهند، پس دو dump که یک روز از هم فاصله دارند اکثریتِ قریببهاتفاقِ chunkهایشان را مشترکاند و ذخیرهکردنِ دومی تقریباً هیچ هزینهای ندارد. اول dump را فشرده کنید و یکتکبایتِ تغییریافته نزدیکِ ابتدا در سراسرِ کلِ جریانِ فشردهشده آبشاری میشود، هیچ chunkای با هیچچیزی match نمیشود، و هر اجرا یک کپیِ کامل ذخیره میکند. تیمها بهطورِ منظم میبینند مخزنشان هرروز به اندازهٔ کاملِ پایگاهداده رشد میکند، دقیقاً به همین دلیل — راهحل، حذفِ یک pipe از یک shell script است.
در آخر، آگاهانه تصمیم بگیرید که آیا به point-in-time recovery نیاز دارید یا نه، چون این پاسخ به شکستی است که dumpِ روزانه نمیتواند حلش کند. اگر کسی ساعتِ 14:32 یک کوئریِ مخرب اجرا کند و شما ساعتِ 17:00 متوجهش شوید، بازیابیِ dumpِ دیشب یک روزِ کاری را از دست میدهد. آرشیوِ پیوسته درعوض لاگ را تا ساعتِ 14:31 دوباره اجرا میکند. این هم فضایِ ذخیرهسازیِ بیشتری هزینه دارد و هم پیچیدگیِ عملیاتیِ معنیداری بیشتر، پس یک پیشفرض نیست — اما برایِ هرچیزی که در آن یک انسان با دسترسیِ نوشتن میتواند سریعتر از آنکه شما متوجه شوید داده را نابود کند، این تفاوتِ بینِ یک حادثه و یک فاجعه است.
پیش از اینکه خارج شود رمزنگاری کنید: restic، borg، و کلیدی که نباید گمش کنید
ویژگیای که همهچیزِ دیگرِ این راهنما را ممکن میکند رمزنگاریِ سمتِ کلاینت است: داده روی همان ماشینی رمزنگاری میشود که تولیدش کرده، پیش از آنکه حتی یک بایت از شبکه عبور کند، با استفاده از کلیدی که مقصد هرگز نمیبیندش. همین یک تصمیمِ طراحی، مقصدِ بکاپ را به فضایِ ذخیرهسازیِ غیرقابلاعتماد تبدیل میکند، و فضایِ ذخیرهسازیِ غیرقابلاعتماد میتواند هر جایی زندگی کند — یک سرورِ ارزان در کشوری دیگر، یک object store، یک NASِ یکی از دوستانتان — بدونِ اینکه هیچکدامشان در موقعیتی باشند که بتوانند دادهتان را بخوانند. ارائهدهندههایی که سمتِ سرور رمزنگاری میکنند، دارند از شما در برابرِ مجموعهای متفاوت و بسیار محدودتر از تهدیدها محافظت میکنند، و این تفاوت دقیقاً در همان موقعیتهایی بیشترین اهمیت را دارد که هاستینگِ آفشور را برایِ دوامآوردن در برابرِ آنها میخرید.
Restic و Borg هر دو این کار را درست انجام میدهند و انتخاب بینِ آنها واقعاً نزدیک است. Restic یک باینریِ استاتیکِ تکی بدونِ هیچ وابستگیای است، فهرستِ بلندی از بکاندها را بهطورِ بومی صحبت میکند — SFTP، object storageِ سازگار با S3، مسیرهای محلیِ ساده — و اجراکردنش از داخلِ یک کانتینر یا یک imageِ مینیمال، آسانترِ آن دو تاست. Borg ابزارِ قدیمیتر و از جهاتی موشکافانهتر است، با گزینههای فشردهسازیِ قویتر، پشتیبانیِ عالی از append-only در سمتِ سرور، و قالبِ مخزنی که بسیاری آن را برای فهمیدن سادهتر میدانند؛ وقتی کار روی SSH انجام میشود باید borg روی هر دو سر نصبشده باشد، که محدودیتِ کوچکی است که گاهی همین موضوع تعیینکننده میشود.
| ویژگی | restic | borg |
|---|---|---|
| رمزنگاری سمتِ کلاینت | همیشه فعال | همیشه فعال (repokey / keyfile) |
| Deduplication | content-defined chunking، بینمیزبانی | content-defined chunking، بهازای هر مخزن |
| بکاندها | SFTP، S3، B2، Azure، محلی، REST | SSH با borg در سمتِ دیگر، محلی |
| نصب روی مقصدِ بکاپ | برای SFTP لازم نیست | لازم است |
| اجرای append-only | rest-server --append-only | borg serve --append-only |
| مرورِ یک اسنپشات بهعنوانِ فایلسیستم | restic mount | borg mount |
| کلاینتهای همزمان، یک مخزن | پشتیبانی میشود | در هر لحظه یک نویسنده |
| اعتبارسنجی | check --read-data-subset | check --verify-data |
هر کدام را که انتخاب کنید، حالا گذرواژه تمامِ ماجراست، و سزاوارِ همان رفتاری است که با seedِ کیفپول دارید. نباید فقط روی همان ماشینی زندگی کند که از آن محافظت میکند — گذرواژهای که کنارِ دادهای که رمزنگاری میکند نگهداری شود، دقیقاً در برابرِ هیچچیز از شما محافظت نمیکند، چون هر سناریویی که سرور را میبرد، کلید را هم با خودش میبرد. آن را در یک مدیرِ گذرواژه روی دستگاهی دیگر بگذارید، یا روی کاغذ در ساختمانی دیگر، و ترجیحاً هر دو. Borg به شما اجازه میدهد کلیدِ مخزن را به فایلی جدا export کنید، restic اجازه میدهد یک مخزن چندین کلیدِ مستقل داشته باشد، و هر کدام از این مکانیزمها راهِ دومی برایتان فراهم میکند که به یادآوردنِ یک رشته وابسته نیست. هیچ بازیابیای، هیچ لینکِ ریستی و هیچ تیکتِ پشتیبانیای که این را برگرداند وجود ندارد: مخزنی رمزنگاریشده بدونِ کلیدش از دادهای تصادفی قابلِتشخیص نیست، که دقیقاً همان نکته است.
ارزش دارد صریح باشیم که چرا rsyncِ ساده به یک سرورِ دیگر جایگزینِ آن نیست، چون این چیزی است که مردم اول از همه سراغش میروند. Rsync یک آینه (mirror) تولید میکند، و آینه هیچ تاریخچهای ندارد: امروز فایلی را حذف کنید، اجرایِ امشب هم وفادارانه همانجا حذفش میکند. هیچ deduplicationای ندارد، پس نگهداشتنِ سی روز یعنی سی کپی، مگر اینکه با هارد لینکها زرنگی به خرج بدهید. رمزنگاریِ درونیای برای دادهٔ درحالِ سکون ندارد، پس مقصد همهچیز را میخواند. و هیچ داستانِ اعتبارسنجیای فراتر از بازخوانیِ منبع ندارد. یک انتقالِ عالی و یک بکاپِ ضعیف است، و این تفاوت روزی نمایان میشود که به نسخهای از سه هفته پیش نیاز دارید.
Append-only باشد، وگرنه کپی است، نه بکاپ
این هم سناریویی که معماری را تعیین میکند. کسی روی سرورِ شما root میگیرد — از طریقِ یک اپلیکیشنِ patchنشده، یک توکنِ لورفته، یک وابستگیای که خصمانه شده. او حالا داخلِ ماشینی است که اعتبارنامههای معتبری برای مقصدِ بکاپِ خودش نگه میدارد، چون بکاپهای زمانبندیشده اینطور کار میکنند. هر چیزی که آن ماشین بتواند حذف کند، او هم میتواند حذف کند، و حذفِ بکاپها در یک نفوذِ مدرن فکرِ بعدی نیست، قدمِ اول است. همین بدونِ وجودِ مهاجم هم صادق است: یک اسکریپتِ خوشنیت با یک متغیرِ اشتباه، وقتی بهعنوانِ root اجرا شود، کاملاً قادر است یک مخزن را تا خالیشدنِ کامل هرس کند.
کنترلی که این را میبندد، اجرای append-only در سمتِ دریافتکننده است. با این پیکربندی، کلاینت میتواند اسنپشاتهای جدید بسازد اما نمیتواند قدیمیها را حذف یا بازنویسی کند — این محدودیت توسطِ فرآیندی روی میزبانِ بکاپ اعمال میشود، نه توسطِ حسنِنیتِ کلاینت. Borg آن را با borg serve --append-only پیاده میکند، سنجاقشده به کلید در authorized_keysِ مقصد، طوری که کلاینت نتواند چیزِ دیگری درخواست کند. Restic هم همین شکل را از طریقِ rest-server با --append-only دارد. روی object storage، معادلش نسخهبندی بهعلاوهٔ یک سیاستِ نگهداریِ object-lock است، که همان نتیجه را از طریقِ مکانیزمی متفاوت به دست میآورد.
پیکربندیِ SSH که این را ممکن میکند ارزشِ آن را دارد که دقیقاً درست تنظیم شود، چون همین خط است که کلِ سازه را نگه میدارد. در authorized_keysِ کاربرِ بکاپ، پیش از کلیدِ کلاینت یک دستورِ اجباری و محدودیتهایی را که راهنمای sshd مستند کرده بگذارید: command="borg serve --append-only --restrict-to-path /srv/backups/web01",restrict. همین یک خط یعنی کلیدی که از کلاینت دزدیده شود نمیتواند یک shell باز کند، نمیتواند پورتی را forward کند، نمیتواند به مخزنِ میزبانِ دیگری دست بزند، و نمیتواند هیچچیزی را حذف کند. به هر کلاینت، کلیدِ خودش و مسیرِ خودش را بدهید.
که سؤالِ بدیهی را پیش میکشد: اگر کلاینت هرگز نتواند حذف کند، چه چیزی اسنپشاتهای قدیمی را حذف میکند؟ هرسکردن جای دیگری اتفاق میافتد، طبقِ یک زمانبندی، با اعتبارنامهای که ماشینِ محافظتشده هرگز نداشته است. در عمل یعنی میزبانِ بکاپ مخزنهای خودش را از یک cronِ محلی هرس میکند، یا یک ماشینِ کوچکِ سوم کلیدِ ممتاز را نگه میدارد و هفتهای یکبار نگهداری را اجرا میکند. Borg اینجا یک چینوچروکِ شناختهشده دارد — یک مخزنِ append-only لازم است compactionِ آن سمتِ سرور اجرا شود، نه توسطِ کلاینت — و رفتارکردن با میزبانِ بکاپ بهعنوانِ مالکِ نگهداری این را تمیز حل میکند. اصل تعمیم پیدا میکند: ماشینی که بکاپ مینویسد هرگز نباید ماشینی باشد که میتواند آنها را نابود کند.
خودِ نگهداری یک سؤالِ سیاستی است با پاسخی متعارف که کار میکند: چند اسنپشاتِ روزانهٔ آخر، چهار یا پنج هفتگی، و شش تا دوازده ماهانه را نگه دارید. هر دو ابزار این را بهشکلِ declarative بیان میکنند، پس شما شکلی را که میخواهید اعلام میکنید و میگذارید ابزار تصمیم بگیرد کدام اسنپشاتها آن را برآورده میکنند. ماهانهها همان چیزیاند که خرابیِ آهسته را میگیرند، و همچنین همانهاییاند که مردم وقتی مخزن بزرگ میشود اول حذفشان میکنند — که دقیقاً برعکس است، چون یک ماهانهٔ فشرده و deduplicateشدهٔ یک دیتاستی که بهسختی تغییر میکند تقریباً هیچ هزینهای ندارد.
کپیِ دوم کجا میرود، وقتی هیچکس نمیتواند شما را شناسایی کند
خارج از سایت بارِ زیادی را در قاعدهٔ 3-2-1 به دوش میکشد، و روی یک ارائهدهندهٔ no-KYC معنایی مشخصتر از «ساختمانی دیگر» دارد. یعنی کپیای که بقایش وابسته به همان شرکت، همان اکانت، همان رابطهٔ پرداخت یا همان حوزهٔ قضاییِ نسخهٔ اصلی نیست. دو سرور در یک اکانت، دو سرور با یک سرنوشتاند، هرقدر هم که دیتاسنترها از هم دور باشند: اکانتی که به هر دلیلی بسته شود هر دو را با خودش میبرد، و یک ابزارِ حقوقی که به یک نهاد ابلاغ شود به هرچه آن نهاد در اختیار دارد میرسد. استقلال ویژگیِ رابطه است، نه فقط جغرافیا.
نسخهٔ عملیِ این کار، از آنچه به نظر میرسد سادهتر است، چون همان پنل همین حالا چهار حوزهٔ قضایی ارائه میدهد. یک instanceِ production در هلند که مخزنش به یک پلنِ Starter در ایسلند push میشود، ماهی $8.50 هزینه دارد و بازیابیِ شما را از دسترسِ هر فرآیندِ ملیِ واحد بیرون میبرد — و چون حوزههای قضایی در برابرِ چه چیزی واقعاً مقاومت میکنند فرق دارند، این جفتکردن ارزشِ کمی فکرکردن را دارد، نه یک شیر یا خط. از آنجا که مخزن پیش از ترکِ مبدأ رمزنگاری میشود، میزبانِ بکاپ ذاتاً نامعتمد است: چیزی که با مکانِ دوم میخرید دردسترسبودن و فاصلهٔ حقوقی است، نه محرمانگی. محرمانگی را از پیش دارید.
برای یک کپیِ سومِ واقعاً مستقل، قویترین معماری جهتِ اتصال را برعکس میکند. بهجایِ اینکه سرور به مقصدی push کند که برایش اعتبارنامه دارد، ماشینی که خودتان کنترلش میکنید — یک باکس در خانه، یک NAS، لپتاپی که طبقِ زمانبندی بیدار میشود — از سرور pull میکند. در این حالت ماشینِ production اصلاً هیچ اعتبارنامهای برای هیچ مقصدِ بکاپی ندارد، که سناریوی نفوذِ بخشِ قبل را از نظرِ ساختاری غیرممکن میکند، نه فقط تخفیفیافته. هزینهاش ماشینی است که باید طبقِ زمانبندی در دسترس یا بیدار باشد، و به همین دلیل مکملِ یک کپیِ پوششدهٔ خارج از سایت است، نه جایگزینِ آن.
| جایگذاری | هزینه | دوام در برابرِ نفوذِ میزبان | دوام در برابرِ ازدسترفتنِ اکانت | توضیحات |
|---|---|---|---|---|
| اسنپشاتِ ساعتی، همان پلن | شامل | خیر | خیر | سریعترین rollback؛ پنجرهٔ هفتروزه |
| instanceِ دوم، حوزهٔ قضاییِ دوم | از $8.50/mo | بله، اگر append-only باشد | خیر — همان اکانت | فاصلهٔ حقوقی و فیزیکیِ ارزان |
| باکسِ اختصاصی، NVMeِ آینهشده | از $39.50/mo | بله، اگر append-only باشد | خیر — همان اکانت | شکلِ درست، فراتر از چند صد گیگابایت |
| Pull از سختافزارِ خودتان | برق | بله، بهصورتِ ساختاری | بله | سرور اصلاً هیچ اعتبارنامهای ندارد |
| object storageِ شخصِ ثالث | بهازای هر GB | بله، با object lock | بله | به مسیرِ پرداختِ ناشناسِ خودش نیاز دارد |
دو محدودیتِ خاصِ این نوع هاستینگ ارزشِ گفتن بدونِ آرایش را دارند. هیچ بازیابیِ اکانتی وجود ندارد: هیچ مدرکِ هویتی برای ارائه، هیچ شمارهتلفنی برای دریافتِ کد، هیچ نمایندهای که بتواند تأیید کند شما همان کسی هستید که میگویید. این همان ویژگیای است که بابتش هنگامِ ثبتنام پول میدهید، و بهطورِ متقارن اعمال میشود — که همین باعث میشود گذرواژه و runbook به شکلی حیاتی باشند که روی یک ارائهدهندهٔ متعارف اصلاً اینطور نیستند. و اگر مقصدِ بکاپ نیاز به پرداخت دارد، باید آن پرداخت هم ناشناس انجام شود، وگرنه کپیِ دوم بیسروصدا همان پیوندِ هویتی را که اولی برای اجتناب از آن طراحی شده بود، دوباره وارد میکند. پرداختِ هزینهٔ هر دو ماشین از یک کیفپولِ کریپتوی یکسان اشکالی ندارد؛ پرداختِ بکاپ با کارت یک تصمیم است، نه یک سهلانگاری.
تمرین، و اینکه چطور میفهمید کار کردنش متوقف شده
کارهای بکاپ معمولاً بهطرزِ چشمگیری شکست نمیخورند. آنها بهتدریج شکست میخورند: یک الگوی exclude که در طولِ یک پاکسازی گستردهتر شده، اعتبارنامهای که فقط در یک طرف چرخانده شده، دیسکی که در مقصد دارد پر میشود، یک ورودیِ cron که در یک ارتقایِ توزیع گم شده. در تمامِ این موارد، ماشین به کار کردن ادامه میدهد، هیچ هشداری داده نمیشود، و مخزن بیسروصدا از رشد باز میایستد. طراحیای که این را میگیرد «هشدار در صورتِ شکست» نیست — کاری که دیگر اجرا نمیشود نمیتواند شکستِ خودش را گزارش کند — بلکه هشدار در نبودِ موفقیت است. کاری کنید هر اجرایِ موفق یک endpointِ dead-man's-switch را ping کند، و آن endpoint وقتی ping بهموقع نرسد فریاد بزند. این ده دقیقه راهاندازی است و تفاوتِ بینِ متوجهشدن در عرضِ یک روز و متوجهشدن در طولِ یک بازیابی است.
بررسیِ یکپارچگی نیمهٔ دوم است. هر دو ابزار میتوانند تأیید کنند که متادیتای مخزن منسجم است، و مفیدتر از آن، که chunkهای ذخیرهشده واقعاً رمزگشایی میشوند و با هششان مطابقت دارند. خواندنِ همهچیز از نظرِ پهنایباند پرهزینه است، پس هر دو یک شکلِ جزئی ارائه میدهند — restic درصدی از داده را در هر اجرا بررسی میکند، borg داده را درصورتِ تقاضا اعتبارسنجی میکند — و یک ریتمِ معقول، یک بررسیِ کاملِ متادیتا بهصورتِ هفتگی و یک بررسیِ جزئیِ داده بهصورتِ ماهانه است، بهاندازهای که یک پاسِ کامل در طولِ یک فصل اتفاق بیفتد. فضای ذخیرهسازی واقعاً فاسد میشود، و هدفِ بررسی این است که درحالیکه هنوز کپیِ دیگری دارید از آن باخبر شوید.
هیچکدام از اینها مدرک نیست که میتوانید بازیابی کنید. آن مدرک دقیقاً یک منبع دارد، که همان بازیابیکردن است. یک instanceِ تازه deploy کنید — کوچکترین پلن $8.50 است و ظرفِ یک ساعت نابودش میکنید — مخزن را در آن بازیابی کنید، و بعد کاری را انجام دهید که مردم ردش میکنند: اپلیکیشن را استارت بزنید و به دادهٔ واقعی نگاه کنید. لاگین کنید. سندی از ماهِ پیش را باز کنید. یک پیامِ آزمایشی از طریقِ سرورِ ایمیل بفرستید. جدولی را کوئری بزنید که باید ردیفهای دیروز را داشته باشد. وجودِ فایلها آزمون نیست؛ کار کردنِ سرویس روی آنها آزمون است. این کار را بارِ اولی که بکاپ را راه میاندازید انجام دهید، و بعد در فاصلههای تقویمیای که واقعاً رعایتشان میکنید، چون تمرین runbook را هم اعتبارسنجی میکند، و runbook سریعتر از داده کهنه میشود.
| بررسی | تناوب | چه چیزی را ثابت میکند |
|---|---|---|
| pingِ dead-man's-switch بعدِ هر اجرا | هر اجرا | کار هنوز اجرا میشود و هنوز موفق است |
| بررسیِ متادیتای مخزن | هفتگی | ایندکس و ساختارِ اسنپشات منسجماند |
| اعتبارسنجیِ جزئیِ داده | ماهانه | chunkهای ذخیرهشده رمزگشایی میشوند و با هششان مطابقت دارند |
| بازیابیِ یک فایل روی ماشینِ زنده | ماهانه | اعتبارنامه، گذرواژه و مسیر هنوز کار میکنند |
| بازیابیِ کامل روی یک سرورِ یکبارمصرف | فصلی | اپلیکیشن واقعاً برمیگردد |
| بازخوانیِ runbook در طولِ بازیابی | فصلی | دستورالعملها با ماشینِ فعلی مطابقت دارند |
runbook سزاوارِ پاراگرافِ خودش است چون ارزانترینِ آیتمهای اینجاست و بیشتر از همه گم میشود. بهترتیب بنویسید: مخزن کجا زندگی میکند و چطور به آن دسترسی پیدا کنید، گذرواژه کجا نگهداری میشود، چطور ماشینِ جایگزین را provision کنید، کدام بستهها و کدام نسخهها را نصب کنید، چه چیزی را به چه ترتیبی بازیابی کنید، کدام رکوردهای DNS را تغییر دهید، و چطور تأیید کنید که کار کرده. آن را بیرون از ماشینی که توصیفش میکند نگه دارید — در خودِ مخزن، در یک مدیرِ گذرواژه، روی کاغذ — و فرض کنید کسی که آن را میخواند خسته است، در ساعتی ناخوشایند کار میکند، و احتمالاً خودِ شما نیست. همین فرضِ آخر است که مجموعهای از یادداشتها را به چیزی تبدیل میکند که یک همکار یا یکی از اعضای خانواده بتواند اجرایش کند.
روی هم که بگذاریم، کلِ این طراحی چشمگیر نیست و همین فضیلتش است: اسنپشاتهای ساعتیای که پلنِ شما همین حالا برای حوادثِ چند روزِ اخیر شامل میشود، یک مخزنِ رمزنگاریشده که هر شب به یک حوزهٔ قضاییِ دوم push میشود جایی که نمیشود حذفش کرد، گذرواژهای جایی که سرور هرگز آن را ندیده، pingی که وقتی کار ساکت میشود شکایت میکند، و یک تمرین روی تقویم. هیچچیز در آن فهرست سخت نیست، بیشترش یک بعدازظهر طول میکشد، و کلِ ماجرا در ماه کمتر از قهوهای هزینه دارد که هنگامِ ازنوساختن از هیچ میخرید. اگر همین حالا دارید این را راه میاندازید، provisionِ ماشینِ دوم حدودِ یک دقیقه طول میکشد — با همان بازیابیای شروع کنید که هرگز تستش نکردهاید، چون تنها بخشِ این ماجراست که حقیقت را به شما میگوید.