معرفی GridStore: فروشگاه ارزش کلید سفارشی Qdrant

چرا موتور ذخیره سازی خودمان را ساختیم
پایگاه داده ها به مکانی برای ذخیره و بازیابی داده ها نیاز دارند. این چیزی است که Qdrant's ذخیره ارزش کلیدی آیا این کلیدها را به مقادیر پیوند می دهد.
هنگامی که ما شروع به ساخت Qdrant کردیم ، باید چیزی را برای کار آماده کنیم. بنابراین ما انتخاب کردیم رفیق به عنوان فروشگاه ارزش کلیدی تعبیه شده ما.
با گذشت زمان ، ما به موضوعاتی رسیدیم. معماری آن به تراکم نیاز داشت (از LSMT استفاده می کند) ، که باعث افزایش سنبله های تأخیر تصادفی شده است. این کلیدهای عمومی را کنترل می کند ، در حالی که ما فقط از آن برای شناسه های متوالی استفاده می کنیم. داشتن گزینه های پیکربندی زیادی باعث می شود همه کاره باشد ، اما تنظیم دقیق آن سردرد بود. سرانجام ، تعامل با C ++ ما را کند کرد (اگرچه ما هنوز هم برای مدتی از آن پشتیبانی خواهیم کرد).
در حالی که در حال حاضر برخی از گزینه های خوب در Rust نوشته شده است که می توانیم از آن استفاده کنیم ، ما به چیزی عرف احتیاج داشتیم. هیچ چیز در آنجا متناسب با نیازهای ما به روشی که می خواستیم نیست. ما به کلیدهای عمومی احتیاج نداشتیم. ما می خواستیم کنترل کاملی بر زمان و کدام داده ها نوشته و گرگرفت. سیستم ما در حال حاضر مکانیسم های بازیابی تصادف داخلی را در خود جای داده است. تراکم آنلاین اولویت نیست ، ما در حال حاضر بهینه ساز داریم. اشکال زدایی سوء استفاده از سوء استفاده از زمان ما نبود.
بنابراین ما ذخیره سازی خودمان را ساختیم. از نظر نسخه Qdrant 1.13، ما از GridStore استفاده می کنیم انبارها و بردارهای پراکندهبشر
در این مقاله ، شما در مورد:
- چگونه GridStore کار می کند – شیرجه عمیق به معماری و مکانیک آن.
- چرا ما از این طریق آن را ساختیم – تصمیمات اصلی طراحی که آن را شکل داده است.
- تست دقیق -چگونه اطمینان حاصل کردیم که ذخیره سازی جدید آماده تولید است.
-
معیارهای عملکرد – معیارهای رسمی که کارآیی آن را نشان می دهد.
اولین چالش ما؟ فهمیدن بهترین راه برای رسیدگی به کلیدهای پی در پی و داده های با اندازه متغیر. ## معماری GridStore: سه مؤلفه اصلی
جزء | شرح |
---|---|
لایه داده ها | مقادیر را در بلوک های با اندازه ثابت ذخیره می کند و آنها را با استفاده از یک سیستم جستجوی مبتنی بر نشانگر برای دسترسی کارآمد بازیابی می کند. |
لایه ماسک | برای ردیابی استفاده از بلوک ، یک بیت ماسک را حفظ می کند ، و بین بلوک های اختصاص یافته و در دسترس تمایز قائل می شود. |
لایه شکاف | در دسترس بودن بلوک در سطح بالاتر ، بهینه سازی تخصیص فضا و استفاده مجدد. |
1. لایه داده برای بازیابی سریع
در هسته GridStore است لایه داده، که برای ذخیره و بازیابی مقادیر بر اساس کلیدهای آنها طراحی شده است. این لایه به ما امکان می دهد خواندن کارآمد را انجام دهیم و به ما اجازه می دهد داده های با اندازه متغیر را ذخیره کنیم. دو مؤلفه اصلی این لایه هستند ردیاب وت شبکه دادهبشر
از آنجا که شناسه های داخلی همیشه عدد صحیح متوالی هستند (0 ، 1 ، 2 ، 3 ، 4 ، …) ، ردیاب مجموعه ای از نشانگرهاست ، جایی که هر اشاره گر دقیقاً از کجا شروع می شود و چه مدت است.
لایه داده از مجموعه ای از نشانگرها برای بازیابی سریع داده ها استفاده می کند.
این باعث می شود جستجوی بسیار سریع باشد. به عنوان مثال ، پیدا کردن کلید 3 فقط موضوع پریدن به موقعیت سوم در ردیاب است و به دنبال نشانگر برای یافتن مقدار در شبکه داده است.
با این حال ، از آنجا که مقادیر از اندازه متغیر هستند ، داده ها به طور جداگانه در یک شبکه از بلوک های به اندازه ثابت ذخیره می شوند ، که در پرونده های صفحه بزرگتر گروه بندی می شوند. اندازه ثابت هر بلوک معمولاً 128 بایت است. هنگام قرار دادن یک مقدار ، GridStore یک یا چند بلوک متوالی را برای ذخیره آن اختصاص می دهد ، و اطمینان می دهد که هر بلوک فقط داده ها را از یک مقدار واحد نگه می دارد.
2. لایه ماسک از فضا استفاده می کند
لایه ماسک به GridStore کمک می کند تا بدون نیاز به تراکم داده های گران قیمت ، به روزرسانی ها و حذف ها را انجام دهند. به جای حفظ ابرداده های پیچیده برای هر بلوک ، GridStore استفاده از استفاده از bitmask ، که در آن هر بیت یک بلوک را نشان می دهد ، با 1 مورد استفاده ، 0 به صورت رایگان.
Bitmask به طور موثر استفاده از بلوک را ردیابی می کند.
این امر می توان تعیین کرد که در کجا می توان مقادیر جدید را نوشت. هنگامی که یک مقدار حذف می شود ، در نشانگر آن نرم می شود و بلوک های مربوطه در bitmask به صورت موجود مشخص می شوند. به همین ترتیب ، هنگام به روزرسانی یک مقدار ، نسخه جدید در جای دیگر نوشته شده است ، و بلوک های قدیمی در Bitmask آزاد می شوند.
این رویکرد تضمین می کند که GridStore فضا را هدر نمی دهد. با رشد ذخیره سازی ، با این حال ، اسکن برای بلوک های موجود در کل bitmask می تواند از نظر محاسباتی گران شود.
3. لایه شکاف برای به روزرسانی های مؤثر
برای بهینه سازی بیشتر به روزرسانی ، GridStore معرفی می کند لایه شکاف، که نمای سطح بالاتری از در دسترس بودن بلوک را فراهم می کند.
به جای اسکن کل بیت ماسک ، GridStore Bitmask را به مناطق تقسیم می کند و بزرگترین فضای آزاد متناسب در هر منطقه را دنبال می کند ، معروف به شکاف منطقهبشر همچنین با ذخیره شکافهای پیشرو و پیشرو در هر منطقه ، سیستم می تواند در صورت نیاز برای ذخیره مقادیر بزرگ ، چندین منطقه را ترکیب کند.
معماری کامل GridStore
این رویکرد لایه بندی شده به GridStore اجازه می دهد تا فضای موجود را به سرعت پیدا کند و کار مورد نیاز برای اسکن ها را در حالی که حافظه را حداقل نگه می دارد ، کاهش می دهد. با استفاده از این سیستم ، یافتن فضای ذخیره سازی برای مقادیر جدید ، نیاز به اسکن تنها بخش کوچکی از کل ابرداده ، به روزرسانی ها و درج های بسیار کارآمد ، حتی در بخش های بزرگ است.
با توجه به پیکربندی پیش فرض ، لایه GAPS در یک بخش میلیونی از اندازه واقعی ذخیره سازی قرار گرفته است. این بدان معنی است که برای هر 1 گیگابایت داده ، لایه شکاف فقط به اسکن 6 کیلوبایت ابرداده نیاز دارد. با استفاده از این مکانیسم ، سایر عملیات می توانند در پیچیدگی تقریباً ثابت اجرا شوند.
شبکه در تولید: حفظ یکپارچگی داده
معماری GridStore چندین ساختار وابسته به یکدیگر را معرفی می کند که برای اطمینان از یکپارچگی داده ها باید در همگام سازی باقی بمانند:
- لایه داده داده ها را نگه می دارد و هر کلید را با مکان خود در ذخیره سازی ، از جمله شناسه صفحه ، افست بلوک و اندازه مقدار آن مرتبط می کند.
- لایه ماسک پیگیری می کند که کدام بلوک ها اشغال شده و رایگان هستند.
- لایه شکاف نمای ایندکس از بلوک های رایگان برای تخصیص فضای کارآمد ارائه می دهد. هر بار که یک مقدار جدید وارد می شود یا مقدار موجود به روز می شود ، تمام این مؤلفه ها باید به روشی هماهنگ اصلاح شوند.
وقتی اوضاع در زندگی واقعی شکسته می شود
سیستم های دنیای واقعی در خلاء کار نمی کنند. خرابی ها اتفاق می افتد: اشکالات نرم افزاری باعث خرابی های غیر منتظره ، فرآیندهای فرسودگی حافظه می شود ، فرایندهای خاتمه یافته ، دیسک ها نتوانند داده ها را به طور قابل اعتماد ادامه دهند و ضرر و زیان برق می تواند هر لحظه عملیات را قطع کند.
سوال مهم این است: اگر هنگام بروزرسانی این ساختارها ، خرابی رخ دهد ، چه اتفاقی می افتد؟
اگر یکی از مؤلفه ها به روز شود اما دیگری نیست ، کل سیستم می تواند متناقض شود. بدتر ، اگر عملیاتی فقط تا حدی برای دیسک نوشته شود ، می تواند منجر به داده های یتیم ، فضای غیرقابل استفاده یا حتی فساد داده شود.
ثبات از طریق idempotency: بهبودی با وال
برای محافظت در برابر این خطرات ، Qdrant به یک متکی است ورود به سیستم نوشتن (WAL)بشر قبل از انجام عملیات ، Qdrant تضمین می کند که حداقل در وال ثبت شده است. اگر یک تصادف قبل از شستشوی همه به روزرسانی ها اتفاق بیفتد ، سیستم می تواند با خیال راحت عملیات را از ورود به سیستم پخش کند.
این مکانیسم بازیابی خاصیت اساسی دیگری را معرفی می کند: عجیبیبشر
سیستم ذخیره سازی باید به گونه ای طراحی شود که با استفاده مجدد از همان عملیات پس از خرابی منجر به همان حالت نهایی شود که گویی این عملیات فقط یک بار اعمال شده است.
راه حل بزرگ: به روزرسانی های تنبل
برای رسیدن به این هدف ، GridStore به روزرسانی های تنبل را تکمیل می کند، اولویت بندی مهمترین قسمت نوشتن: خود داده ها.
👉 به جای اینکه بلافاصله تمام ساختارهای ابرداده را به روز کنید ، ابتدا مقدار جدید را می نویسد در حالی که سبک وزن در انتظار تغییر در یک بافر را حفظ می کند.
👉 سیستم فقط در صورت درخواست صریح ، این به روزرسانی ها را نهایی می کند ، و اطمینان می دهد که یک تصادف هرگز منجر به علامت گذاری داده ها به عنوان حذف شده قبل از به روزرسانی با اطمینان می شود.
👉 در سناریوی بدترین حالت ، GridStore ممکن است نیاز به نوشتن همان داده ها دو بار داشته باشد ، که منجر به یک فضای جزئی در بالای سر می شود ، اما هرگز با رونویسی از داده های معتبر ، ذخیره سازی را خراب نمی کند.
چگونه محصول نهایی را آزمایش کردیم
اول … تست مدل
GridStore را می توان با استفاده از تست مدل ، به طور مؤثر آزمایش کرد ، که رفتار آن را با یک نقشه هش در حافظه ساده مقایسه می کند. از آنجا که GridStore باید مانند نقشه هش پایدار عمل کند ، این روش به سرعت ناسازگاری ها را تشخیص می دهد.
این روند ساده است:
- یک نمونه GridStore و یک نقشه هش خالی را آغاز کنید.
- عملیات تصادفی را اجرا کنید (قرار دهید ، حذف کنید ، بروزرسانی کنید) در هر دو.
- تأیید کنید که نتایج پس از هر عمل مطابقت دارد.
- تمام کلیدها و مقادیر را برای اطمینان از قوام مقایسه کنید. این رویکرد پوشش تست بالایی را فراهم می کند ، و موضوعاتی مانند پایداری نادرست یا حذف معیوب را در معرض نمایش قرار می دهد. اجرای تست های مدل در مقیاس بزرگ تضمین می کند که GridStore در استفاده در دنیای واقعی قابل اعتماد است. در اینجا یک روش ساده لوحانه برای تولید عملیات در زنگ زدگی وجود دارد.
enum Operation {
Put(PointOffset, Payload),
Delete(PointOffset),
Update(PointOffset, Payload),
}
impl Operation {
fn random(rng: &mut impl Rng, max_point_offset: u32) -> Self {
let point_offset = rng.random_range(0..=max_point_offset);
let operation = rng.gen_range(0..3);
match operation {
0 => {
let size_factor = rng.random_range(1..10);
let payload = random_payload(rng, size_factor);
Operation::Put(point_offset, payload)
}
1 => Operation::Delete(point_offset),
2 => {
let size_factor = rng.random_range(1..10);
let payload = random_payload(rng, size_factor);
Operation::Update(point_offset, payload)
}
_ => unreachable!(),
}
}
}
تست مدل روشی با ارزش بالا برای گرفتن اشکالات است ، به خصوص هنگامی که سیستم شما از یک جزء خوب تعریف شده مانند نقشه هش تقلید می کند. اگر مؤلفه شما مانند یک مورد دیگر رفتار می کند ، استفاده از تست مدل ارزش زیادی را برای کمی تلاش به ارمغان می آورد.
ما می توانستیم در برابر RocksDB آزمایش کنیم ، اما سادگی بیشتر اهمیت دارد. یک نقشه ساده هش به ما امکان می دهد توالی های تست عظیم را به سرعت اجرا کنیم و سریعتر مسائل را در معرض دید قرار دهیم.
حتی برای اشکال زدایی واضح تر ، آزمایش مبتنی بر خاصیت باعث ایجاد تست خودکار و کوچک شدن می شود. این خرابی ها را با موارد آزمایش حداقل مشخص می کند و شکار اشکال را سریعتر و مؤثرتر می کند.
آزمایش تصادف: آیا GridStore می تواند فشار را تحمل کند؟
طراحی برای مقاومت در برابر تصادف یک چیز است و اثبات آن که تحت استرس کار می کند چیز دیگری است. برای فشار دادن یکپارچگی داده Qdrant به حد مجاز ، ما ساختیم سقوط، یک نیمکت آزمایشی که به طرز وحشیانه ای Qdrant را می کشد و دوباره شروع می کند ، در حالی که یک بار کاری به روزرسانی سنگین را کنترل می کند.
Crasher حلقه ای را اجرا می کند که به طور مداوم داده ها را می نویسد ، سپس به طور تصادفی Qdrant را خراب می کند. در هر راه اندازی مجدد ، Qdrant دوباره تکرار می کند ورود به سیستم نوشتن (WAL)، و ما تأیید می کنیم که آیا یکپارچگی داده وجود دارد یا خیر. ناهنجاری های احتمالی عبارتند از:
- داده های گمشده (امتیاز ، بردارها یا بارهای بار)
- ارزش بارگذاری فاسد این رویکرد تهاجمی و در عین حال ساده ، هنگام اجرای دوره های طولانی ، مسائل دنیای واقعی را کشف کرده است. در حالی که ما همچنین از آزمایش هرج و مرج برای تنظیمات توزیع شده استفاده می کنیم ، Crasher در آزمایش سریع و قابل تکرار در یک محیط محلی ، برتری می یابد. ## تست عملکرد شبکه: معیارها
برای اندازه گیری تأثیر موتور ذخیره سازی جدید ما ، از آن استفاده کردیم شلوغی ، یک چارچوب معیار ذخیره سازی با ارزش کلیدی، برای مقایسه GridStore در برابر Rocksdb. ما سه بار کار را آزمایش کردیم:
نوع بار کار | توزیع عملیات |
---|---|
با ارزش خواندن | 95 ٪ می خواند |
سنگین | 80 ٪ درج |
سنگین | 50 ٪ به روزرسانی |
نتایج برای خودشان صحبت می کنند:
میانگین تأخیر برای انواع بارهای کاری در سراسر صفحه ، به ویژه برای درج ها ، پایین تر است.
این نشان دهنده افزایش روشنی در عملکرد است. همانطور که می بینیم ، سرمایه گذاری در GridStore در حال پرداخت است.
معیار پایان به پایان
حال ، بیایید تأثیر را در یک نمونه Qdrant واقعی آزمایش کنیم. تاکنون ، ما فقط یک شبکه یکپارچه را برای بارهای بارهای وت بردارهای پراکنده، اما حتی این سوئیچ جزئی باید پیشرفت های قابل توجهی را نشان دهد.
برای معیار ، ما از خانه خود استفاده کردیم ابزار BFB برای تولید بار کار. پیکربندی ما:
bfb -n 2000000 --max-id 1000000 \
--sparse-vectors 0.02 \
--set-payload \
--on-disk-payload \
--dim 1 \
--sparse-dim 5000 \
--bool-payloads \
--keywords 100 \
--float-payloads true \
--int-payloads 100000 \
--text-payloads \
--text-payload-length 512 \
--skip-field-indices \
--jsonl-updates ./rps.jsonl
این معیار 1 میلیون امتیاز دو بار صعود می کند. هر نقطه:
- یک بار متوسط تا بزرگ
- یک بردار متراکم کوچک (بردارهای متراکم از یک نوع ذخیره سازی متفاوت استفاده می کنند)
– یک بردار پراکنده
پیکربندی اضافی:
- آزمایشی که ما داده های بار به روز شده را به طور جداگانه در یک درخواست دیگر انجام دادیم.
- هیچ شاخص بارگذاری وجود ندارد ، که تضمین می کند سرعت مصرف خالص را اندازه گیری می کنیم.
سرانجام ، ما معیارهای تأخیر درخواست را برای تجزیه و تحلیل جمع آوری کردیم.
ما این کار را در برابر Qdrant 1.12.6 اجرا کردیم و بین پشتیبان های قدیمی و جدید ذخیره سازی قرار گرفتیم.
نتیجه نهایی
مصرف داده ها است دو برابر سریع و با توان نرم تر – یک پیروزی عظیم! 😍
ما برای سرعت بهینه شدیم و آن را پرداخت کردیم – اما در مورد اندازه ذخیره سازی چیست؟
- شبکه: 2333MB
- RocksDB: 2319MB به طور دقیق ، RocksDB کمی کوچکتر است ، اما تفاوت در مقایسه با مصرف سریعتر 2 برابر و توان پایدار است. یک تجارت کوچک برای کسب عملکرد بزرگ!
تلاش برای بیرون رفتن از GridStore
GridStore نشان دهنده پیشرفت قابل توجهی در نحوه مدیریت Qdrant است ذخیره ارزش کلیدی نیازها این عملکرد عالی و به روزرسانی های ساده متناسب با مورد استفاده ما را ارائه می دهد. ما موفق شده ایم ضمن حفظ یکپارچگی داده ها ، حتی تحت بارهای سنگین و خرابی های غیر منتظره ، سریعتر و قابل اطمینان تر از داده ها را نیز بدست آوریم. در حال حاضر به عنوان یک زمینه ذخیره سازی برای بارهای دیسک و بردارهای پراکنده استفاده می شود.
👉 توجه به این نکته حائز اهمیت است که GridStore با Qdrant کاملاً یکپارچه است و به همین ترتیب ، به عنوان یک جعبه مستقل آزاد نشده است.
API آن هنوز در حال تحول است ، و ما برای اطمینان از ثبات و عملکرد حداکثر ، بر پالایش آن در اکوسیستم خود متمرکز شده ایم. به گفته این ، ما ارزشی را که این نوآوری می تواند به جامعه گسترده تر زنگ زد ، تشخیص دادیم. در آینده ، پس از تثبیت API و ما آن را به اندازه کافی از Qdrant جدا می کنیم ، ما آن را به عنوان سهم در جامعه منتشر خواهیم کرد.
در حال حاضر ، GridStore همچنان به پیشرفت در QDrant ادامه می دهد و فواید یک موتور ذخیره سازی متناسب را نشان می دهد که با خواسته های مدرن در ذهن طراحی شده است. برای به روزرسانی های بیشتر و انتشار بالقوه جامعه در ارتباط باشید زیرا ما همچنان به مرزهای عملکرد و قابلیت اطمینان ادامه می دهیم.
ساده ، کارآمد و فقط برای Qdrant طراحی شده است.