فایلسیستم ZFS یکی از پیشرفتهترین فایلسیستمهای بازمتنی است که امروزه موجود است. ZFS در سال ۲۰۰۷ توسط Jakub Dawidek از سیستمعامل OpenSolaris برای FreeBSD پورت شد. در سال ۲۰۱۰ پروژه OpenSolaris تعطیل شد و توسعه اصلی ZFS به صورت انحصاری و غیر آزاد ادامه یافت. اما نسخهای که در FreeBSD وجود دارد، همچنان توسط توسعهدهندگان این سیستمعامل پشتبانی و به روز میشود و قابلیتهای جدید به آن اضافه میشوند.
حافظه
بعضی از قابلیتهای ZFS شدیدا به حافظه RAM وابسته هستند. بنابراین در سیستمهایی که حافظه RAM اندکی دارند، باید بهینه سازیهایی صورت گیرد تا بتوان حداکثر بازدهی را بدست آورد. برای استفاده از ZFS، کل حافظه سیستم در حداقلترین حالت باید ۱ گیگابایت باشد که البته دو گیگابایت یا بیشتر پیشنهاد میشود. اندازه pool و همین طور انتظاراتی که شما از ZFS دارید، دو رکن اساسی برای تعیین کردن اندازه RAM هستند (برخی از قابلیتهای ZFS به شدت به RAM وابسته هستند). به طور کلی میتوان گفت که برای هر ۱ ترابایت اندازه pool، یک گیگابایت حافظه RAM مورد نیاز است. اما اگر میخواهید از قابلیت deduplication استفاده کنید، باید برای هر ۱ ترابایت pool، پنج گیگابایت RAM در نظر بگیرید. بعضی از کاربران حتی با اینکه حافظه RAM اندکی دارند، باز هم از ZFS استفاده میکنند، در این حالت ممکن است در مواقعی که سیستم در زیر بار سنگین است، دچار اختلال شود. در سیستمهایی که حافظه RAM در آنها کمتر از اندازه پیشنهاد شده است، ممکن است احتیاج به بهینهسازی بیشتری باشد.
پیکربندی در هسته
اگر کاربر معماری i386 هستید، به خاطر محدودیتهایی که این معماری در استفاده از RAM دارد، باید خط زیر را به فایل پیکربندی هسته اضافه کرده و آن را مجددا کامپایل و نصب نمایید. سپس سیستم خود را با استفاده از این هسته جدید بوت کنید:
options KVA_PAGES=512
این گزینه فضای آدرسدهی در هسته را افزایش میدهد. به این ترتیب میتوان مقدار vm.kvm_size را فراتر از محدودیت ۱ گیگابایتی (یا دو گیگابایتی برای PAE) که در حال حاضر دارد تنظیم کرد. برای پیدا کردن مناسب ترین مقدار برای این گزینه، فضای آدرس مورد نظر را به مگابایت تبدیل کرده و سپس آن را بر عدد ۴ تقسیم کنید. (در این مثال ما ۲ گیگابایت را بر ۴ تقسیم کردیم که نتیجه ۵۱۲ حاصل شد)
بهینهسازی بوتلودر
فضای آدرسدهی kmem را میتوان در تمامی دیگر معماریهای FreeBSD غیر از i386 هم افزایش داد. در سیستم آزمایشی ما که یک گیگابایت حافظه RAM داشت، بعد از افزودن خطوط زیر به فایل /boot/loader.conf و راهاندازی مجدد سیستم نتیجه موفقیت آمیزی حاصل شد:
vm.kmem_size="330M" vm.kmem_size_max="330M" vfs.zfs.arc_max="40M" vfs.zfs.vdev.cache.size="5M"
با اجرای دستورات زیر میتوانید قابلیت اتصال فایلسیستمهای ZFS را در هنگام بوت فعال کنید:
# echo 'zfs_enable="YES"' >> /etc/rc.conf # service zfs start
از اینجا به بعد، فرض میکنیم که سه دیسک سخت SCSI به نامهای da0، da1 و da2 در سیستم وجود دارد. اگر دیسکهای شما از نوع IDE هستند، FreeBSD آنها را با نام ad خواهد شناخت.
سیستم ZFS از چند لایه تشکیل میشود. در پایینترین لایه vnode ها قرار دارند. هر موجودیتی که قابلیت ذخیره اطلاعات را داشته باشد vnode نامیده میشود. پارتیشنها، slice ها، دیسکها، فایلها و … همه vnode هستند. در لایه بالاتر pool ها قرار میگیرند. Pool ها با دستهبندی vnode ها ایجاد میشوند. میتوانید چندین vnode را با هم ترکیب کرده و یک pool ایجاد کنید. بعد از اینکه با استفاده از vnodeها pool های مورد نیاز خود را ایجاد کردید، می توانید dataset های خود را بر روی این pool ها بنا کنید. dataset میتواند یک فایلسیستم یا یک snapshot باشد. فایلسیستمها ویژگیهای زیادی را در اختیار کاربر قرار میدهند و میتوانید آنها را به تعداد دلخواه ایجاد کنید. snapshot هم یک کپی دقیق از یک فایلسیستم در یک لحظه خاص است.
برای ایجاد یک pool ساده، متشکل از تنها یک هارددیسک، به صورت زیر عمل کنید:
# zpool create example /dev/da0
برای دیدن این pool، خروجی دستور df را بررسی کنید:
# df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235230 1628718 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032846 48737598 2% /usr example 17547136 0 17547136 0% /example
دستور بالا نشان میدهد که یک pool به نام example ایجاد و مونت شده است. هماکنون میتوانید به این pool همانند یک فایلسیستم معمولی دسترسی داشته باشید. همان طور که در مثال زیر نشان داده شده، کاربران میتوانند فایلهای دلخواه خود را در آن ایجاد کرده و از آن به صورت یک فایلسیستم معمولی استفاده کنند.
# cd /example # ls # touch testfile # ls -al total 4 drwxr-xr-x 2 root wheel 3 Aug 29 23:15 . drwxr-xr-x 21 root wheel 512 Aug 29 23:12 .. -rw-r--r-- 1 root wheel 0 Aug 29 23:15 testfile
در مثال قبل، pool ای که ایجاد کردیم اصطلاحا غیر قابل اطمینان است. یعنی اگر برای دیسک سخت مشکلی پیش بیاید، هیچ تضمینی برای نجات دادن اطلاعات آن وجود ندارد. روش بهتر برای ایجاد pool ها استفاده از تکنیک mirroring است. بدین ترتیب، از دو دیسک سخت برای ایجاد pool استفاده خواهیم کرد که اطلاعات به صورت هم زمان در هر دو دیسک ذخیره میشود. اگر یکی از آنها دچار اشکال شد، می توان اطلاعات را از دیسک دیگر بازیابی کرد. برای ساختن یک pool به صورت mirroring به این صورت عمل میکنیم:
# zpool create example mirror da0 da1
در دستور بالا، example نام این pool را مشخص میکند که شما میتوانید از هر نام دلخواهی استفاده کنید. (به غیر از کلمات رزرو شده مانند mirror و raidz) اندازه دیسکها باید با هم برابر باشد.
مثال بعدی نحوه ایجاد یک pool متشکل از چهار دیسک سخت که دو به دو با هم mirror شدهاند را نشان میدهد:
zpool create example mirror da0 da1 mirror da2 da3
با این حال، این pool هنوز هیچ یک از قابلیتهای ZFS را ندارد. برای استفاده از قابلیتهای اصلی ZFS باید فایلسیستمهایی را بر روی آن pool ایجاد کنید. دستور زیر یک فایلسیستم بر روی این pool ایجاد کرده و قابلیت فشردهسازی را در آن فعال میکند.
# zfs create example/compressed # zfs set compression=gzip example/compressed
اکنون example/compressed یک فایلسیستم ZFS است که اطلاعات به صورت فشرده شده در آن ذخیره میشوند. سعی کنید چند فایل حجیم را در آن کپی کنید.
قابلیت فشردهسازی را میتوانید با دستور زیر غیر فعال کنید:
# zfs set compression=off example/compressed
برای unmount کردن یک فایلسیستم، دستور زیر را اجرا کرده و نتیجه را با دستور df بررسی کنید.
# zfs umount example/compressed # df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235232 1628716 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032864 48737580 2% /usr example 17547008 0 17547008 0% /example
برای اتصال مجدد فایلسیستم دستور زیر را اجرا کنید:
# zfs mount example/compressed # df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235234 1628714 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032864 48737580 2% /usr example 17547008 0 17547008 0% /example example/compressed 17547008 0 17547008 0% /example/compressed
با دستور mount هم میتوانید وضعیت pool و فایلسیستم ایجاد شده را مشاهده کنید.
# mount /dev/ad0s1a on / (ufs, local) devfs on /dev (devfs, local) /dev/ad0s1d on /usr (ufs, local, soft-updates) example on /example (zfs, local) example/data on /example/data (zfs, local) example/compressed on /example/compressed (zfs, local)
همان طور که مشاهده کردید، بعد از اینکه فایلسیستمهای ZFS را ایجاد کردید، می توانید همانند دیگر فایلسیستم های معمولی از آنها استفاده کنید. با این حال ZFS قابلیتها و ویژگیهای زیادی دارد که میتوانید آنها را بر روی فایلسیستمهای خود فعال کنید. در مثال پیشرو، یک فایل سیستم جدید به نام data ایجاد خواهیم کرد. از آنجا که قرار است فایلهای مهمی در این فایلسیستم ذخیره شوند، آن را طوری تنظیم میکنیم که از هر بلاک اطلاعات دو تا ذخیره کند.
# zfs create example/data # zfs set copies=2 example/data
بار دیگر با استفاده از df فایلسیستمها را بررسی میکنیم:
# df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235234 1628714 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032864 48737580 2% /usr example 17547008 0 17547008 0% /example example/compressed 17547008 0 17547008 0% /example/compressed example/data 17547008 0 17547008 0% /example/data
توجه داشته باشید که تمامی فایلسیستمهایی که در یک pool ایجاد میکنید، همگی فضایی به یک اندازه دارند. یعنی کل فضای آن pool در میان همه آن فایلسیستمها به اشتراک گذاشته میشود.
RAID-Z
راهی برای جلوگیری کردن از خراب شدن و از کار افتادن دیسکها نیست. اما تکنیکهایی وجود دارد که به کمک آنها میتوان اطلاعات آن را نجات داد. از تکنیک RAID میتوان برای جلوگیری از از دست رفتن اطلاعات در هنگام آسیب دیدن یک هارددیسک استفاده کرد. برای ایجاد یک pool از نوع RAID-Z دستور زیر را اجرا کرده و دیسکهایی که میخواهید در pool قرار گیرند را مشخص کنید:
# zpool create storage raidz da0 da1 da2
پیشنهاد میشود تعداد دیسکهای موجود در یک RAID-Z بین سه و نه تا باشد. در مواقعی که به یک pool با تعداد دیسکهای ۱۰ تا یا بیشتر نیاز دارید، آن را به قسمتهای کوچکتر بشکنید. اگر فقط دو دیسک دارید، بهتر است از قابلیت mirroring استفاده کنید.
دستور بالا یک pool با نام storage ایجاد خواهد کرد. این موضع را میتوانید به کمک دستورات df و mount بررسی کنید. دستور زیر، یک فایلسیستم جدید به نام home در داخل این pool ایجاد خواهد کرد:
# zfs create storage/home
حالا میتوان قابلیت فشرده سازی را در این فایلسیستم فعال کرد. دستور اول باعث میشود یک کپی اضافه از فایلهای موجود در آن فایلسیستم در همانجا ذخیره شود.
# zfs set copies=2 storage/home # zfs set compression=gzip storage/home
میتوان دایرکتوری خانگی کاربران را در داخل این فایلسیستم قرار دارد. کافی است اطلاعات فعلی آنها را در داخل این فایلسیستم کپی کرده و سپس یک لینک نرم مناسب ایجاد کنیم:
# cp -rp /home/* /storage/home # rm -rf /home /usr/home # ln -s /storage/home /home # ln -s /storage/home /usr/home
از این به بعد اطلاعات کاربران در داخل /storage/home ذخیره خواهد شد. برای بررسی این موضوع، یک کاربر جدید ایجاد کرده و سپس از طریق آن به سیستم وارد شده و فایلهایی را ایجاد کنید.
از فایلسیستمها میتوان snapshot ایجاد کرد. به این ترتیب میتوان بعدها از این snapshot برای برگرداندن اطلاعات استفاده کرد.
# zfs snapshot storage/home@08-30-08
توجه کنید که تنها میتوان از فایلسیستمها snapshot گرفت و از فایلها و دایرکتوریها نمیتوان snapshot گرفت. کاراکتر @ برای جدا کردن نام فایلسیستم و نام snapshot استفاده میشود. حالا فرض کنید یکی از کاربران اطلاعات مهمی را از دست داده و میخواهیم از snapshot استفاده کنیم:
# zfs rollback storage/home@08-30-08
میتوان در بازههای زمانی مختلف snapshot های مختلفی ایجاد کرد. برای دیدن لیست snapshot های موجود، کافی است دستور ls را در شاخه .zfs/snapshot موجود در آن فایلسیستم اجرا کنید. به عنوان مثال میخواهیم لیست تمام snapshot هایی که از فایلسیستم storage/home گرفتهایم را ببینیم:
# ls /storage/home/.zfs/snapshot
برای راحتی کار، می توانید اسکریپتی بنویسید که در بازههای زمانی مختلف از فایلسیستمها snapshot تهیه کند. با این حال، snapshotها با گذشت زمان میتوانند مقدار زیادی از فضای ذخیرهسازی را اشغال کنند. برای پاک کردن یک snapshot کافی است به صورت زیر عمل کنید:
# zfs destroy storage/home@08-30-08
بعد از انجام این آزمایشهای اولیه، می توان فایلسیستم ایجاد شده را از /storage/home به /home منتقل کرد تا نیازی به symlink نباشد و دسترسی به آن هم راحتتر باشد:
# zfs set mountpoint=/home storage/home
برای اطمینان از اینکه فایلسیستم در مسیر /home قابل دسترس است، دستورات df و mount را اجرا کنید:
# mount /dev/ad0s1a on / (ufs, local) devfs on /dev (devfs, local) /dev/ad0s1d on /usr (ufs, local, soft-updates) storage on /storage (zfs, local) storage/home on /home (zfs, local) # df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 2026030 235240 1628708 13% / devfs 1 1 0 100% /dev /dev/ad0s1d 54098308 1032826 48737618 2% /usr storage 26320512 0 26320512 0% /storage storage/home 26320512 0 26320512 0% /home
بازیابی RAID-Z
تمام RAID های نرمافزاری روشی را برای بررسی کردن وضعیت به کاربر ارائه میدهند. برای بررسی کردن وضعیت یک RAID-Z کافی است دستور زیر را اجرا کنید:
# zpool status -x
اگر تمام pool ها سالم باشند و همه چیز عادی باشد، پیغام زیر چاپ خواهد شد:
all pools are healthy
اگر مشکلی وجود داشته باشد، مثلا یک دیسک به حالت offline رفته باشد، وضعیت pool چیزی به این صورت خواهد بود:
pool: storage state: DEGRADED status: One or more devices has been taken offline by the administrator. Sufficient replicas exist for the pool to continue functioning in a degraded state. action: Online the device using 'zpool online' or replace the device with 'zpool replace'. scrub: none requested config: NAME STATE READ WRITE CKSUM storage DEGRADED 0 0 0 raidz1 DEGRADED 0 0 0 da0 ONLINE 0 0 0 da1 OFFLINE 0 0 0 da2 ONLINE 0 0 0 errors: No known data errors
این یعنی یکی از دستگاهها قبلا توسط مدیر سیستم به حالت offline برده شده است. (در اینجا دیسک da1). احتمالا مدیر سیستم قصد داشته آن دیسک را با یک دیسک جدید جاگزین کند. هر وقت که میخواهید یک دیسک را جایگزین کنید، ابتدا باید با دستور زیر آن را به حالت offile ببرید:
# zpool offline storage da1
سپس سیستم را خاموش کرده و دیسک جدیدی را با da1 جایگزین کنید. بعد از آن سیستم را روشن کرده و سپس این دستور را اجرا کنید:
# zpool replace storage da1
حالا یک بار دیگر وضعیت pool را بررسی میکنیم. این بار از گزینه -x استفاده نمیکنیم تا خروجی را با جزئیات بیشتر ببینیم:
# zpool status storage pool: storage state: ONLINE scrub: resilver completed with 0 errors on Sat Aug 30 19:44:11 2008 config: NAME STATE READ WRITE CKSUM storage ONLINE 0 0 0 raidz1 ONLINE 0 0 0 da0 ONLINE 0 0 0 da1 ONLINE 0 0 0 da2 ONLINE 0 0 0 errors: No known data errors
همان طور که در مثال بالا میبینید، همه چیز طبق روال عادی پیش میرود.
بررسی صحت اطلاعات
ZFS برای بررسی صحت اطلاعات ذخیره شده از checksum ها استفاده میکند. این قابلیت به صورت پیش فرض فعال است. اما شما میتوانید با استفاده از این دستور آن را غیر فعال کنید:
# zfs set checksum=off storage/home
انجام این کار پیشنهاد نمیشود. چون checksum ها فضای اندکی را اشغال میکنند. به کمک آنها میتوان صحت اطلاعات ذخیره شده در دیسک را بررسی کرد. این عمل به scrubbing مشهور است.
برای بررسی صحت اطلاعات ذخیره شده در pool ای به نام storage، کافی است این دستور را اجرا کنید:
# zpool scrub storage
انجام این کار میتواند مدت زیادی طول بکشد. هر چه میزان اطلاعات ذخیره شده بیشتر باشد، این کار بیشتر طول خواهد کشید. چرا که لازم است تمام دادههای ذخیره شده بررسی شوند. اگر به هر دلیل از انجام این کار منصرف شدید، کافی است دستور زیر را اجرا کنید:
# zpool scrub -s storage
در حین انجام عمل دادهها، میتوانید با استفاده از دستور زیر از میزان پیشرفت کار آگاه شوید:
pool: storage state: ONLINE scan: scrub in progress since Tue Apr 16 17:13:12 2013 ۶٫۲۹G scanned out of 74.0G at 16.2M/s, 1h11m to go ۰ repaired, 8.50% done config: NAME STATE READ WRITE CKSUM storage ONLINE 0 0 0 raidz1 ONLINE 0 0 0 da0 ONLINE 0 0 0 da1 ONLINE 0 0 0 da2 ONLINE 0 0 0 errors: No known data errors
بعد از پایان یافتن عملیات، وضعیت pool به این صورت خواهد بود:
# zpool status storage pool: storage state: ONLINE scrub: scrub completed with 0 errors on Sat Jan 26 19:57:37 2013 config: NAME STATE READ WRITE CKSUM storage ONLINE 0 0 0 raidz1 ONLINE 0 0 0 da0 ONLINE 0 0 0 da1 ONLINE 0 0 0 da2 ONLINE 0 0 0 errors: No known data errors
سهمیه بندی یا Quota
ZFS از انواع مختلف سهمیهبندی پشتیبانی میکند: سهمیهبندی بر اساس کاربر یا گروه، سهمیه بندی عمومی و نوع refquota.
همان طور که قبلا هم گفته شد، کل فضای موجود در یک pool در بین تمام فایلسیستمهای آن pool به اشتراک گذاشته میشود و به طور کلی هر فایلسیستم میتواند از تمام ظرفیت pool استفاده کند. میتوان با استفاده از سهمیهبندی، یک فایلسیستم را طوری محدود کرد که فقط بتواند از مقدار فضای مشخصی استفاده کند. سهمیهبندی، مقدار فضایی که یک فایلسیستم میتواند استفاده کند را محدود میکند. این محدودیت بر روی فایلسیستمهای زیرین آن فایلسیستم هم اعمال میشود. از این قابلیت میتوانید برای محدود کردن فضای اختصاص یافته به کاربران استفاده کنید. سهمیهبندیهای نوع عمومی را به صورت زیر می توان بر روی یک فایلسیستم اعمال کرد:
# zfs set quota=10G storage/home/bob
دستور بالا، محدودیت حداکثر ۱۰ گیگابایت فضا را بر فایلسیستم storage/home/bob اعمال میکند. یعنی فایلسیستم storage/home/bob تنها میتواند ۱۰ گیگابایت اطلاعات را دربرگیرد.
سهمیهبندی بر اساس کاربران، حدااکثر فضایی که توسط یک کاربر خاص میتواند مورد استفاده واقع شود را مشخص میکند. قالب کلی آن به شکل userquota@user=size است که قسمت user آن باید به یکی از اشکال زیر باشد:
- اسامی سازگار با POSIX مانند joe
- شماره ID کاربر مانند ۷۸۹
- اسامی SID به صورت joe.bloggs@example.com
- شماره SID کاربر به صورت S-1-123-456-789
به عنوان مثال، دستور زیر محدودیت ۵۰ گیگابایتی را بر روی کاربری به نام joe اعمال میکند:
# zfs set userquota@joe=50G
به این ترتیب joe فقط میتواند ۵۰ گیگایت اطلاعات داشته باشد. این اطلاعات میتوانند در هر جایی از دیسک که joe به آنحا دسترسی دارد قرار گیرند. اگر میخواهید این محدودیت را بردارید و یا مطمئن شوید که هیچ محدودیتی بر روی آن کاربر اعمال نشده است، دستور زیر را اجرا کنید:
# zfs set userquota@joe=none
اطلاعات مربوط به سهمیه بندی کاربران توسط دستور zfs get all نشان داده نمیشود. کاربران معمولی و غیر root تنها میتوانند اطلاعات سهمیهبندی مربوط به خودشان را ببینند. اما کاربرانی که مجوز userquota به آنها اهدا میشود، نه تنها میتوانند اطلاعات سهمیه بندی دیگران را ببینند، بلکه میتوانند آن را تغییر هم بدهند.
سهمیه بندی بر اساس گروه، مقدار فضایی که توسط یک گروه خاص میتواند مصرف شود را محدود میکند. قالب کلی آن به صورت groupquota@group=size است. برای اعمال یک محدودیت ۵۰ گیگابایتی بر روی گروهی به نام firstgroup، کافی است دستور زیر را اجرا کنید:
zfs set groupquota@firstgroup=50G
در صورتی که میخواهید این محدودیت را از این گروه بردارید، یا مطمئن شوید که محدودیتی بر روی این گروه اعمال نشده، دستور زیر را اجرا کنید:
# zfs set groupquota@firstgroup=none
کاربران معمولی و غیر root تنها میتوانند اطلاعات سهمیه بندی مربوط به همان گروهی که به آن تعلق دارند را ببینند. با این حال کاربر root و یا کاربرانی که از امتیاز groupquota برخوردار هستند، می توانند اطلاعات سهمیه بندی تمام گروهها را ببینند و ویرایش کنند.