وقتی حجم دادهها و تعداد کاربران زیاد میشود، دیگر یک سرور واحد نمیتواند پاسخگوی همه درخواستها باشد. اینجاست که مفهوم کلاستر وارد عمل میشود. در کلاستر، چندین سرور با هم کار میکنند تا هم بار پردازش بین آنها تقسیم شود و هم اگر یکی از سرورها دچار مشکل شد، سیستم همچنان در دسترس بماند.
در ClickHouse هم درست مثل خیلی از سیستمهای توزیعشده، کلاستر نقش مهمی دارد. هر کلاستر از چندین نود (سرور) تشکیل شده که دادهها و پردازشها بین آنها پخش میشود. برای اینکه دادهها قابل اعتماد باشند، هر بخش داده (Shard) معمولاً چند کپی (Replica) دارد تا اگر یکی از سرورها از دسترس خارج شد، نسخه دیگری جای آن را بگیرد.
اجزای اصلی کلاستر در ClickHouse
برای اینکه یک کلاستر ClickHouse درست کار کند، چند جزء کلیدی لازم داریم:
- خود کلاستر (Cluster)
- مجموعهای از چندین نود (سرور) است که دادهها و بار پردازش بین آنها تقسیم میشود.
- هر نود بخشی از دادهها را نگه میدارد یا به عنوان کپی (Replica) از دادههای دیگر عمل میکند.
- جداول توزیعشده (Distributed Tables)
- این نوع جدول در واقع داده را ذخیره نمیکند، بلکه مثل یک دروازه ورودی عمل میکند.
- وقتی کوئری روی یک جدول توزیعشده اجرا میکنید، ClickHouse به طور خودکار آن را به تمام نودهای مربوطه میفرستد و نتایج را جمع میکند.
- بنابراین شما فقط با یک جدول کار میکنید ولی پشت صحنه داده روی چندین نود پخش شده است.
- جداول تکرارشده (Replicated Tables)
- برای اطمینان از در دسترس بودن دادهها (High Availability)، هر شارد معمولاً چند نسخه (Replica) دارد.
- این جداول به کمک Keeper با هم هماهنگ میشوند تا همه نسخهها یکسان باشند.
- اگر یکی از سرورها خراب شود، Replica دیگر همچنان میتواند داده را در اختیار سیستم قرار دهد.
خلاصه ساده
- کلاستر = مجموعهای از نودها.
- جدول توزیعشده = پخش و جمع کردن کوئریها در کل کلاستر.
- جدول تکرارشده = داشتن کپی مطمئن از دادهها برای جلوگیری از از دست رفتن اطلاعات.
اما یک پرسش کلیدی اینجاست: چه کسی بین این نسخهها هماهنگی برقرار میکند؟
اینجا پای Keeper به میان میآید.
نقش Keeper در کلاستر
وقتی دادهای در یکی از Replicaها درج میشود، لازم است همان تغییر در بقیه Replicaها هم اعمال شود. همچنین وقتی ساختار جدول تغییر میکند یا دادهای حذف و ادغام میشود، همه نسخهها باید از این تغییرات مطلع شوند.
Keeper دقیقاً مسئول این هماهنگی است.
- او مثل یک “دفتر ثبت وقایع” عمل میکند و تمام تغییرات مهم را ثبت میکند.
- هر Replica به این دفتر مراجعه میکند و میبیند چه تغییراتی رخ داده تا اگر عقب مانده بود خودش را بهروز کند.
- به همین خاطر، اگر یک سرور برای مدتی خاموش شود، بعد از بازگشت با کمک Keeper میفهمد چه چیزهایی را از دست داده و دوباره به حالت هماهنگ برمیگردد.
چرا Keeper مهم است؟
- بدون Keeper، نسخههای مختلف داده بهمرور از هم جدا میشوند و نتیجه کوئریها قابل اعتماد نخواهد بود.
- Keeper کمک میکند همه Replicaها همیشه همگام باشند.
- همچنین دستورات مدیریتی (مثل تغییر ساختار جداول در کل کلاستر) هم از طریق Keeper هماهنگ اجرا میشوند.
ClickHouse Keeper در برابر ZooKeeper
در گذشته برای این کار از ZooKeeper استفاده میشد. اما تیم ClickHouse برای سادهتر و سریعتر کردن کار، محصول مخصوص خودش به نام ClickHouse Keeper را طراحی کرد.
- این ابزار سبکتر است.
- با خود ClickHouse یکپارچهتر کار میکند.
- و معمولاً در عمل نگهداری راحتتری دارد.
جزئیات فنی و جریانهای کاری
اجزای داخلی Keeper و عملکرد Raft
- Keeper از پیادهسازی NuRaft برای الگوریتم Raft استفاده میکند و متادیتای رپلیکیشن را با لاگها و snapshotها نگهداری میکند.
- هر سرور Keeper دارای مسیر ذخیره لاگها (
log_storage_path) و مسیر ذخیره snapshotها (snapshot_storage_path) است.
- وقتی تغییراتی در وضعیت رپلیکیشن رخ میدهد (مثلاً درج جدید، الحاق پارت جدید، ادغام پارتها)، این تغییرات ابتدا در لاگ Keeper ثبت میشود و سپس Replica های دیگر آن را پردازش میکنند.
هماهنگی Replicaها و وضعیت آنها
- Replicaها هر کدام به Keeper متصلاند و تغییرات لاگ را میخوانند و سپس دادههای جدید را از منبع (مثلاً Replicaای که وظیفه درج دارد) دریافت میکنند.
- اگر یک Replica کمی عقب افتاده باشد (down بوده یا ارتباطش قطع شده باشد)، پس از بازگشت، از لاگ Keeper میخواند که کدام تغییرات جدید باید به آن ارسال شود و عملیات Catch-up انجام میدهد.
- در عملیات
ON CLUSTER یا تغییرات DDL، ClickHouse از Keeper کمک میگیرد تا مطمئن شود تغییر در همه Replica ها انتشار یابد.
نکات طراحی و توصیهها
- توصیه شده است که حداقل سه نود Keeper داشته باشی تا quorum برقرار باشد (مثلاً یک خطا را تحمل کند).
- اگر بار کاری ClickHouse زیاد باشد، اجرای Keeper روی همان سرور ممکن است باعث رقابت بر منابع (CPU، I/O) شود. پس معمولاً ترجیح داده میشود Keeper جداگانه باشد.
- در پیکربندی جدولهای ReplicatedMergeTree، نیازی نیست کاربر مستقیماً با Keeper کار کند — ClickHouse داخلِ موتور رپلیکیشن با Keeper تعامل دارد.
- هنگام افزودن یا حذف نود از کلاستر، وضعیت Keeper باید به روز شود تا Replica جدید بتواند با لاگ هماهنگ شود.