در این مقاله، در خصوص معماری HDFS در آپاچی هدوپ صحبت میکنیم. از مطالب قبلی، سیستم فایل توزیع شده HDFS، میدانیم که HDFS یک سیستم فایل توزیع شده است که بروی سختافزارهای کم هزینه اجرا میشود. در این مقاله نگاهی عمیقتر به معماری HDFS در آپاچی هدوپ انداخته و خصوصیتها و ویژگیهای این پروژه محبوب را بررسی میکنیم.
موضوعاتی که در این پست، در خصوص معماری سیستم فایل HDFS در آپاچی هدوپ بررسی میشوند شامل موارد زیر هستند:
- توپولوژی Master/Slave در HDFS
- مفاهیم NameNode ، DataNode و NameNode Secondary
- بلاک دادهها در HDFS
- مدیریت تکرارها
- قابلیت آگاهی از رک[1] در HDFS
- مکانیسم خواندن و نوشتن داده در HDFS
معماری سیستم فایل توزیع شده هدوپ:
HDFS یا سیستم توزیع فایل هدوپ یک سیستم فایل با ساختار بلاکی است که در آن هر فایل به بلاکهایی با اندازههای از پیش تعیین شده تقسیم می شود. این بلاکها بصورت توزیع شده در چندین ماشین خوشه ذخیره میشوند.
معماری HDFS در آپاچی هدوپ از یک معماری Master/Slave پیروی میکند. یک خوشه HDFS متشکل از یک گره به عنوان Master (سرویس NameNode[2]) و سایر گرهها به عنوان گرههای Slave (سرویس DataNode[3]) است. HDFS میتواند بروی طیف وسیعی از ماشینهایی که از جاوا پشتیبانی میکنند اجرا شود. گرچه میتوان چندین DataNode را بروی یک ماشین اجرا کرد، اما به منظور افزایش کارآمدی، این DataNodeها بروی ماشینهای مختلف پخش میشوند.
NameNode:
سرویس NameNode سرویس مدیریتی در سیستم فایل هدوپ میباشد. وظیفه اصلی این سرویس مدیریت تمام گرههای Slave و در حقیقت کل سیستم فایل HDFS میباشد. در شکل زیر موقعیت قرارگیری این مولفه در HDFS نشان داده شده است.
وظایف NameNode:
- بصورت یک سرویس در گره Master بوده که مدیریت و نگهداری از DataNodeها را انجام میدهد.
- متادادههای تمام فایلها، برای مثال محل ذخیرهسازی بلاکها ، اندازه فایلها، دسترسیها، ساختار درختی و غیره را در خوشه ضبط میکند. برای ذخیرهسازی این اطلاعات، دو نوع فایل بصورت متاداده هستند:
- FsImage: این فایل شامل وضعیت کامل فضای نام سیستم فایل از ابتدای راهاندازی خوشه HDFS است.
- EditLogs: این فایل شامل تمام تغییرات ایجاد شده در سیستم فایل HDFS پس از آخرین تغییرات موجود در فایل FsImage میباشد.
- NameNode از تمام تغییرات در سیستم فایل باخبر میشود و متاداده مرتبط با آن تغییرات را بروزرسانی میکند. برای مثال، اگر یک فایل از HDFS حذف شود، NameNode سریعا این تغییرات را در فایل EditLogs ذخیره میکند.
- این سرویس دایماً پیامهای گزارش بلاک[4] و ضربان قلب[5] را از گرههای Slave در خوشه دریافت میکند تا از وضعیت لحظهای آنها باخبر شود.
- سرویس NameNode لیست تمام بلاکهای سیستم فایل را در خود دارد و میداند هریک از این بلاکها در کدام گره ذخیره شدهاند.
- NameNode همچنین وظیفه مدیریت تکرار تمام بلاکها در سیستم فایل را برعهده دارد.
- درصورت خرابی هریک از گرههای Slave، NameNode تصمیم میگیرد که در یک Slave جدید یک کپی دیگر از دادههای از دست رفته ایجاد کند تا سطح تکرار بلاکها حفظ شود. همچنین برقرار سطح توازن داده و ترافیک شبکه در سطح خوشه نیز از دیگر وظایف سرویس NameNode بشمار میرود.
DataNode:
DataNodeها، گرههایSlave در سیستم HDFS هستند. برخلاف NameNode که پیشنهاد میشود دارای سختافزاری با ظرفیت محاسباتی بالا باشد؛ برای گرههای Slave میتوان از سختافزارهای مقرون بصرفه (سختافزاری که میتواند دارای کیفیت بالا یا قابلیت دسترسی بالا نباشد) استفاده کرد. در واقع گره Slave یک ماشین سرور است که دادهها را در سیستم فایل محلی خود نظیر ext3 یا ext4 ذخیره میکند.
عملکردهای سرویس DataNode:
- DataNode سرویسی است که بروی هرکدام از ماشینهای Slave اجرا میشود.
- دادههای واقعی HDFS در گرههای Slave ذخیره میشوند.
- سرویس DataNode درخواستهای خواندن یا نوشتن از کلاینتها را اجرا میکند.
- بصورت متناوب ضربان قلب را به NameNode ارسال میکند تا سلامتی کلی HDFS را گزارش کند. بصورت پیشفرض، این تناوب برای هر 3 ثانیه تعیین شده است.
تاکنون، متوجه شدهاید که NameNode اهمیت بسیاری دارد. اگر این گره در عملکرد خود دچار اشکال شود، تمام سیستم فایل دچار اشکال میشود. در واقع معماری HDFS دارای یک نقطه شکست(SPOF[6]) میباشد. اما با مکانیسمهایی نظیر قابلیت دسترسپذیری بالا که در نسخه 2 هدوپ معرفی شد این مشکل برطرف شده است. در قسمتهای بعدی بیشتر در این مورد صحبت خواهیم کرد.
Secondary NameNode:
علاوه بر سرویسهای NameNode و DataNode، سرویس سومی بنام NameNode Secondary وجود دارد. این NameNode Secondary بصورت همزمان با NameNode اصلی بعنوان یک سرویس کمککننده کار میکند. البته NameNode Secondary بعنوان یک NameNode پشتیبان نیست، و اصولا دارای چنین کارکردی نیست.
عملکرد NameNode Secondary:
- NameNode Secondary بصورت مداوم در تناوبهای مشخصی تمام سیستم فایل و متادادهها را، از حافظه اصلی مربوط به NameNode خوانده و آنها را در دیسک محلی خود ذخیره میکند.
- این سرویس، مسئول درهمآمیزی EditLogs با FsImage از NameNode است.
- NameNode Secondary در فواصل زمانی مشخص EditLog ها را از NameNode دانلود کرده و با فایل FsImage درهم میآمیزد. FsImage جدید به دوباره به NameNode کپی شده و در راهاندازی بعدی هر زمان که NameNode شروع به فعالیت کند، این فایل به عنوان فضای نام سیستم فایل مورد استفاده قرار میگیرد.
از اینرو، NameNode Secondary بصورت منظم در سیستم فایل checkpointهایی را اجرا میکند. به همین دلیل، به این گره CheckpointNode هم اطلاق میشود.
بلاک:
اکنون که میدانیم دادهها در HDFS بصورت گسسته در سرتاسر گرههای Slave و به حالت بلاک ذخیره میشوند، بد نیست نگاهی به بلاک و چگونگی شکلگیری آن بیاندازیم.
بلاکها کوچکترین واحد ذخیرهسازی دادهها در HDFS هستند. بطور کلی در هر سیستم فایلی، دادهها بصورت مجموعهایی از بلاکها ذخیره میشوند. بصورت مشابه، HDFS هر فایل را بصورت بلاکها ذخیره میکند که این بلاکها در میان خوشه آپاچی هدوپ بصورت پراکنده ذخیره میشوند. اندازه پیشفرض هر بلاک در آپاچی هدوپ نسخه 2.x، 128 مگابایت (در آپاچی هدوپ نسخه 1.x 64 مگابایت) است که میتوان بر اساس نیاز، این پیکربندی را تغییر داد.
در HDFS لزومی ندارد اندازه هر فایل بصورت مضرب دقیقی از اندازه بلاک پیکربندی شده، وجود داشته باشد (128 مگابایت، 256 مگابایت و غیره). برای مثال در شکل بالا فایل «example.txt» با اندازه 514 مگابایت وجود دارد. فرض کنید که اندازه پیکربندی پیش فرض بلاکها 128 مگابایت است. در اینصورت 5 بلاک برای ذخیرهسازی این فایل ایجاد میشود. چهار بلاک اول 128 مگابایت و آخرین بلاک 2 مگابایت است.
بزرگ بودن اندازه بلاکها
یکی از دلایل اصلی اینکه اندازه بلاکها در سیستم فایل HDFS بزرگ است این است که از HDFS معمولا برای ذخیرهسازی مجموعه دادههای بزرگ در مقیاس ترابایت و پتابایت استفاده میشود. بنابراین اگر اندازه بلاک را برای مثال 4 کیلوبایت درنظر بگیریم (نظیر اندازه بلاکها در سیستم فایل در لینوکس)، تعداد بلاکها بسیار زیاد میشود و بنابراین متادادههای مربوط به بلاکها هم بسیار افزایش مییابند. در اینصورت مدیریت این تعداد زیاد از بلاکها و متادادههای آنها باعث ایجاد سَربارِ زیادی در سیستم میشود و این اصلاً مطلوب نیست.
مدیریت تکرارها[7]:
HDFS راهی مطمئن جهت ذخیره حجم زیادی از دادهها در محیطی توزیع شده، از طریق تقسیم دادهها به بلاک دادهها فراهم میکند. جهت فراهم آوردن قابلیت تحملپذیری در برابر خطا، این بلاکها در چندین گره از خوشه کپی میشوند. ضریب تکرار پیش فرض در HDFS، 3 است. البته میزان تعداد تکرارها قابل پیکربندی است. بنابراین، همانطور که در تصویر زیر هم مشخص است هر بلاک سه بار بر روی گرههای Slave مختلف ذخیره شده است (با درنظر گرفتن ضریب پیشفرض).
بنابراین در صورت ذخیره یک فایل 128 مگابایتی در HDFS با استفاده از ضریب پیشفرض، فضایی به میزان
384 مگابایت (3*128 مگابایت) اشغال خواهد شد؛ زیرا بلاکها سه بار کپی شده و هر کپی در DataNode متفاوتی ساکن میشود.
سرویس NameNode بطور متناوب گزارشی از تعداد بلاکها از سرویسهای DataNode جهت نگهداری از ضریب تکرار دریافت میکند. بنابراین هر زمان بلاکی دارای تعداد تکرار بیشتر یا کمتر از ضریب تکرار باشد، NameNode در صورت نیاز این تکرارها را پاک و یا اضافه میکند.
ویژگی آگاهی از رک[8]:
به منظور افزایش قابلیت تحملپذیری در برابر خطا، سرویس NameNode اطمینان مییابد که تمام تکرارها بر روی یک گره و یا یک رک یکسان ذخیره نشوند. این سرویس از الگوریتم آگاهی از رک، برای کاهش تأخیر و همچنین افزایش تحملپذیری در خطا استفاده میکند.
با درنظر گرفتن ضریب تکرار 3، الگوریتم آگاهی از رک بدین صورت عمل میکند که اولین تکرار از یک بلاک را بر روی همان گره در رک محلی ذخیره میشود و دو تکرار بعدی در رک متفاوتی و بروی گرههای متفاوتی همانند تصویر بالا ذخیره میشوند. در صورت وجود تکرارهای بیشتر، بقیه آنها بر روی گرههای تصادفی قرار میگیرند به شرط آنکه در صورت امکان بیشتر از دو بلاک بروی یک رک یکسان قرار نگیرند. یک خوشه هدوپ را میتوان بصورت شکل زیر تصور کرد.
مزیتهای آگاهی از رک:
دلایل زیر را میتوان به عنوان مزیتهای استفاده از قابلیت آگاهی از رک در خوشه هدوپ برشمرد:
- بهبود عملکرد شبکه: ارتباط بین گرههای مستقر در رکهای مختلف در یک خوشه بوسیله سوئیچ هدایت میشود. بطور کل، پهنای باند بیشتری بین ماشینهای موجود در یک رک نسبت به ماشینهای موجود بین رکهای مختلف وجود دارد. بنابراین، آگاهی از رک کمک میکند تا ترافیک نوشتن در بین رکهای مختلف کاهش یافته و موجب فراهمشدن عملکرد نوشتاری بهتری در سطح خوشه گردد. از طرفی عملکرد خواندن هم به دلیل استفاده از پهنای باند چندین رک، افزایش مییابد.
- جلوگیری از دست رفتن دادهها: حتی در صورت خرابی یک رک به دلیل قطع برق و یا خرابی سوئیچ، هیچ نگرانی بابت از دست رفتن دادهها وجود ندارد.
معماری خواندن/نوشتن در HDFS:
در این قسمت در خصوص چگونگی عملکرد خواندن و یا نوشتن در HDFS صحبت میکنیم. HDFS از فلسفه “یکبار نوشتن و خواندن زیاد” پیروی میکند. بنابراین فایلهای از قبل ذخیره شده در HDFS قابل ویرایش نیستند. اما میتوان با بازکردن مجدد فایل، دادههای جدیدی به آن اضافه کرد. بطور کلی روال زیر را میتوان برای نوشتن دادهها در نظر گرفت.
معماری نوشتن دادهها در HDFS:
به منظور توضیح بیشتر برای مثال موقعیتی را تصور کنید که در آن کلاینت HDFS خواهان نوشتن فایلی با نام «example.txt» با اندازه 248 مگابایت است.
تصور کنید که اندازه بلاک سیستم بصورت 128 مگابایت (پیشفرض) پیکربندی شده است. در این صورت
فایل بصورت دو بلاک یعنی بلاک A با اندازه 128 مگابایت و بلاک B با اندازه 120 مگابایت تقسیم میشود.
مراحل زیر در زمان نوشتن دادهها در HDFS اجرا خواهد شد:
- اول، کلاینت HDFS برای درخواست نوشتن دو بلاک یعنی بلاکهای A و B به NameNode درخواست میدهد.
- سپس، NameNode به کلاینت اجازه نوشتن داده و آدرسهای IP DataNodeها یعنی جایی که بلاکهای فایل در آنجا نوشته میشوند را فراهم میکند.
- انتخاب آدرسهای IP گرههای DataNodeها بر اساس در دسترس بودن، ضریب تکرار و آگاهی از رک اتفاق میافتد.
- تصور کنید که ضریب تکرار 3 تعیین شده است. بنابراین NameNode برای کلاینت، فهرستی از 3 آدرس IP مربوط به DataNodeها را برای هر بلاک فراهم میکند. این فهرست برای هر بلاک منحصربهفرد است.
- تصور کنید NameNode فهرستی از IP های زیر را برای کلاینت فراهم کرده است:
- For Block A, list A = {IP of DataNode 1, IP of DataNode 4, IP of DataNode 6}
- For Block B, set B = {IP of DataNode 3, IP of DataNode 7, IP of DataNode 9}
- هر بلاک در سه DataNode مختلف جهت حفظ ضریب تکرار کپی میشود تا ضریب تکرار در سرتاسر خوشه یکسان باقی بماند.
- حال کل پردازش کپی دادهها در سه مرحله رخ میدهد:
- ایجاد خط لوله
- ارسال جریان دادهها و تکرار
- خاتمه دادن خط لوله (دریافت Ack صحت کپی داده)
ایجاد خط لوله
قبل از نوشتن بلاکها، کلاینت بررسی میکند که DataNode حاضر در هر کدام از فهرست IP ها آماده دریافت داده باشند. در انجام این کار، کلاینت یک خط لوله برای هرکدام از این بلاکها ایجاد میکند که این کار بوسیله ارتباط دادن DataNodeها در فهرست مربوط به همان بلاک انجام میگیرد. برای مثال اگر بلاک A درنظر گرفته شود، فهرست DataNodeهای فراهم شده توسط NameNode بدین صورت است:
For Block A, list A = {IP of DataNode 1, IP of DataNode 4, IP of DataNode 6}
بنابراین برای بلاک A، کلاینت گامهای زیر را برای ایجاد خط لوله اجرا میکند:
- کلاینت اولین DataNode را در این فهرست (IP های DataNode برای بلاک A) انتخاب میکند که DataNode 1 است و یک ارتباط TCP/IP شکل میدهد.
- کلاینت DataNode 1 را برای دریافت بلاک آگاه میکند. همچنین IPهای دو DataNode بعدی، یعنی جاییکه این بلاک قرار است تکرار شوند را هم برای DataNode 1 ارسال میکند.
- DataNode 1 با DataNode 4 ارتباط برقرار میکند. DataNode 1 به DataNode 4 اطلاع میدهد تا آماده دریافت این بلاک بوده و IP DataNode 6 را نیز به آن میدهد. سپس DataNode 4 به DataNode 6 اعلام میکند برای دریافت دادهها آماده باشد.
- مرحله بعد، مرحله ارسال Ack با توالی معکوس است یعنی از DataNode 6 تا 4 و سپس 1.
- سرانجام DataNode 1 به کلاینت اعلام میکند که تمام DataNodeها آماده بوده و خط لوله بین کلاینت، DataNode 1،4 و 6 ایجاد میشود.
- حال ایجاد خط لوله کامل شده و کلاینت سرانجام کپی جریان دادهها را آغاز میکند.
کپی جریان داده:
در حالی که خط لوله ایجاد میشود، کلاینت، دادهها را به سمت خط لوله ارسال میکند. به یاد داریم که در HDFS، دادهها براساس ضریب تکرار، ایجاد میشوند. بنابراین در اینجا بلاک A در سه DataNode ذخیره میشود. ذکر این نکته حایز اهمیت است که کلاینت، بلاک A را فقط به DataNode 1 ارسال میکند. کپی دادهها برای رسیدن به تعداد تکرارهای بلاک همیشه بصورت بصورت سریالی و بوسیله DataNodeها انجام میشود.
بنابراین، گامهای زیر در خلال ایجاد تکرارها رخ میدهد:
- زمانیکه این بلاک در DataNode 1 توسط کلاینت نوشته شد، DataNode 1 به DataNode 4 متصل میشود.
- سپس، DataNode 1 این بلاک را داخل خط لوله ارسال میکند و دادهها در DataNode 4 کپی میشوند.
- سپس، DataNode 4 به DataNode 6 متصل شده و آخرین تکرار بلاک را کپی میکند.
پایان کار خط لوله یا مرحله ارسال Ack:
زمانیکه این بلاک به تمام سه DataNode کپی شد، در هر گره یک Ack برای حصول اطمینان کلاینت و NameNode از اینکه
دادهها به صورت موفقیتآمیز نوشته شدهاند، شکل میگیرد. پس از دریافت Ack، کلاینت خط لوله را بسته و جلسه TCP خاتمه مییابد.
همانطور که در تصویر زیر نشان داده شده است، ارسال Ack بصورت توالی معکوس رخ میدهد یعنی از DataNode 6 به 4 و سپس DataNode 1. سرانجام DataNode 1 سه Ack(شامل خودش) را درخط لوله منتقل میکند و به کلاینت ارسال میکند. کلاینت نیز درنهایت به NameNode اطلاع میدهد که دادهها بصورت موفقیتآمیز نوشته شدهاند. NameNode، متادادههای خود را بروز رسانی کرده و کلاینت خط لوله را پایان میدهد.
بطور مشابه، بلاک B بصورت موازی با بلاک A در DataNodeهای مربوطه کپی میشود. بنابراین موارد زیر هم باید درنظر گرفته شوند:
- کلاینت بلاک A و بلاک B را به صورت همزمان به اولین DataNode ارسال میکند.
- بنابراین در این مورد، دو خط لوله برای هرکدام از بلاکها تشکیل شده و تمام پردازشهای توضیح داده شده در بالا بصورت موازی برای هر دو خط لوله رخ میدهد.
- کلاینت این بلاکها را در داخل اولین DataNode نوشته و سپس DataNodeها به صورت متوالی دادهها را در گرههای دیگر کپی میکنند.
همانطور که در تصویر بالا میبینید، برای هر بلاک دو خط لوله (A و B) ایجاد شده است. در زیر، جریان عملیات در حال اجرا، برای هر کدام از بلاکها به ترتیب خطوط لوله وجود دارد:
- برای بلاک A: 1A -> 2A -> 3A -> 4A
- برای بلاک B: 1B -> 2B -> 3B -> 4B -> 5B -> 6B
معماری خواندن HDFS:
معماری خواندن از HDFS نسبتاً آسانتر است. دوباره مثال بالا را درنظر میگیریم جاییکه کلاینت HDFS خواهان خوانده شدن فایل“example.txt” است.
گامهای زیر در خلال مرحله خواندن رخ میدهد:
- کلاینت به NameNode دسترسی پیدا کرده و درخواست متاداده بلاکهای فایل “example.txt” را برای آن ارسال میکند.
- NameNode فهرست DataNodeها یعنی جایی که هر بلاک (بلاک A و B) ذخیره شدهاند را برمیگرداند.
- بعد از آن، کلاینت به DataNodeها جایی که بلاکها ذخیره شدهاند، متصل میشود.
- کلاینت شروع به خواندن دادههای موازی از DataNodeها (بلاک A از DataNode 1 و بلاک B از DataNode 3) میکند.
- زمانیکه کلاینت تمامی بلاکهای فایلی مورد نیاز را دریافت کرد، این بلاکها را به ترتیب به یکدیگر متصل کرده تا فایل اصلی را ایجاد کند.
در هنگام رسیدگی به درخواست خواندن توسط کلاینت، HDFS نزدیکترین کپی داده به کلاینت را انتخاب میکند. این کار باعث کاهش زمان خوانده شدن و پهنای باند مصرفی میشود. بنابراین در صورت امکان، تکرارهایی از بلاک دادهها انتخاب میشود که بروی رک یکسان وجود داشته باشند. در تصویر زیر نیز روال گردش کار خواندن دادهها از HDFS نشان داده شده است.
در این مقاله سعی شد تا معماری HDFS، خصوصیات آن، نحوه خواندن و نوشتن دادهها در HDFS بررسی شود. در پستهای بعدی در مورد دیگر خصوصیات سیستم فایل HDFS نظیر قابلیتهای دسترسپذیری بالا صحبت خواهیم کرد.
[1] Rack Awareness
[2] NameNode
[3] DataNode
[4] Block Report
[5] Heartbeat
[6] Single Point of Failure
[7] Replica Management
[8] Rack Awareness