دربارهٔ این فصل
یادداشتِ همراه نوارتا حالا به این فکر کردید که چطور سرویسهای بزرگ اینترنتی میتوانند میلیاردها رکورد را بدون کند شدن ذخیره کنند؟ وقتی حجم دادهها یا تعداد درخواستها آنقدر زیاد میشود که روی یک سرور جا نمیشود، چارهای نداریم جز این که سیستم را خرد کنیم. در این قسمت از شبگفتار میخواهیم ببینیم چطور میتوانیم دادهها را بین چند ماشین تقسیم کنیم تا سیستم زیر بار زیاد زانو نزند.
موضوع این بخش از کتاب «طراحی برنامههای دادهگرا» نوشته مارتین کلپمن، پارتیشنبندی (Partitioning) است که به معنای تقسیم یک پایگاه دادهٔ بزرگ به قطعات کوچکتر و توزیع آنها بین چند گره مختلف در یک کلاستر است.
اولین ایده برای تقسیم دادههای کلید-مقدار، استفاده از محدودهٔ کلید (Key Range) است. در این روش، یک بازهٔ مداوم از کلیدها به هر پارتیشن اختصاص داده میشود؛ درست مثل جلدهای یک دائرةالمعارف چاپی که حروف الفبا را به ترتیب در خود جای دادهاند. مزیت این روش این است که اسکنهای بازهای بسیار کارآمد انجام میشوند و میتوانید به راحتی دادههای یک بازه را بخوانید. مشکل اینجاست که اگر کلید شما یک تاریخ یا زمان باشد، تمام نوشتنهای جدید روی آخرین پارتیشن یعنی امروز متمرکز میشوند و بقیهٔ سرورها بیکار میمانند که به این وضعیت توزیع نامتوازن (Skew) میگویند و پارتیشن شلوغ را هات پارتیشن (Hot Partition) مینامیم.
برای حل مشکل هات پارتیشن، راه دوم یعنی هش پارتیشن (Hash Partition) به میدان میآید. در این روش، یک تابع هش (Hash) روی کلید اعمال میشود تا خروجی بهصورت تصادفی در کل بازه پخش شود. این کار باعث میشود دادهها و بار درخواستها خیلی متوازنتر بین گرهها تقسیم شوند. عیب بزرگش این است که ترتیب قرار گرفتن کلیدها از بین میرود و دیگر نمیتوانید بهینه جستجوی بازهای انجام دهید، مگر اینکه از کلیدهای ترکیبی مثل کاساندرا (Cassandra) استفاده کنید که ستون اول را هش میکند و بقیه را مرتب نگه میدارد.
قضیه وقتی پیچیدهتر میشود که پای ایندکسها (Index) به میان میآید. اگر بخواهیم روی ستونهایی غیر از کلید اصلی سرچ کنیم، به ایندکس ثانویه (Secondary Index) نیاز داریم. اینجا با دو رویکرد روبهرو میشویم؛ یا ایندکسها را به صورت محلی در همان پارتیشن داده نگه میداریم که خواندن را نیازمند جستجوی همزمان در همهٔ پارتیشنها (Scatter/Gather) میکند، یا ایندکس جهانی میسازیم که نوشتن را کندتر و پیچیدهتر میکند.
با گذشت زمان حجم دادهها تغییر میکند یا سروری از کار میافتد و ما به بازتوازن (Rebalancing) نیاز پیدا میکنیم تا بار سیستم دوباره روی گرهها به توازن برسد. اگر بخواهیم تعداد پارتیشنها را با تغییر تعداد گرهها هماهنگ کنیم، روشهایی مثل ایجاد تعداد زیادی پارتیشن ثابت از ابتدا یا ایجاد پویای پارتیشنها به داد ما میرسند تا مجبور نباشیم کل دادهها را جابهجا کنیم.
وقتی کلاستر ما پارتیشنبندی شد، پرسش اینجاست که درخواست کاربر چطور به سرور درست میرسد. اینجاست که مسیریابی درخواست (Request Routing) اهمیت پیدا میکند. سیستمهایی مثل کافکا (Kafka) و اچبیس (HBase) برای پیگیری اینکه هر پارتیشن روی کدام گره است از سرویسهای هماهنگکننده مثل زوکیپر (ZooKeeper) استفاده میکنند، در حالی که برخی دیگر از پروتکلهای شایعهپراکنی (Gossip) بهره میبرند.
پیشنهاد کاربردی من این است که همیشه پیش از رشد ناگهانی ترافیک، استراتژی کلیدگذاری را طوری طراحی کنید که روی یک کلید خاص بار بیش از حد نیفتد و اگر کاربر خاصی دارید که درخواستهایش سیلآساست، حتماً پیشوند یا پسوند تصادفی به کلیدهایش اضافه کنید تا سیستم زیر بار له نشود.
امیدوارم این مرور کوتاه به شما کمک کرده باشد دید بهتری نسبت به مقیاسپذیری پایگاههای داده پیدا کنید. تا قسمت بعدی، پاینده و پیروز باشید.