مصاحبه ها

کاساندرا – مصاحبه با جاناتان الیس

این مطلب عیناً از وب سایت مطلبچه های مهندسی نرم افزار برداشته شده است که با همت جناب محمدعلی بزرگ زاده به زیبایی ترجمه شده است و مهندسی داده، با هدف جمع آوری مطالب مناسب فارسی در حوزه کلان داده به بازنشر آن پرداخته است .
در این مصاحبه رابرت بلومن با جاناتان الیس در حاشیه کنفرانس O’Reilly Scala سال ۲۰۱۱ گفتگو می‌کند. جاناتان، کرسی ریاستِ (Project Chair) پروژه Apache Cassandra را به عهده دارد. Cassandra یک پایگاه داده توزیع‌شده مقیاس‌پذیر و غیررابطه‌ای است که تحت تأثیر از پروژه BigTable شرکت گوگل و بسیاری از تکنیک‌های مربوط به سیستم‌های توزیع شده‌ای است که پیشگام آن مقاله Dynamo شرکت آمازون بوده است. الیس درباره مدل داده‌های Cassandra، مدل ذخیره‌سازی آن و تکنیک‌های بکار رفته در آن برای دستیابی به کارایی بالا بحث می‌کند و نگاهی به گرایش‌های خارج از پایگاه داده‌های غیررابطه‌ای می‌اندازد. (متأسفانه صدای دو دقیقه اول مصاحبه مخدوش بوده و ترجمه نشده است)
کمی در مورد تاریخچه Cassandra توضیح دهید.
Cassandra در فیسبوک آغاز شد. در تابستان ۲۰۰۸ متن باز شد. من بعداً همان سالی که پروژه به بنیاد Apache رفت، درگیرش شدم. در آن زمان آن را به Apache Incubator بردیم، در آوریل سال پیش [سال ۲۰۱۰] جواز پایان دوره را کسب کرد و ریلیز ۰٫۷ را در ژانویه [سال ۲۰۱۱] دادیم.
چرا اکنون افراد به دنبال جایگزین‌هایی برای پایگاه داده‌های رابطه‌ای می‌گردند؟
چندین دلیل دارد. ما اصطلاح کلی NoSQL را داریم که برای هر پایگاه داده غیررابطه‌ای استفاده می‌شود و انواع مختلف سیستم‌ها در این گروه قرار می‌گیرند. اما من فکر می‌کنم مشکل واقعاً جالبی که وجود داشته است، در ارتباط با مقیاس‌پذیری است. پایگاه داده‌های رابطه‌ای برای مقیاس‌‌پذیری طراحی نشده بودند و آن را خوب انجام نمی‌دهند. در واقع، با چند بخش کردن (Partitioning) یک سیستم رابطه‌ای می‌توانید آن را مقیاس‌پذیر کنید اما در نهایت با دو چیز مواجه می‌شوید. یکی اینکه [چیزی که ساخته‌اید] خیلی موردی است مثلاً نمی‌توانید یک معماری برای چندبخش کردن یک پایگاه داده رابطه‌ای برای eBay بیابید و آمازون را روی آن اجرا کنید. مطلب دیگر این است که وقتی این کار را انجام می‌دهید و برای مقیاس‌پذیری یک پایگاه داده رابطه‌ای آن را چند بخش می‌کنید، مجبورید که از مزایایی که به خاطر آن پایگاه داده رابطه‌ای را انتخاب کرده بودید، دست بکشید که در درجه اول، همان تضمین‌های ACID است. شرکت‌هایی که به مشکلات کلان‌داده‌ها برمی‌خورند، به این دو سناریو نگاه می‌کنند: یا باید چیزی بسازند که واقعاً از مزایای قدرت پلتفرم اولیه بهره نبرد یا اینکه سیستمی توسعه دهند که برای این کاربردهای موردنیاز، طراحی شده است و به این طریق، در قبال از دست دادن ACID مزایایی هم داشته باشند.
افراد سعی می‌کنند به مسائل اصولی‌تر فکر کنند و درگیر مصالحه‌هایی نشوند که وقتی چیزها در جای خودش قرار نمی‌گیرد، رخ می‌دهد.
بله، من هم همین فکر را می‌کنم. شرکت‌های بیشتری به مراکز داده‌ آن چنان حجیمی می‌رسند که دیگر با پایگاه داده‌های بر روی تک‌ماشین قابل رسیدگی نیست. و وقتی بخش کردن آن را آغاز می‌کنید، پایگاه‌ داده‌های مقیاس‌پذیر مانند Cassandra، تطبیق بیشتری با برنامه‌تان دارد.
آیا شما این دسته‌بندی پایگاه‌داده‌های غیررابطه‌ای به انواع ذخیره‌گاه کلید-‌مقدار (Key Value Store)، پایگاه‌های سندگرا (Document Oriented) و جداول بزرگ که ستون‌های هم‌خانواده (Column Family) نامیده می‌شوند را قبول دارید؟
بله، من چند سال پیش مقاله‌ای با عنوان اکوسیستم NoSQL نوشتم. یکی از چیزهایی که در آنجا در موردش صحبت کردم این است که چند جنبه‌‌ مختلف برای ارزیابی یک پایگاه داده وجود دارد. یکی از آنها مدل داده آن (Data Model) است که همان چیزی است که الان شما در موردش صحبت کردید که از این جنبه، انواع کلید-مقدار، سندگرا و ستون‌های هم‌خانواده را داریم. اما برای ارزیابی این سیستم‌ها فاکتورهای دیگری هم مطرح است. یکی از آنها مدل ذخیره‌سازی (Storage Model) است که البته به مدل داده مرتبط است اما با آن یکسان نیست. به عنوان مثال پایگاه داده‌ای با عنوان Riak وجود دارد که شرکتی با نام Basho آن را توسعه داده است، مدل داده‌ این پایگاه داده سندگرا است اما با سیستم‌های کلید-مقدار قابل جا زدن (Pluggable) پیاده‌سازی شده است بنابراین می‌توانید آن را بر روی LevelDB اجرا کنید یا بر روی Bitcask اجرا کنید که یک پایگاه داده کلید-مقدار تک‌ماشینی مجزا است. بنابراین ویژگی‌های وابسته به پیاده‌سازی خیلی متفاوتی وجود دارد. به همین ترتیب، CouchDB هم یک مدل داده سندگرا دارد اما پیاده‌سازی آن مبتنی بر B-tree است. بنابراین از لحاظ ویژگی‌های مربوط به کارایی، Bitcask با CouchDB با MongoDB کاملاً متفاوت هستند.
بیایید در مورد مدل داده‌های Cassandra صحبت کنیم. برای ما یک دید کلی از مفاهیم اصلی مدل داده Cassandra ارائه کنید.
Cassandra در اساس مدل داده خود را از BigTable گوگل گرفته است و دنیا را به شکل فضای کلیدها (KeySpace) و ستون‌های هم‌خانواده (Column Family) ارائه می‌کند که متناظر با Schema و جداول پایگاه‌‌ داده‌های رابطه‌ای است. چند تفاوت بین ستون‌های هم‌خانواده و جداول وجود دارد. یکی این است که ستون‌هایی که در ستون‌های هم‌خانواده در Cassandra وجود دارند – با اینکه بدون Schema نیستند زیرا می‌توانید ستون‌ها را حاشیه نویسی (Annotate) کنید و فرمت آن را اجبار کنید- اما یک مدل تُنُک (Sparse) دارد؛ شما می‌توانید در سطرهای خود، ستون‌هایی داشته باشید بدون اینکه لازم باشد نوع آنها را اعلان کنید و می‌توانید بعداً متادیتایی در مورد نوع داده‌هایش اضافه کنید یا اینکه به همان حالت و به شکل ستونی که پر از بایت‌ است رهایش کنید. بنابراین تفاوت این است که برای اضافه کردن یک ستون، نیازی نیست که همه سطرهای جدول را از نو تخصیص‌دهی کنید. می‌توانید به یکی از این دو صورت در نظر بگیرید که یا تغییر جدول (Alter Table) یک چیز اختیاری (Optional) است و یا اینکه کارایی آن به نسبت خیلی بالا است. در هر دو حال، خیلی خوب است.
شما بین Schemaهای بیشتر استاتیک -هرچند که توسط سرور اجبار نشده باشد- با Schemaهای بیشتر دینامیک -که در آن آزادانه ستون‌هایی اضافه می‌کنید- تفاوت قائل شده‌اید.
بله. مایلم مدل سازی کاربردهای Cassandra را به دو دسته از ستون‌های هم‌خانواده تفکیک کنم که آنها را ستون‌های ‌هم‌خانواده استاتیک و ستون‌های هم‌خانواده دینامیک نامیده‌ام. من از نظر حسی که در مورد میزان تغییراتی که در زمان اجرا رخ می‌دهد این دسته‌بندی استاتیک و دینامیک را بکار برده‌ام نه از نظر اینکه نوع داده استاتیک یا دینامیک باشد. به عبارت دیگر ستون‌های هم‌خانواده استاتیک آنهایی هستند که مثلاً برای سطرهایی هستند که نمایانگر اشیاء برنامه هستند. [آن سطرها] کمابیش ستون‌های یکسانی دارند. ممکن است ۶ ماه از استقرار وب‌سایت‌تان گذشته باشد که بخواهید به اطلاعات فردی کاربران، شماره اس‌ام‌اس را هم اضافه کنید. در اینجا مجبور نیستید که از Alter Table استفاده کنید، برنامه‌تان می‌تواند شماره اس‌ام‌اس را بدون کارهای از جنس DBA اضافه کند اما هنوز بیشتر سطرها، مجموعه ستون‌های مشترک یکسانی خواهند داشت.
نوع دیگر ستون‌های هم‌خانواده برای این استفاده می‌شود که بیانگر یک دید مجسم‌شده (Materialized View) بر روی یک سطر باشد. وقتی ما چند ریلیز دادیم یکی از موارد انتخابی User Story های جدید، مربوط به تعداد ستون‌ها بوده است. Cassandra در نسخه ۰٫۷ می‌تواند ۲ میلیون ستون در یک سطر داشته باشد. محدودیت قبلی این بود که می‌توانستید تا ۲ گیگابایت داده در یک سطر داشته باشید زیرا برای ذخیره طول آن از یک عدد صحیح ۳۲ بیتی استفاده کرده بودیم. در هر دو صورت نسبت به آنچه در سیستم‌های رابطه‌ای داشتید، از تعداد خیلی بیشتری از ستون‌ها داریم صحبت می‌کنیم. علتش حماقت ما نیست بلکه به این خاطر است که ابزاری فراهم کنیم که از الحاق کردن (Join) بپرهیزیم.
حتی در سیستم‌های رابطه‌ای، افراد آموخته‌اند که برای رسیدن به بیشترین کارایی از الحاق کردن جداول بپرهیزند اما این قضیه در سیستم‌های توزیع‌شده اهمیت بیشتری دارد که در آن سطرهایی که در جداول مختلف یا ستون‌های هم‌خانواده متفاوتی قرار دارند، در ماشین‌های مختلفی قرار گرفته‌اند، به همین علت هزینه این الحاق‌ها بیشتر می‌شود زیرا به غیر از [هزینه]جستجوی داده‌ها بر روی یک ماشین، شامل تأخیر‌های شبکه هم خواهد بود. بنابراین ما واقعاً می‌خواهیم روی این مطلب پرهیز از الحاق، تأکید کنیم. این که می‌توانید میلیون‌ها ستون را در یک سطر داشته باشید، اجازه می‌دهد که نتایج پرس‌وجو‌ها (Query) را در این سطرها دینُرمال کنیم. (دینرمال کردن در سطرهای مختلف به معنای قرار دادن اطلاعات یکسان در سطرهای مختلف و ایجاد افزونگی است و دقیقاً در مقابل طراحی نرمال در پایگاه داده‌های رابطه‌ای قرار دارد که از افزونگی پرهیز می‌شود -مترجم)
به عنوان نمونه، یکی از مثال‌های آموزشی که برای Cassandra داریم، مثال توییتر است که twissandra نامیده می‌شود. اگر به سایت twissandra.com بروید، یک دموی سبک و لینکی به سورس برنامه در GitHub وجود دارد که به زبان Python و بر روی Django نوشته شده است، یکی از ویژگی‌های عالی Python این است که خیلی خوانا است و واقعاً نیاز نیست که پیش‌زمینه Python داشته باشید، بنابراین اگر برنامه‌نویس جاوا یا هر زبان دیگری هم باشید، باز هم مثال واقعاً خوبی برایتان خواهد بود. در توییتر، پرس‌وجوی اصلی که انجام می‌شود این است: «دوستان من چه توییت‌هایی داشته‌اند؟» روشی که در پایگاه داده‌های رابطه‌ای دارید این است که یک جدول برای توییت‌ها و یک جدول برای کاربران و یک جدول برای ارتباط برقرار کردن کاربران با هم داریم که بگوییم دوستان من چه کسانی هستند. اگر بخواهید مثلاً ۵۰ توییت اخیر که دوستان من داشته‌اند را بیابید، روش کارتان اینگونه خواهد بود که ابتدا بگویید که مجموعه توییت‌هایی که دوستان من داشته‌اند چیست و با الحاق کردن جداول، سطرها را استخراج کرده و سپس نتیجه را براساس زمان منظم کرده و جواب را بدست آوریم.
این برای هر کسی که کتابی در مورد پایگاه داده‌های رابطه‌ای خوانده باشد، یک مثال طراحی کاملاً ساده با استفاده از مدل‌های نرمال‌شده خواهد بود. شما آن را با بهره‌گیری از مزیت مدل داده‌های Cassandra چطور انجام می‌دهید؟
روشی که آن را در Cassandra انجام می‌دهیم اینگونه است که یک ستون‌های هم‌خانواده مجزا برای این پرس‌وجو که «چه توییت‌هایی دوستان من داشته‌اند؟» خواهم داشت و فرضاً آن را ستون‌های هم‌خانواده Timeline می‌نامیم. من هرگاه کسی توییتی بکند برای همه افرادی که او را دنبال (Follow) می‌کنند سطری در Timeline دینُرمال می‌کنم.
در پایگاه داده رابطه‌ای، ایده این است که هر قطعه اطلاعاتی را تنها در یک جا قرار می‌دهید و به این ترتیب طراحی را نرمال می‌کنید و همواره هر اطلاعاتی که بخواهید را با تعداد کافی الحاق کردن بدست خواهید آورد. اما به نظر می‌رسد که در Cassandra ابتدا در مورد پرس‌وجو‌هایی که می‌توانید داشته باشید فکر می‌کنید و بعد برای هر کدام از آن پرس‌وجو‌ها یک محل ذخیره‌سازی می‌سازید.
دقیقاً درست است. ما در شرکت DataStax معمولاً با این مواجه می‌شویم که افراد فکر می‌کنند چون Cassandra یک دید سطر و ستونی دارد، باید از آن به شکل یک پایگاه داده رابطه‌ای ناقص استفاده کنند و همچنان یک مدل داده نرمال داشته باشند اما فقط الحاق‌ها (Join) را در طرف کلاینت انجام دهند. اما Cassandra تلاش می‌کند به جای آن، شما را به سمت مدل دینرمال هدایت کند تا شما را از شرّ خودتان در امان دارد زیرا تنها به این طریق است که می‌توانید کارایی واقعاً بالایی بدست آورید. تولید این کپی‌های اضافی، آنقدر که فکر می‌کردید، پرهزینه نیست. بیایید در زمان تولید، کمی هزینه نوشتن برای از قبل محاسبه کردن پرس‌وجو‌ها بکنید تا [پاسخ‌ دادن به] این پرس‌وجو‌ها، سبک و سریع باشد.
فرض کنید برنامه‌ای داشته باشید که روابط متعددی داشته باشد و پرس‌و‌جوهای متفاوت زیادی با مسیرهای مختلف از A به B به C، از B به C به A و … وجود داشته باشد و در نهایت به بیست نوع پرس‌وجوی مختلف برسید. در اینجا اینکه به تعداد همه روش‌های ممکنِ دسترسی به داده‌ها، هزاران کپی از داده‌های یکسانی داشته باشیم، روش کارآمدی است؟ یا این که این صرفاً یک کاربرد اشتباه از این [سیستم] ذخیره‌ی اطلاعات است؟
یک چیز مهمی که به آن اشاره نکردم این است که درست است که Cassandra از الحاق پشتیبانی نمی‌کند اما ایندکس کردن را پشتیبانی می‌کند. این امکانی است که پایگاه‌ داده‌های از نوع کلید-مقدار برای پرس‌و‌جوهای پیچیده‌تر فراهم نمی‌کنند اما Cassandra آن را دارد که به چنین برنامه‌هایی که ترکیب‌های خیلی زیادی برای پرسش‌‌ها وجود دارد و شاید پیش‌محاسبه کردن آنها از لحاظ تعداد ترکیبات ممکن، غیرعملی باشد، خیلی کمک می‌کند. البته اگر شما برنامه‌ای داشته باشید که در آن، در زمان اجرا، انواع پرس‌وجو‌های موردی رخ می‌دهد، از لحاظ مقیاس‌پذیری واقعاً با یک مسأله فوق‌العاده سخت مواجه هستید. اینکه در Cassandra الحاق نداریم، از یک حیث کار را سخت‌تر می‌کند اما هر سیستمی که الحاق داشته باشد، مجموعه مشکلات دیگری هم ایجاد می‌کند. از این نظر، اگر هم ترکیبات مختلف پرس‌وجو دارید و هم می‌خواهید مقیاس‌پذیر باشید، Cassandra به خوبی هرچیز دیگری خواهد بود.
من می‌خواهم به جنبه‌های سیستمی این پروژه بپردازم. یک مقاله از دو نفر در فیسبوک در ارتباط با Cassandra خواندم که گفته بودند ویژگی‌های اصلی Cassandra این موارد است: توزیع شده، غیرمتمرکز (Decentralized)، مقیاس‌پذیری بالا، قابلیت تحمل خطا و سازگاری قابل تنظیم (Tunable Consistency). آیا با این فهرست موافقید؟
بله، و شاید کارایی بالا هم [باید اضافه شود].
چگونه Cassandra، توزیع‌شدگی را حاصل می‌کند؟
چندین مورد است که در دسته توزیع‌شدگی قرار می‌گیرد. یکی این است که چگونه داده‌ها را بین چندین ماشین تقسیم کنم. مورد دیگر این است که حالا که داده‌ها را بین ماشین‌ها تقسیم کردم چگونه اطمینان یابم که از هرکدام چندین کپی داشته باشم؟ مورد اول بخش کردن (Partitioning) و مورد دوم، رونوشت‌برداری (Replication) نامیده می‌شود. در Cassandra، هر دو این‌ها، استراتژی‌های قابل جاگذاری (Pluggable) هستند. عموماً بخش کردن، با یک بخش‌کننده مبتنی بر درهم‌سازی سازگار (Consistent Hashing Partitioner) انجام می‌شود که بخش‌کننده تصادفی خوانده می‌شود که سطرها را بر اساس MD5 محاسبه شده از کلید اصلی‌شان، در کلاستر توزیع می‌کند. رونوشت‌برداری، مبحث جالب‌تری است چون ممکن است بخواهید به نتایج مختلفی دست یابید. مثلاً ممکن است بخواهید که از داده‌هایتان کپی‌هایی گرفته شود و تضمین بشود که حداقل یک نسخه از آنها در هرکدام از ۲ مراکز داده‌ (Data Center) [موردنظر] قرار گرفته باشد. ممکن است بگویید من ۳ مجموعه داده دارم و می‌خواهم هرکدام از آنها بر روی یکی از مراکز داده قرار بگیرد و یک کپی اصلی از همه آنها بر روی مرکز داده چهارم داشته باشم.
شما به استقرار چند مرکز داده به شکل حالتی از موارد ممکن برای توزیع‌کردن داده‌ها می‌نگرید. این طور نیست که یک کار مهندسی مجزا باشد که وقتی مراکز داده‌ها را برپا و اجرا کردیم حالا چطور چند مرکز داده‌ای را مدیریت کنیم.
این از طراحی Cassandra ناشی می‌شود که یک سیستم کاملاً توزیع‌‌شده است و در یک کلاستر Cassandra هیچ گره مخصوص متفاوتی وجود ندارد، در خیلی از سیستم‌ها و طراحی‌های قدیمی‌تر می‌دیدید که نوعی گره ارشد (Master) وجود داشت که مسئول بازه مشخصی از داده‌ها بود و درصورتی، نوشتن سریع انجام می‌شد که در همان مرکز داده گره ارشد قرار می‌گرفتید. شما نمی‌توانستید بر روی مراکز داده دیگر بنویسید، باید آن را به گره ارشد می‌فرستادید و بعد شاید با مکانیزم Log Shipping یا روش‌های مشابه بر روی مرکز داده دوم رونوشت می‌گرفتید بنابراین سیستم دومی وجود داشت که از مرکز داده منفرد اصلی رونوشت می‌شد. اما در Cassandra، مرکز داده دوم، تنها گره‌های بیشتر بر روی کلاستر است. بنابراین هنگام رونوشت‌برداری عمده کارها طوری انجام می‌شود که گویی تنها یک مرکز داده وجود دارد با این تفاوت که Cassandra متوجه این می‌شود که فاصله با [یک گره] زیاد است و هزینه [ارسال به آن] زیاد است بنابراین اگر بخواهد بر روی چند گره که بر روی یک مرکز داده قرار گرفته‌اند، رونوشت بردارد، آن را به یک گره می‌فرستد و به آن گره می‌گوید که به گره‌های دیگر که محلی خودت هستند نیز بفرست تا هزینه‌ها کمینه شود.
افراد عموماً به این شکل فکر می‌کنند که یک مرکز داده، زنده (Live) و دیگری پشتیبان (Backup) باشد. آیا شما، کل کلاستر Cassandra که در یک محدوده جغرافیایی وسیع پخش شده است را به یک شکل می‌بینید و واقعاً برایتان مهم نیست که در کجای این کلاستر می‌نویسید؟
اکثر افراد این قابلیت که بتوان به همه سیستم‌های پخش شده در مراکز داده‌ها دسترسی داشت را خیلی مفید می‌دانند زیرا به شما این اجازه را می‌دهد که اگر مثلاً دارید به [دو دسته] کاربران ساحل شرقی و ساحل غربی یا کاربران کالیفرنیا و اروپا خدمت می‌دهید، کاربران بتوانند بروزرسانی‌های خود را بر روی گره‌هایی انجام دهند که به آنها نزدیک‌تر است. می‌توانید افزونگی جغرافیایی را بصورت رایگان حاصل کنید اما شاید از این دو شاخصه کیفی، تأخیر کمتر برای مشتری‌ها، از اهمیت بیشتری برخوردار باشد.
به ما بگویید که در خلال عملیات نوشتن چه رخ می‌دهد؟
هنگام نوشتن، می‌توانید با هر گره‌ای در کلاستر Cassandra صحبت کنید و به او این حق را بدهید که نسخه‌های رونوشت را ارسال کند.
آیا کلاینت می‌تواند به هر گره‌ای در کلاستر متصل شود؟ آیا عموماً یک ترازگر بار (Load Balancer) وجود ندارد؟ یا کلاینت چطور می‌فهمد که به کدام گره متصل شود؟
راه‌های مختلفی برای آن وجود دارد، به این شکل نیست که جواب‌ها غلط باشد. روش مورد علاقه من این است که یک DNS از نوع چرخشی (Round Robin) راه بیاندازم. ما می‌بینیم که برخی مشتری‌ها از ترازگر‌های بار از قبیل HAProxy یا ترازگر‌های بار سخت‌افزاری استفاده می‌کنند و یا حتی از رهیافت‌های سمت کلاینت بهره می‌گیرند مثلاً در جاوا کلاینت‌هایی مانند Hector پشتیبانی می‌کنند که به هر گره‌ دلخواهی در کلاستر Cassandra متصل شده و از او بخواهید که در مورد گره‌های دیگر به شما اطلاع دهد و بعد اتصال‌ها را بین همه آن گره‌ها یا گره‌هایی که نسبت به مرکز داده‌اش محلی هستند، پخش کند. همچنین Cassandra از یک API هوشمند با عنوان StorageProxy پشتیبانی می‌کند که بوسیله آن کلاینت، مستقیماً داده‌ها را به ماشین‌های رونوشت (Replica) مسیردهی می‌کند. ما بر روی آن تأکید نمی‌کنیم زیرا فقط برای جاوا است اما برای افرادی که بخواهند از آن استفاده کنند، وجود دارد و در شمار معدودی از محیط‌های عملیاتی استفاده می‌شود. اکثر مشتری‌ها از ThriftAPI و بر روی آن، در جاوا از Hector و یا در Python از Picasa استفاده می‌کنند. (در نسخه ۰٫۸ از Cassandra، زبان پرس‌وجوی CQL اضافه شد و از نسخه ۱٫۲ به بعد به توسعه‌دهندگان توصیه شده است که به جای ThriftAPI از API هایی که مبتنی بر CQL برای زبان‌های برنامه‌نویسی مختلف فراهم شده است استفاده کنند -مترجم)
گره‌ای که کلاینت به آن متصل می‌شود، گره هماهنگ‌کننده (Coordinator) نامیده می‌شود و مسئول ارسال نسخه‌ها به ماشین‌های رونوشت و برگشت نتیجه موفقیت یا شکست به کلاینت براساس نتایج دریافتی از ماشین‌های رونوشت است. موفقیت یا شکست در Cassandra تا حدی یک مفهوم فازی است زیرا Cassandra از سطح سازگاری قابل تنظیم (Tunable Consistency Level) پشتیبانی می‌کند به این معنی که می‌توانید به Cassandra بگویید که عمل نوشتن را تنها در صورتی موفقیت‌آمیز درنظر بگیرد که در اکثریت رونوشت‌های آن سطر نوشته شده باشد و یا می‌توانید تنها یک رونوشت را برای موفقیت‌آمیز بودن، کافی بدانید و بپذیرید که رونوشت‌های دیگر بر روی ماشین‌هایی که الان در دسترس نیستند در آینده انجام شود.
آیا کلاینت، تعداد رونوشت‌ها در هنگام نوشتن را برای هر عملیات نوشتن، و یا برای هر ستون‌هم‌خانواده و کلاستر کنترل می‌کند؟
بله، به عبارت دیگر در ارتباط با تعداد رونوشت‌ها، دو عامل وجود دارد. یکی تعداد کلی رونوشت‌های هر سطر است که برای هر فضای‌کلید مشخص می‌شود و در آن‌جا تعیین می‌کنید که برای این مجموعه از ستون‌ها هم‌خانواده چه تعداد رونوشت کلی می‌خواهید داشته باشید. اما تعداد رونوشت‌هایی که قبل از اعلام موفقیت‌آمیز بودن عملیات، برایش منتظر می‌شویم، برای هر عملیات جداگانه می‌تواند مشخص می‌شود.
بله، دو عدد وجود دارد. یکی تعداد کلی رونوشت‌هایی است که سرانجام نوشته می‌شود و دیگری تعداد رونوشت‌هایی که نیاز دارید تا یک عملیات کلاینت برگشت داده شود.
حال، بگویید خلال خواندن چه رخ می‌دهد؟
خواندن کمی پیچیده‌تر می‌شود. در سطح بالای کار، مانند نوشتن می‌ماند تنها با این تفاوت که جهتش برعکس است. کلاینت، به هماهنگ‌کننده می‌گوید که من فلان مجموعه ستون‌ها از این سطر را می‌خواهم و هماهنگ‌کننده، می‌رود و آن را می‌آورد. اما اگر کمی عمیق‌تر شویم، کار کمی پیچیده‌تر می‌شود زیرا می‌خواهیم که عمل خواندن بصورت کارا انجام شود، به عبارت دیگر اگر ۵ کپی از یکسری از داده‌ها داشته باشیم و بخواهیم برای هر درخواستی همه آنها را واکشی کنیم باعث ترافیک زیادی در شبکه می‌شود، ما چنین چیزی را نمی‌خواهیم. بنابراین، کلاینت می‌گوید که چه سطحی از سازگاری را می‌خواهد یعنی چه تعداد رونوشت را باید مقایسه کند تا عملیات خواندن را موفقیت‌آمیز اعلام کند و مطمئن شود که داده‌های تا همان حد تازه مود درخواست کلاینت را فراهم کرده است.
Cassandra یک زیرسیستم با نام تشخیص‌دهنده خرابی (Failure Detector) دارد که از الگوریتمی استفاده می‌کند که در مقاله The Phi Accrual Failure Detector توضیح داده شده است که یک الگوریتم احتمالاتی خیلی پیچیده مبتنی بر تکنیک ضربان قلب (Heart Beat) است. می‌توانیم بگوییم که اگر از یک گره، برای چند ثانیه ضربانی دریافت نکنیم و اخیراً ترافیک شبکه فرّار بوده، ممکن است هنوز آن گره زنده باشد و اما اگر این وضعیت طول بکشد، با دقت بالایی احتمال اینکه آن گره واقعاً پایین آمده باشد زیاد می‌شود.
بنابراین با داشتن فهرستی از گره‌هایی که خراب نیستند، نزدیک‌ترین آنها را انتخاب می‌کنیم – خود اینکه چطور نزدیک بودن اندازه‌گیری می‌شود موضوع دیگری است که می‌‌شود به آن بپردازیم- و بعد به او می‌گوییم که می‌خواهیم داده‌های موجود در ستون‌های درخواست‌شده را برایمان بفرستد اما از دیگر ماشین‌های رونوشتی که برای ارضاء سطح سازگاری موردنظر، نیاز است تنها درخواست می‌کنیم که کد درهم‌سازی (Hash) ستون‌های موردنظر را بفرستند. بنابراین بدنه مجموعه نتایج تنها یکبار ارسال خواهد شد.
بنابراین، این یک سیستم بهینه‌سازی شده است زیرا در اغلب موارد این چکیده‌ها با بدنه [اصلی نتایج] تطابق خواهند داشت و به کلاینت نتایج را برمی‌گردانیم اما اگر این کدهای درهم‌سازی با هم تطابق نداشته باشند، باید یک نوبه دوم را آغاز کنم و این‌ بار درخواست دریافت همه بدنه نتایج را از همه بکنم تا بفهمم که داده چه کسی از اعتبار افتاده و کپی جدید‌تر را برایش بفرستم.
ما از تئوری Cap می‌دانیم که سیستم‌های توزیع‌شده ذخیره داده، یا در دسته‌ای می‌افتند که به سازگاری بیش از دسترس‌پذیری (Availability) تأکید دارند و یا برعکس، به سازگاری بیش از دسترس‌پذیری تأکید دارند. آیا صحیح است که بگوییم که Cassandra بیشتر به دسترس‌پذیری گرایش دارد و ممکن است داده‌ای به شما بدهد که منسوخ شده باشد؟
بیشتر مواقع در آن دسته قرار می‌گیرد اما Cassandra به شما اجازه می‌دهد که اگر بخواهید انتخاب داشته باشید. اگر درخواست سطح سازگاری حد نصاب (Quorum Consistency Level) را برای نوشتن‌ها و همین سطح دسترسی را برای خواندن‌ها هم داشته باشیم، در این صورت خواننده، همواره آخرین مقادیر نوشته شده را خواهد دید و در این صورت، سیستم سازگار خواهد بود، اما [در این شرایط] اگر فاکتور رونوشت‌برداری ۳ باشد، سطح سازگاری حد نصاب، تنها اجازه از دست رفتن یک گره را می‌دهد یعنی قبل از اینکه بگوید بعلت خرابی بیش از حد و از دست رفتن بیش از حد ماشین‌ها، دیگر نمی‌تواند درخواست‌ها را پاسخ دهد تنها اجازه از دست رفتن یک گره را می‌دهد. (طبق مستندات Cassandra معنای حد نصاب در تنظیمات Cassandra، نصف بعلاوه یک است -مترجم)
اغلب، تیم استقرار محصول می‌گوید که مشکلی ندارد که هنگام شرایط خرابی، داده‌های منسوخ شده را ببیند و می‌تواند سطح سازگاری موردنیاز را کاهش دهد تا دسترس‌پذیری بالاتر داشته باشد.
وقتی یک گره به کلاستر اضافه می‌کنید چه رخ می‌دهد؟
وقتی یک گره به کلاستر اضافه می‌کنید، گره‌های موجود، داده‌هایی که گره جدید مسئولش است را به آن روانه می‌کنند. بخشی از آن با استفاده از چیزی مشابه با درهم‌سازی سازگار (Consistent Hashing) و مسیریابی در زمان ثابت (Constant Time) بدون هیچ ارشد مرکزی (Central Master) انجام می‌شود. ما همچنان مجبور به انتقال داده‌هایی هستیم که موقعیت آنها در حلقه نشان‌ها (Token Ring) الزام می‌کند که به گره جدید تعلق داشته باشند. ما، به فرآیند انتقال داده‌ها به گره جدید در سیستم، عملیات راه‌اندازی (Bootstrapping) می‌گوییم.
جنبه مثبتش این است که با توجه به اینکه ما داده‌ها را در دیسک مدیریت می‌کنیم، می‌توانیم این‌کار را بدون هیچ عملیات I/O تصادفی انجام دهیم. همه‌اش، خواندن ترتیبی از روی یک ماشین موجود و نوشتن ترتیبی بر روی گره جدید است. بنابراین خیلی کارا و سریع است.
کلاسترهایی که مشتری‌های شما در DataStax استفاده می‌کنند چقدر بزرگ است؟
بزرگترینی که من می‌شناسم، کلاستری است که در DigitalReasoning مربوط به دولت آمریکا، اجرا شده است که بیش از ۴۰۰ گره دارد. البته از لحاظ اندازه، این مقدار غیرمتعارف است، میانگین یا متداول‌ترین اندازه کلاسترها، احتمالاً بین ۲۰ تا ۴۰ گره است البته از آن طرف هم، مشتری‌هایی داریم که با تنها ۲ گره آغاز کرده‌اند زیرا می‌خواسته‌اند که در همان حینی که مقیاس‌شان بزرگ می‌شود، Cassandra هم بزرگ شود و نمی‌خواسته‌اند که از ابتدا با یک کلاستر عظیم شروع کنند.
آیا همه گره‌ها در کلاستر، الگوریتم Phi Failure Detection را اجرا می‌کنند؟
بله.
و اگر گره‌ای، پایین بیاید و دیگر گره‌ها، با استفاده این الگوریتم، به نسبت سریع متوجه شوند که آن گره پایین آمده است، آیا گره‌ها، وارد معکوس فرآیند اضافه شدن گره می‌شوند تا برای داده‌هایی که بر روی گره خراب شده بوده است، تعداد کافی رونوشت تهیه کنند؟
سئوال خوبی است چون ما در واقع فرض نمی‌کنیم که گره بصورت دائم مرده است مگر اینکه کاربر دخالت کرده و بگوید که این گره قرار نیست برگردد زیرا شرایط متداول خرابی، انواع خرابی‌های موقتی است؛ چه اینکه سوییچ خراب شده باشد و به این دلیل شبکه از دسترس خارج شده باشد، چه اینکه مدار بیش از حد بار داشته باشد و گره پایین آمده باشد و … [در همه این شرایط] همه داده‌ها همچنان آنجا هستند. اینکه داده‌ها قطعاً از بین رفته باشند و دیگر وجود نداشته باشند به ندرت رخ می‌دهد. بنابراین ما نمی‌خواهیم که سربار بازتولید آن داده‌ها را بپردازیم مگر آنکه کسی بگوید این کار لازم است.
خوب است که فاکتور رونوشت‌برداری، به مقداری که می‌خواهید بزرگ باشد اما رایج ترین آن فاکتور رونوشت‌برداری ۳ است زیرا اگر تنها یک رونوشت داشته باشید، چند عیب دارد. یکی اینکه حدنصاب برای ۲ همچنان همان ۲ است بنابراین اگر سازگاری سطح حد نصاب داشته باشید، نمی‌توانید چیزی را از دست دهید مگر آنکه مجبور می‌شوید درخواست‌ها را پاسخ ندهید. عیب دیگر این است که اگر دو رونوشت داشته باشیم و یکی از آنها پایین بیاید، تا زمانی که دوباره رونوشت برداشته شود، واقعاً خیلی عصبی خواهیم بود زیرا تا قبل از آن فقط یک نسخه داریم که اگر آن را هم از دست بدهیم، همه چیز تمام می‌شود. اما اگر فاکتور رونوشت‌برداری ۳ داشته باشید، حتی اگر یک نسخه را از دست بدهید، همچنان احساس اطمینان خواهید داشت که همچنان دو کپی دیگر دارید و عصبی نمی‌شوید مگر آنکه دومی را هم قبل از آنکه اولی برگردد یا دوباره رونوشت‌برداری شود، از دست بدهید.
در حالتی که دو مرکز داده داشته باشید و یکی از آنها یا ارتباط بین آنها را از دست بدهید و تنظیم کرده باشید که رونوشتی بر روی مرکز داده دیگر [آنکه اکنون در دسترس نیست] قرار بگیرد، در این حالت، اگر فکر کنید که برای مدتی به آن مرکز داده دسترسی نخواهید داشت آیا در آن مرکز داده‌ای که نجات یافته رونوشت‌های به تعداد موردنظر را خواهید نوشت [شامل تعداد رونوشت‌هایی که قرار بوده در مرکز داده از دسترس ‌خارج ‌شده نوشته شود]؟
معمولاً خیر زیرا در اینجا نیز اگر کل یک مرکز داده را از دست بدهم، احتمالاً به خاطر مشکلات شبکه است و آن مرکز داده دوباره بعد از احتمالاً چندساعت یا در بدترین حالت، بعد از چند روز برخواهد گشت. در Cassandra رونوشت‌برداری می‌کنید تا از داده‌هایتان محافظت کنید نه به خاطر اینکه کارایی را بهبود دهید. افرادی که با پس‌زمینه‌های پایگاه داده‌های رابطه‌ای می‌آیند ممکن است فکر کنند که ما رونوشت‌های بیشتر را برای رسیدگی به حجم ترافیک بیشتر فراهم می‌کنیم اما روش صحیح رسیدگی به ترافیک بیشتر، اضافه کردن ماشین‌ها و پخش کردن داده‌ها بین ماشین‌های بیشتر است نه اینکه تعداد رونوشت‌ها را زیاد کنید که به معنای کپی‌های بیشتر بین همان تعداد ماشین است. هرچند برای خواندن، چکیده‌ها به جای داده‌های اصلی واکشی می‌شود اما تعمیر در خواندن (Read Repair) هم انجام می‌شود، ممکن است تحت بعضی شرایط، امکان تعمیر در خواندن را خاموش کنید، یعنی در حالت کلی این امکان وجود دارد که برخی احتیاط‌ها را انجام ندهید اما در همان پیکربندی اولیه و اصلی Cassandra، با اضافه کردن رونوشت‌های بیشتر، ظرفیت بیشتری ایجاد نمی‌کنید بلکه با اضافه کردن ماشین‌های بیشتر و پخش کردن رونوشت‌ها به شکل بی‌دوام‌تری در بین آن ماشین‌ها، این کار را می‌کنید.
شما به تعمیر در خواندن (Read Repair) اشاره کردید. به ما بگویید که چگونه کار می‌کند؟
تعمیر در خواندن به این معنی است که اگر حتی یک خواندن با سطح سازگاری مرتبه ۱ داشته باشم که فقط می‌گوید نتیجه را از نزدیک‌ترین رونوشت به من بده، در این حال نیز Cassandra، در پس‌زمینه به کارش ادامه می‌دهد و بعد از آنکه پاسخ شما را داد از دیگر رونوشت‌ها هم برای چکیده چیزی که همین حالا خوانده بود، سئوال کرده تا مطمئن شود که آن رونوشت‌ها بروز هستند. این یکی از ۳ روشی است که Cassandra رونوشت‌هایش را همگام (In Synch) نگه می‌دارد.
نمی‌توان رونوشت‌های Cassandra را طوری تخریب کرد که مجبور باشیم آنها را از نو بسازیم که یکی از ویژگی‌های خیلی خوب است که از پس‌زمینه‌ [مشکلاتِ] مربوط به پایگاه‌های رابطه‌ای می‌آید. من دیده‌ام که در PostgreSQL از روش رونوشت‌برداری Slony استفاده می‌شود که در آن تنها روش بازسازی این است که گره‌ بَرده (Slave) از نو ساخته شود.
شما نمی‌خواهید که مجبور باشید این کار را در محیط عملیاتی انجام دهید؟
نه، چون به غیر از آنکه باعث تاوان سنگینی از لحاظ کارایی می‌شود، وقتی در این شرایط قرار بگیرید که تنها یک کپی از داده‌ها باقی مانده باشد عصبی می‌شوید و اگر هنگام بازسازی، مشکلی رخ دهد، وضعیت خوبی نخواهید داشت.
Cassandra برای اینکه رونوشت‌های خود را بروز نگه دارد از ۳ روش استفاده می‌کند که عبارتند از تعمیر در خواندن (Read Repair) که به آن اشاره شد، واگذاری آیتم نشان‌خورده (Hinted Handoff) و تعمیر کل موجودیت (Entire Entity Repair). همه این اصطلاحات از مقاله Dynamo آمازون آمده است، البته به این معنی نیست که حتماً باید این مقاله را بخوانید. اما بطور خلاصه توصیح می‌دهم که دو مورد دیگر به چه معناست.
واگذاری آیتم نشان‌‌خورده به این معناست که اگر بخواهم چیزی را بنویسم و متوجه شوم که یکی از ماشین‌های رونوشت آن پایین آمده است، یکی از این دو حالت ممکن است رخ دهد: اول اینکه به تعداد کافی، ماشین رونوشت زنده (Live) برای برآورده کردن سطح سازگاری مورد نیاز را نداشته باشم؛ در این صورت، به کلاینت یک خطای عدم‌دسترسی برمی‌گردانم با این مضمون که تعداد ماشین‌های زنده لازم برای برآورده کردن درخواست شما وجود ندارد. اما در حالت دوم، اگر به تعداد کافی ماشین‌های زنده داشته باشم، به یکی از آنها، به همراه درخواست نوشتن، متادیتاهایی هم می‌فرستم که به او می‌گوید که: «در زمان برگشت فلان ماشین رونوشتی که هم‌اکنون پایین آمده است، فرآیند [نوشتن بر روی آن] را تکرار کن!». به این کار نشان زدن گفته می شود و تکرار کردن این فرآیند، واگذار می‌شود و این اصطلاح واگذاری آیتم نشان‌خورده، از آنجا آمده است.
روش سوم برای رسیدن به سازگاری، روش تعمیر کل موجودیت است. در این روش، درختی از کدهای درهم‌سازی (Hash Code) برای هر مجموعه داده موجود در یک ماشین رونوشت تهیه می‌کنیم و با مبادله این کدهای درهم‌سازی متوجه می‌شویم که کدام بلاک از داده‌ها، بروز نیست. تا وقتی که بفهمیم دقیقاً چه چیزی بروز نیست، تنها همین کدهای درهم‌سازی است که در شبکه جابجا می‌شود و بعد آن‌ها [بلاک‌ها] را تعمیر می‌کنیم.
یعنی بدون اینکه نیاز باشد کل درخت را بفرستید آن‌ها را بصورت کارا با هم مقایسه می‌کنید.
بله، در بدترین حالت، که مثلاً پوشه داده‌ها را rm -rf کرده باشیم و هیچ چیز در آن باقی نمانده باشد، کل درخت انتقال داده می‌شود اما اگر داده‌های مشترک داشته باشند، Cassandra می‌تواند از انتقال آن بخش‌ها، جلوگیری کند.
می‌خواهم بحث را عوض کرده و در مورد مدل ذخیره‌سازی (Storage Model) که به آن اشاره داشتید صحبت کنیم. در مورد مدل ذخیره‌سازی Cassandra برایمان بگویید.
تا الان که در مورد رونوشت‌برداری و سطح سازگاری صحبت می‌کردیم، Cassandra از [مقاله] Dynamo میراث گرفته بود، اما وقتی در مورد مدل ذخیره‌سازی صحبت می‌کنیم، بحث عوض می‌شود و از BigTable متأثر می‌شویم. در واقع، BigTable اولین چیزی نبود که این نحو مدل ذخیره‌سازی برای پایگاه‌های داده را توضیح می‌داد. این مبحث از مقاله‌ای با عنوان The log-structured merge-tree که در سال ۱۹۹۶ منتشر شد نشأت می‌گیرد. آن مقاله توجه زیادی به خود جلب نکرده بود تا اینکه گوگل ۱۰ سال بعد در BigTable به آن ارجاع داد.
اغلب پایگاه‌های داده از یک مدل ذخیره‌سازی مبتنی بر B-tree استفاده می‌کنند که کم‌وبیش روش بروزرسانی در محل (Update in Place) دارند. می‌توان به نوعی آن‌ها را مدل ذخیره‌سازی بروزرسانی در محل دانست که در آن بلاک مشخصی از داده وجود دارد که سطرها در آن قرار دارند و شما آنها را دنبال کرده و سطر موردنظر را یافته و ستون‌ها را مطابق با درخواست بروزرسانی می‌کنید. اما در عوض، ما در Cassandra وقتی درخواست بروزرسانی برای ستون‌های هم‌خانواده‌ای را دریافت می‌کنیم، آنها را در ساختاری قرار می‌دهیم که به آن Memtable می‌گوییم. ما تا زمانیکه Memtable پر شود، این بروزرسانی‌ها را جمع می‌کنیم و در دیسک نمی‌نویسیم. سپس Memtable را بر اساس سطرها مرتب کرده و آن را در دیسک (جاییکه به آن SSTable می‌گوییم) می‌نویسیم. وقتی در دیسک نوشتیم دیگر، تغییرناپذیر (Immutable) خواهد بود و هیچگاه بروزرسانی در محل برایش انجام نمی‌شود. ما تنها با قرار دادن یک نسخه جدید در Memtable و سرانجام نوشتن آن در فایل داده، آن را بروزرسانی می‌کنیم.
خود گره، نوشتن و خواندن خارج از Memtable را به عهده می‌گیرد؟
بله، داده‌ها در Memtable بلافاصله برای پاسخگویی به درخواست‌ها آماده هستند. مثلاً فرض کنید برای اطلاعات مربوط به هر کاربر یک سطری تخصیص یافته باشد و نام شرکت من از Riptano به DataStax تغییر یابد و در پروفایل من آدرس شرکت Riptano.com ثبت شده باشد و نام آن را به DataStax.com تغییر دهم، در آنصورت، رکورد اصلی خود را در دیسک و بر روی فایل SSTable خواهم داشت و URL جدید را در Memtable دارم که هنوز در دیسک نوشته نشده است. در این حالت، اگر کسی بیاید و معادل پرس‌وجوی Select * from user where name = ‘jonathan ellis’ را درخواست کند، Cassandra مقدار جدیدی که در Memtable نشسته است را با سطری که در دیسک قرار دارد را ادغام کرده و مقدار سرجمع آنها را می‌سازد، مابقی داده‌هایی که در دیسک قرار دارند، داده‌های جاری هستند بنابراین به همان صورت که هستند در نتیجه بازگشتی قرار می‌گیرند.
یعنی قبل از اینکه هیچ چیزی بر روی دیسک نوشته شود، عمل نوشتن بصورت موفقیت‌آمیز پایان می‌یابد؟
پاسخ کوتاه آن خیر است زیرا قبل از آنکه داده‌ها را در Memtable قرار دهیم، آنها را به CommitLog اضافه می‌کنیم. این همان نوع معماری است که پایگاه داده‌های سنتی برای پشتیبانی از مانایی (Durability) دارند. در اینجا پارامتری که قابل تنظیم است این است که هر از چند وقت می‌خواهیم CommitLog را fsync کنیم؟ یا به عبارت دیگر هر از چند وقت می‌خواهیم، از سیستم‌عامل بخواهیم که اطلاعات CommitLog را به دیسک بفرستد؟ اگر CommitLog را در وسیله (Device) مجزایی نسبت به جایی که داده‌ها را از آن می‌خوانید قرار دهید، پیوسته در حال الحاق کردن هستید که عملیات خیلی سریعی خواهد بود زیرا لازم نیست که هِد دیسک را بچرخانید. همانند Cassandra این در مورد پایگاه داده‌های رابطه‌ای که CommitLog داشته باشند نیز صادق است که باید CommitLog را در وسیله مجزایی قرار داده باشید در غیر اینصورت، کارایی بدتر می‌شود.
در محیط‌های غیرکارا نوعی روش دور زدن (Workaround) برای آن وجود دارد که هر چند ثانیه یک بار fsync کنیم. یعنی به جای اینکه نوشتن‌ها را در گروه‌های ۱۰ میلی‌ثانیه‌ای یا یک میلی‌ثانیه‌ای دسته‌بندی کنید و همه آن‌ها را با هم fsync کنیم هر چند ثانیه یک بار اینکار را می‌کنیم. بهرحال شما نمی‌خواهید که همه نوشتن‌ها را fsync کنید و نوعی دسته کردن خواهید داشت، اگر مجبور باشید که داده‌ها و CommitLog را بر روی یک دیسک به اشتراک بگذارید، می‌توانید آسان بگیرید و بگویید که مستقل از تعداد نوشتن‌هایی که خواهد آمد، هر ۱۰ ثانیه یک بار fsync می‌کنید تا به کارایی بالاتری برسید.
آنچه شما در اینجا تلاش می‌کنید انجام دهید پشتیبانی از نوشتن‌های زیاد بدون نیاز به fsync های زیاد است.
دقیقاً.
آیا برای همه زبان‌های رایج برنامه‌نویسی [برای Cassandra]، کلاینت وجود دارد؟
بستگی به این دارد که چه چیزی را «رایج» بخوانیم. دو سطح از کلاینت‌های Cassandra وجود دارد. پروتکل خامی که برای تعاملات وجود دارد یک فریم‌ورک RPC و Serialization است که Thrift خوانده می‌شود و برای زبان‌های مختلف کد تولید می‌کند. بله، من فکر می‌کنم زبان‌های رایج به خوبی پوشش داده شده‌اند. در واقع تنها موردی که من برخورد داشتم که فردی درخواست کلاینت برای آن کرده بود که Thrift آن را تولید نمی‌کرد، Delphi بود. [برای زبان‌های مختلفی کلاینت وجود دارد مثلاً] C#، Erlang، OCaml، SmallTalk، …
و Java، Perl، Ruby، Python و …
بله، Thrift حتی برخی زبان‌های گمنام را هم پشتیبانی می‌کند. اما تعبیر درست Thrift این است که آن را نوعی Driver درنظر بگیریم، چیزی مشابه libpq برای PostgreSQL است. در واقع شما اگر راهی داشته باشید، نمی‌خواهید که برنامه‌تان با فراخوانی‌های RPC موجود در Thrift کار کند. برای این منظور، چیزهای کمی بیشتری هم داریم. ما کلاینت‌هایی برای Java، Python، Ruby، PHP و C# داریم. این‌ها مواردی هستند که به خوبی پشتیبانی می‌‌شوند. اما C++ کمی حساس است، کلاینتی برای آن وجود دارد اما نیاز است که بر روی آن کار شود تا یک محیط واقعاً تمام و کمال شود. Perl هم محیط دیگری است که برای آن یک کلاینت واقعاً خوب که برای امکانات Cassandra نسخه ۰٫۷ بروز باشد وجود ندارد. این دو مورد C++ و Perl مهمترین مواردی هستند که دوست داریم، چیزهای بهتری در مورد آنها بشنویم.
آیا Cassandra چیزی مشابه با تراکنش (Transaction) را پشتیبانی می‌کند؟
چیزی مشابه با آن و نه خودش را پشتیبانی می‌کند. وقتی صحبت از تراکنش می‌شود به چیزی فکر می‌کنیم که اتمیک، مجزا (Isolated)، سازگار (Consistent) و مانا (Durable) باشد. Cassandra مانایی را به شما می‌دهد، اگر در صحبت‌های قبلی من روشن نبوده است، باید بگویم که شما قطعاً می‌توانید Cassandra را طوری تنظیم کنید که همه نوشتن‌ها، صد در صد مانا باشند و اگر برق رفت، هر نوشتنی که تصدیق (Acknowledge) شده باشد، از طریق پشتیبان‌ها، در دسترس باشد بنابراین مانایی را داریم. همینطور اتمیک بودن را با محدودیت‌هایی داریم. اتمیک بودن به این معناست که اگر درخواست نوشتنی داشتم یا همه آن انجام شود یا هیچکدامش انجام نشود. Cassandra اتمیک بودن را برای یک سطر ارائه می‌کند که همان سطحی است که ما در CommitLog قرار می‌دهیم و همان سطحی است که ما داده‌ها را مسیردهی و پارتیشن می‌کنیم.
اما مفهوم گسترده‌تر تراکنش که افراد به آن فکر می‌کنند این است که بر روی جداول مختلف بروزرسانی داشته باشند و می‌خواهند همه آن به صورت یک گروه رخ دهد. Cassandra اتمیک بودن بر روی سطر‌های مختلف را پشتیبانی نمی‌کند اما آنچه پشتیبانی می‌کند، مفهومی است که دسته (Batch) نام دارد که همان چیز مشابه با تراکنش است که Cassandra دارد. می‌توانید دسته‌ای از بروزرسانی‌ها داشته باشید که آن را به Cassandra بفرستید. آنچه باید نگرانش باشید این است که گره هماهنگ‌کننده (Coordinator Node)، در خلال کار، خراب شود. این، یک حالت حاشیه‌ای (Edge Case) است که در این مورد وجود دارد. اگر گره هماهنگ‌کننده، در خلال کار خراب شود، کلاینت باید به سراغ گره دیگری برود که با آن صحبت کند (یک گره هماهنگ‌کننده جدید). این یکی از کارهایی است که کلاینت‌های خوب مانند Hector و Picasa برایتان انجام می‌دهند. بعد، دوباره تلاش می‌کنید که دسته مورد نظر را اجرا کنید. ویژگی دسته‌ها این است که حتی اگر بخشی از آن از قبل اعمال شده باشد، تلاش دوباره برای آن، خنثی می‌شود و تنها بخش‌هایی که قبلاً انجام نشده بودند انجام می‌شوند و بخش‌هایی که قبلاً انجام شده بودند تخریب نمی‌شوند و همه چیز خوب خواهد بود.
اگر یک پایگاه داده خیلی دینرمال شده‌ای طراحی کنید که برای پرس‌وجو‌های مختلف، نسخه‌های مختلفی از داده‌های یکسانی وجود داشته باشد، می‌توانید دسته‌هایی (Batch) داشته باشید که بخشی از آن کامل شده باشد. در این صورت، آیا کلاینت‌ها نباید برای رسیدگی به این شرایط -آنچه ما آن را «خرابی‌های یکپارچگی‌های ارجاعی در حین خواندن» (Referential Integrity Failures During Reads) می‌نامیم- آماده باشند؟
اگر کاملاً دینرمال نباشید و تنها تاحدی دینرمال کرده باشید، باید نگرانش باشید زیرا تاحدی دینرمال کردن به این معنی است که برخی الحاق‌ها را در سمت کلاینت انجام خواهید داد، در این صورت باید نگرانش باشید. اما اگر کاملاً دینرمال کرده باشید که هر پرس‌وجویی از یکی از آن سطرهای داخل دید‌های مجسم‌شده (Materialized View) بیاید، از آنجاییکه داده‌های داخل آن سطر اتمیک هستند، نیازی به نگرانی نیست.
که یا [همه‌اش] موفق می‌شود یا نمی‌شود. بقیه صحبت ما همه‌اش مربوط به پروژه Cassandra خواهد بود. در مورد ساختار Cassandra بعنوان یک پروژه متن‌باز صحبت کنید.
Cassandra، یک نمونه کاملاً موفق از پروژه‌های متن‌باز است. من اشاره کردم که وقتی کار روی Cassandra را آغاز کردم که در Rackspace کار می‌کردم. ما شروع کردیم که مهندسانی از توییتر و دگ بگیریم که بر روی آن کار کنند. الان بیش از ۱۰۰ نفر هستند که حداقل با یک Patch مشارکت داشته‌اند و کسانی که با گزارش دادن و کارهای دیگر، مشارکت داشته‌اند بیشتر هستند. به عنوان مثال Rackspace دنبال این نیست که یک چیز انحصاری بسازد. در حال حاضر، DataStax چندین نفر را بصورت تمام‌وقت بر روی آن گذاشته است. یک جامعه کاملاً سالم از افرادی از شرکت‌های مختلف هستند که به همراه هم بر روی آن کار می‌کنند.
آیا شما فهرست‌‌های نامه (Mailing List)، ویکی و چیزهای مشابه با آن دارید؟
ما فهرست‌های نامه‌ای برای کاربران، توسعه‌دهنده‌ها، توسعه‌دهنده‌های کلاینت‌ها و … داریم. شما در دنیای متن‌باز عموماً چنین چیزهایی را می‌بینید. در چند سال گذشته، پروژه‌ها به سمت تعاملات بلادرنگ (Real-time Communication) رفته‌اند و پروژه‌های جوان‌تر بر روی چیزهایی مانند IRC نسبت به فهرست نامه، تأکید بیشتری دارند. ما خیلی از توسعه‌های Cassandra را در کانال توسعه Cassandra در FreeNode انجام می‌دهیم. در واقع در IRC می‌توانید خیلی راحت در هر زمانی، راهنمایی‌های بلادرنگ بگیرید. همینطور یک فهرست نامه برای بحث‌های پیچیده‌تر و یا با تأخیرکم‌تر وجود دارد.
اگر افراد بخواهند در مورد این پروژه بیشتر بدانند کجا بروند؟
ابتدا به سایت cassanra.apache.org بروند. من به طور خاص صفحه‌ای که در مورد مقالات و ارائه‌ها هست را توصیه می‌کنیم که تعدادی مقالات باکیفیت در مورد Cassandra دارد.
در مورد شرکت‌تان، شرکت DataStax برایمان بگویید.
من DataStax را حدود ۸ ماه پیش آغاز کردم، ما نام آن را Riptano گذاشته بودیم، اما اسمش را عوض کردیم. ما محصولات حرفه‌ای و پشتیبانی ازCassandra داریم. ما بیش از ۵۰ مشتری را پشتیبانی می‌کنیم. خیلی خوب پیش رفته است. این هفته، ما پلتفرم مدیریت Cassandra خودمان با عنوان OpsCenter را معرفی می‌کنیم و شروع می‌کنیم که آن را به کاربران علاقه‌مند بدهیم.
آیا به شخصه جایی یا در بلاگی می‌نویسید؟
این روزها بیشتر بلاگ‌های خود را در وبلاگ DataStax می‌نویسم. نام من در توییتر به خاطر برخی دلایل تاریخی @spyced است.

مجتبی بنائی

دانشجوی دکترای نرم‌افزار دانشگاه تهران (yun.ir/smbanaie)، مدرس دانشگاه و فعال در حوزه توسعه نرم‌افزار و مهندسی داده که تمرکز کاری خود را در چند سال اخیر بر روی مطالعه و تحقیق در حوزه کلان‌داده و زیرساخت‌های پردازش داده و تولید محتوای تخصصی و کاربردی به زبان فارسی و انتشار آنها در سایت مهندسی داده گذاشته است. مدیریت پروژه‌های نرم‌افزاری و طراحی سامانه‌های مقیاس‌پذیر اطلاعاتی از دیگر فعالیتهای صورت گرفته ایشان در چند سال گذشته است.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

جای خالی در معادله زیر را با کی برد انگلیسی وارد کنید : * Time limit is exhausted. Please reload CAPTCHA.

این سایت از اکیسمت برای کاهش هرزنامه استفاده می کند. بیاموزید که چگونه اطلاعات دیدگاه های شما پردازش می‌شوند.

دکمه بازگشت به بالا