چندی پیش یکی از خوانندگان سایت مهندسی داده با نام کاوه، سوالی را در خصوص انتخاب بانک اطلاعاتی مناسب برای طراحی یک سامانه شبکه اجتماعی مطرح کرد که با توجه به نکات خوبی که در این پرسش و پاسخ مبادله شد تصمیم گرفتم که مطالب آنرا برای علاقه مندان به عنوان یک نوشتار جداگانه در سایت قرار دهم.
کاوه :
من یک برنامه نویس وب هستم.
مدتی است که با سایت شما در حوزهی کلان داده آشنا شدهام و مطالب آن را دنبال میکنم.
همچنین یک پروژهی Social Media در دست ایجاد دارم که در خصوص نگهداری اطلاعات در دیتابیسهای NoSQL در حال تحقیق و بررسی هستم.
با بررسیهای اولیهی انجام شده و با توجه به اینکه ماهیت کار شبیه Facebook و Instagram است، پایگاه دادهی Cassandra را انتخاب کردم.
فرض کنیم که در سیستم ما مفاهیم User, Post و Tag وجود داشته باشد. هر User تعدادی User دیگر را به عنوان Friend انتخاب میکند. هر User تعدادی Post ارسال میکند و هر User تعدادی Tag روی برخی از پستها میگذارد. هر Post تعدادی Tag دارد و بالعکس، هر Tag نیز تعدادی Post دارد.
اگر بخواهیم با نگاه کاساندرا پایگاه داده را طراحی کنیم، باید یک Column Family به نام UserFriends داشته باشیم، یک Column Family به نام UserPosts، یکی به نام PostTags و یکی هم به نام TagPosts.
در UserFriends، به ازای هر User در هر سطر با کلید سطر UserId، دوستان آن User در ستونها نگهداری میشود.
در UserPosts، به ازای هر User در هر سطر با کلید سطر UserId، مطالب ارسالی آن User در ستونها نگهداری میشود.
در PostTags، به ازای هر Post در هر سطر با کلید سطر PostId، تگهای آن Post در ستونها نگهداری میشود.
در TagPosts، به ازای هر Tag در هر سطر با کلید سطر TagName، مطالب ارسالی مرتبط با آن Tag در ستونها نگهداری میشود.
سوال اول این است که آیا به این ترتیب، ذخیرهی یک نوع داده (مانند Post یا Tag) در چند Column Family صحیح است؟
سوال دوم این است که در هر ستون چه اطلاعاتی از آن Entity باید نگهداری شود؟ یعنی آیا در UserFriends، نگهداری Id ی User هایی که دوست یک User هستند کفایت میکند یا اینکه باید کل اطلاعات هر User را نگهداری کرد و Column Family های عنوان شده را به Super Column تبدیل نمود؟
سوال سوم اینکه اگر پاسخ سوال دوم این باشد که نگهداری میزان اطلاعات در هر Column Family وابسته به نحوهی نمایش اطلاعات در Application باشد و ما اطلاعاتی را از هر Entity نگه بداریم که در Application به نمایش آن احتیاج داریم، اگر قرار باشد Application در مسیر توسعه نحوهی نمایش اطلاعات را تغییر بدهد، این تغییرات در پایگاه داده بسیار عظیم و زمانبر خواهد بود. در این حالت چه باید کرد؟ مثلاً فرض کنید در قسمتی که قرار است لیست دوستان یک کاربر را نمایش دهیم، در یک نسخه تنها نام دوستان را نمایش دهیم، اما در نسخهی بعدی به این نتیجه برسیم که اگر نام کاربر را به پروفایلش لینک کنیم بهتر است و در پایگاه داده کاساندرا، در Column Family ی UserFriends به ازای هر User، آدرس پروفایل کاربر را نداشته باشیم، چگونه میتوان این تغییر را به وجود آورد و پایگاه داده را به سرعت به روز رسانی کرد؟ ضمن اینکه ممکن است در حالتهای دیگر، ناچار باشیم با توجه به نحوهی نگهداری اطلاعات در کاساندرا، چندین Column Family را Update کنیم.
ممنون میشوم اگر اطلاعات خود را در اختیار بنده قرار داده و کمکم کنید.
با تشکر
کاوه
مهندسی داده :
از توضیحاتتان متوجه شدم که تا حدود بسیار زیادی مدلسازی داده با کاساندرا را مسلط شده اید که جای تبریک دارد .
توصیه من این است که به دلیل ماهیت روابط مختلف و دایره واری که موجودیتهای شما دارند دیتابیس های گراف محور مثل
Neo4j یا Orientdb
را که گزینه های مناسبی برای کار شما به نظر می رسند را نیز بررسی کنید.
و اما سوالات شما .
۱.مدلسازی شما کاملا درست انجام شده است .
۲. توصیه من ذخیره حداقلی داده ها در حد آی دی ها و نهایتا یکی دو فیلد دیگر مانند صد کاراکتر اول پست و تاریخ آن است که برای نمایش اولیه یک پست نیاز به مراجعه به دیتابیس تا حد امکان نباشد. اما اگر این اطلاعات زیاد باشد بهتر است آی دی ها را ذخیره کنید و با درخواستهای بعدی نیاز اطلاعاتیتان را برآورده کنید .
۳. آپدیت زمانبر خواهد بود و بسته به حجم داده و حجمفعلی و میزان توزیع شدگی کاساندرا دارد که در حقبقت ساختن مجدد سطرها خواهد بود . تخمین دقبقی ازین بخش ندارم .
موفق باشید
کاوه :
بنده نیز به این جمع بندی رسیده بودم که بهترین گزینه Graph Database ها هستند، زیرا با استفاده از Column Oriented Database ها، اطلاعات باید در جاهای مختلفی به صورت تکراری ذخیره شود که چندان خوشایند نیست.
به نظر میرسد Column Oriented Database ها فقط برای دریافت اطلاعات بخشی از application با سرعت بسیار بالا مناسب هستند و میتوان آنها را به denormalize کردن جداول در یک جدول در دیتابیسهای رابطهای تشبیه کرد.
اما مشکلی که در خصوص Graph Database ها وجود دارد این است که نسخهی Enterprise دیتابیسهای معروف در این زمینه Commercial هستند و تعداد زیادی Database به صورت Open Source وجود دارد که به علت عدم شهرت و عدم استقبال توسط کمپانیهای بزرگ، اعتبار آنها مورد تردید است.
آیا دیتابیس معتبر Open Source ای که نسخهی Enterprise آن نیز رایگان باشد وجود دارد؟
مهندسی داده :
با تحلیلتون موافقم . ما هم یک سری مشکلاتی که با Neo4j داشتیم سر مجوز استفاده تجاریش بود.
موفق باشید .
پی نوشت :
استفاده از بانکهای اطلاعاتی سطر گسترده برای جاهایی که ماهیت روابط پیچیده است و وابستگی زیادی بین داده ها وجود دارد مشابه مثال فوق، چندان توصیه نمی شود. مگر برای افزایش سرعت و کارآیی بخشی از کار. مثلا برای ذخیره دوستان و پستها و برچسبها از یک بانک اطلاعاتی رابطه ای استفاده شود و برای داشبورد یک کاربر که قرار است آخرین پستهای دوستانش را نمایش دهد، کاساندرا یا معادل آن به کار رود.
یعنی یک جدول در کاساندرا ایجاد کنیم با نام FriendPosts که کلید آن نام یک کاربر و داده های آن هم پستهای دوستان آن کاربر باشد و به ازای هر پست، یک ستون به سطر دوستان آن شخص اضافه شود که اطلاعات پست در آن باشد. به این ترتیب با لاگین کردن هر کاربر ، از این جدول اطلاعات اصلی پستهای اخیر به راحتی از کاساندرا خوانده و نمایش داده میشود و نهایتا برای نمایش اطلاعات نویسنده پست ، از بانک اطلاعاتی رابطه ای استفاده می کنیم.
همچنین به ازای هر تگ هم می توان یک جدول در کاساندرا ایجاد کرد که به ازای تک تک برچسبهای یک پست، یک ستون به این جدول اضافه شود که کلید آن هم خود تگ و ستونهای آن هم شماره شناسایی پست و صد کاراکتر اول و نویسنده آن باشد . به این ترتیب با کلیک بر روی هر برچسب، به سرعت آخرین مطالب مرتبط با آن یافت خواهد شد.
نکته : در شکل فوق، در جدول دوم که مطالب دوستان یک کاربر ذخیره می شود، از تاریخ استفاده نکرده ایم چون خود شناسه هر مطلب بر حسب timeuuid تولید می شود که یک شناسه متغیر با زمان و تصاعدی است که باعث میشود مطالب به ترتیب ذخیره شوند (البته باید ترتیب ذخیره سازی را هنگام ایجاد جدول، نزولی تعیین کنیم.)
راه حل دوم ، استفاده از بانکهای اطلاعاتی گراف محور است که به دلایل مختلف استفاده از آنها حداقل در ایران کمتر نهادینه شده است و امیدوارم دوستانی که تجربیاتی در این خصوص دارند با سایر علاقه مندان به اشتراک بگذارند.
مشکل اصلی ما کاربران تازه وارد در NoSQL پیدا کردن ساختار مناسب در پایگاه داده هست. مثلا اینکه باید بدونیم کاساندرا با شیوه ای که داده ها را ذخیره میکنه برای ساخت یه سیستم وبلاگ دهی یا شبکه اجتماعی چطوری میتونه به ما کمک کنه تا ما برتری اون را نسبت به SQL ببینیم؟
ما در SQL یکسری جداول برای پست ها و نظرات و تگ ها و دسته بندی ها درست میکنیم و بعد از اون اطلاعات یکبار ذخیره میشن و جداول مختلفت به وسیله فیلد ها و یا جداول اضافه به هم ربط پیدا میکنند.
فکر میکنم اگر بتونیم درک کاملی از شیوه ذخیره سازی داده ها در NoSQL و ارتباط هایی که دیتابیس بین داده ها میسازه داشته باشیم میتونیم خیلی ساده تر به طراحی دیتابیس در این مدل بپردازیم.
باید قبل از هر چیزی با نمونه های عملی آشنا بشیم تا شیوه های تحلیل بانک های اطلاعاتی در NoSQL را بشناسیم.
با سلام
چرا mongoDB توصیه نمی کنید؟
مهندسی داده :
کاربردهایی مثل تلگرام باید مقیاس پذیری بالا و سرعت لحظه ای داشته باشند که طبق تجربه قبلی با مانگو ، نگران این دو مساله هستم (هر چند با نسخه ۳ مانگو کار نکرده ام و شاید این مسائل ، کمرنگ تر شده باشد .)
از طرفی در سامانه های نوین امروزی ، یک دیتابیس یا راه حل برای همه بخش ها ، کاربرد نخواهد داشت و برای هر بخش بهتر است از ابزار و بانکها و کتابخانه های خاص منظوره استفاده کرد .
چند هفته است که داریم تحقیق می کنیم و تا الان مناسب ترین سیستم پایگاه داده برای سرعت و مقیاس پذیری کاساندرا بوده. هیچ یک از پایگاه داده های گراف محور توانایی real time بودن در مقیاس بزرگ رو ندارن. مثلا neo4j که sharding رو ساپورت نمی کنه و این یک ضعف بسیار بزرگی هست. ما یک voice chat با neo4j داشتیم و در مورد مقیاس پذیری سوالاتی پرسیدیم و گفتند که مشتریانشان دیتابیس بزرگتر از ۲۰۰ گیگابایت نداشتند. با ۱۵۰ میلیود گره در این دیتابیس به حجم ۳۵ گیگابایت رسیدیم!
با شما موافقم هر چند مدلسازی تمام داده ها در کاساندرا مناسب نخواهد بود. الاستیک سرچ را هم حتماْ امتحان کنید سرعت آن شما را شگفت زده خواهد کرد و مشکلات مقیاس پذیری هم ندارد .
به نظرم ترکیب پستگرس و کاساندرا و الاستیک سرچ می تواند یک راه حل مناسب و جامع و با نگاه به آینده باشد.
البته خود زبان برنامه نویسی هم بسیار مهم است و نقش حیاتی را در کارآیی شما ایفا خواهد کرد.
در وهله اول، اسکالا و در جایگاه بعدي ، GO را پیشنهاد می کنم.
موفق باشید.
درست است که ماهیت دیتابیس های گراف محور مناسب معماری شبکه های اجتماعی می باشند ولی از پرفورمنس پایینی در حجم داده های بالا برخوردارند. مثلا neo4j در یک تست بنچمارک ساده مقابل mysql شکست خورد. البته این بنچمارک قطعی و خیلی دقیق نیست.
داده های ما ۱۵۰ میلیون گره بدون اضافه کردن edge بود.
http://stackoverflow.com/questions/37378607/in-my-tests-ne4j-seems-so-slow-compared-to-mysql-how-can-i-make-it-faster
خیلی درگیر این تست ها نباشید.
Neo4j دیتابیس آینده داری هست.