Касандра. Как да не умрете, ако знаете само Oracle

Хей Хабр.

Казвам се Миша Бутримов, бих искал да ви разкажа малко за Касандра. Моята история ще бъде полезна за тези, които никога не са се сблъсквали с NoSQL бази данни - има много функции за внедряване и клопки, за които трябва да знаете. И ако не сте виждали нищо друго освен Oracle или друга релационна база данни, тези неща ще ви спасят живота.

Какво толкова хубаво има в Касандра? Това е NoSQL база данни, проектирана без нито една точка на отказ, която се мащабира добре. Ако трябва да добавите няколко терабайта за някаква база данни, просто добавяте възли към пръстена. Да го разширя ли до друг център за данни? Добавете възли към клъстера. Да се ​​увеличат ли обработените RPS? Добавете възли към клъстера. Работи и в обратна посока.

Касандра. Как да не умрете, ако знаете само Oracle

В какво друго е добра? Става дума за обработка на много заявки. Но колко е много? 10, 20, 30, 40 хиляди заявки в секунда не е много. 100 хиляди заявки в секунда за запис - също. Има компании, които казаха, че поддържат 2 милиона заявки в секунда. Вероятно ще трябва да повярват.

И по принцип Cassandra има една голяма разлика от релационните данни - тя изобщо не е подобна на тях. И това е много важно да запомните.

Не всичко, което изглежда еднакво, работи по същия начин

Веднъж един колега дойде при мен и ме попита: „Ето език за заявки CQL Cassandra и има оператор select, има where, има and. Пиша писма и не става. Защо?". Третирането на Cassandra като релационна база данни е идеалният начин за извършване на насилствено самоубийство. И аз не го рекламирам, това е забранено в Русия. Просто ще проектирате нещо грешно.

Например, клиент идва при нас и казва: „Нека изградим база данни за телевизионни сериали или база данни за директория с рецепти. Там ще имаме ястия с храна или списък с телевизионни сериали и актьори в тях. Казваме радостно: „Да вървим!“ Просто изпратете два байта, няколко знака и сте готови, всичко ще работи много бързо и надеждно. И всичко е наред, докато клиентите не идват и казват, че домакините решават и обратния проблем: имат списък с продукти и искат да знаят какво ястие искат да приготвят. Мъртъв си.

Това е така, защото Cassandra е хибридна база данни: тя едновременно предоставя ключова стойност и съхранява данни в широки колони. В Java или Kotlin може да се опише така:

Map<RowKey, SortedMap<ColumnKey, ColumnValue>>

Тоест карта, която съдържа и сортирана карта. Първият ключ към тази карта е клавишът Row или Partition key - ключът за разделяне. Вторият ключ, който е ключът към вече сортирана карта, е ключът за групиране.

За да илюстрираме разпределението на базата данни, нека начертаем три възела. Сега трябва да разберете как да разложите данните на възли. Защото, ако натъпчем всичко в едно (между другото може да са хиляда, две хиляди, пет - колкото искате), тук не става въпрос за разпределение. Следователно имаме нужда от математическа функция, която ще върне число. Просто число, дълго int, което ще попадне в някакъв диапазон. И ще имаме един възел, отговорен за един диапазон, вторият за втория, n-тият за n-тия.

Касандра. Как да не умрете, ако знаете само Oracle

Това число се взема с помощта на хеш функция, която се прилага към това, което наричаме ключ за разделяне. Това е колоната, която е посочена в директивата за първичен ключ и това е колоната, която ще бъде първият и най-основен ключ на картата. Той определя кой възел какви данни ще получи. В Cassandra се създава таблица с почти същия синтаксис като в SQL:

CREATE TABLE users (
	user_id uu id,
	name text,
	year int,
	salary float,
	PRIMARY KEY(user_id)

)

Първичният ключ в този случай се състои от една колона и също така е ключът за разделяне.

Как ще се представят нашите потребители? Някои ще отидат в един възел, други в друг, а трети в трети. Резултатът е обикновена хеш таблица, известна също като карта, известна също като речник в Python, или проста структура на стойност на ключ, от която можем да четем всички стойности, да четем и записваме по ключ.

Касандра. Как да не умрете, ако знаете само Oracle

Изберете: кога разрешаването на филтрирането се превръща в пълно сканиране или какво да не правите

Нека напишем някои оператори за избор: select * from users where, userid = . Получава се като в Oracle: пишем select, посочваме условията и всичко работи, потребителите го получават. Но ако изберете например потребител с определена година на раждане, Cassandra се оплаква, че не може да изпълни заявката. Тъй като тя не знае нищо за това как разпространяваме данните за годината на раждане - тя има само една колона, посочена като ключ. Тогава тя казва: „Добре, все още мога да изпълня тази молба. Добавяне на разрешено филтриране." Добавяме директивата, всичко работи. И в този момент се случва нещо ужасно.

Когато работим с тестови данни, всичко е наред. И когато изпълните заявка в производство, където имаме например 4 милиона записа, тогава всичко не е много добре за нас. Тъй като разрешаването на филтриране е директива, която позволява на Cassandra да събира всички данни от тази таблица от всички възли, всички центрове за данни (ако има много от тях в този клъстер) и едва след това да ги филтрира. Това е аналог на пълното сканиране и едва ли някой е възхитен от него.

Ако имахме нужда само от потребители по ID, щяхме да се справим с това. Но понякога трябва да напишем други заявки и да наложим други ограничения върху избора. Затова помним: всичко това е карта, която има ключ за разделяне, но вътре е сортирана карта.

И тя също има ключ, който наричаме Клъстерен ключ. Този ключ, който от своя страна се състои от избраните от нас колони, с помощта на които Cassandra разбира как нейните данни са физически сортирани и ще бъдат разположени на всеки възел. Тоест, за някакъв ключ за разделяне, ключът за групиране ще ви каже точно как да вкарате данните в това дърво, какво място ще заемат там.

Това наистина е дърво, там просто се извиква компаратор, към който предаваме определен набор от колони под формата на обект, и също така е посочен като списък от колони.

CREATE TABLE users_by_year_salary_id (
	user_id uuid,
	name text,
	year int,
	salary float,
	PRIMARY KEY((year), salary, user_id)

Обърнете внимание на директивата за първичен ключ; нейният първи аргумент (в нашия случай годината) винаги е Partition key. Може да се състои от една или повече колони, няма значение. Ако има няколко колони, тя трябва отново да бъде премахната в скоби, така че препроцесорът на езика да разбере, че това е първичният ключ, а зад него всички останали колони са ключът за клъстериране. В този случай те ще бъдат предадени в компаратора в реда, в който се появяват. Тоест, първата колона е по-значима, втората е по-малко значима и т.н. Как пишем, например, равни полета за класове данни: изброяваме полетата и за тях пишем кои са по-големи и кои по-малки. В Cassandra това са, относително казано, полетата от класа данни, към които ще се прилагат записаните за него равенства.

Задаваме сортиране и налагаме ограничения

Трябва да запомните, че редът на сортиране (низходящ, възходящ, какъвто и да е) се задава в същия момент, когато се създава ключът, и не може да бъде променен по-късно. Той физически определя как данните ще бъдат сортирани и как ще бъдат съхранявани. Ако трябва да промените ключа за групиране или реда на сортиране, ще трябва да създадете нова таблица и да прехвърлите данни в нея. Това няма да работи със съществуващ.

Касандра. Как да не умрете, ако знаете само Oracle

Напълнихме нашата таблица с потребители и видяхме, че те попадат в пръстен, първо по година на раждане, а след това вътре във всеки възел по заплата и потребителски идентификатор. Сега можем да избираме чрез налагане на ограничения.

Пак се появява нашата работеща where, and, получаваме потребители и всичко отново е наред. Но ако се опитаме да използваме само част от ключа за клъстериране и то по-малко значим, тогава Касандра веднага ще се оплаче, че не може да намери мястото в нашата карта, където този обект, който има тези полета за нулевия компаратор, и този това беше току-що зададено, - къде лежи. Ще трябва отново да изтегля всички данни от този възел и да ги филтрирам. И това е аналог на пълно сканиране в рамките на възел, това е лошо.

При всяка неясна ситуация създайте нова таблица

Ако искаме да можем да насочваме потребители по ID, или по възраст, или по заплата, какво трябва да направим? Нищо. Просто използвайте две таблици. Ако трябва да достигнете до потребителите по три различни начина, ще има три таблици. Отминаха дните, когато пестехме място на винта. Това е най-евтиният ресурс. Това струва много по-малко от времето за реакция, което може да бъде пагубно за потребителя. За потребителя е много по-приятно да получи нещо за секунда, отколкото за 10 минути.

Ние търгуваме с ненужно пространство и денормализирани данни за способността да мащабираме добре и да работим надеждно. В края на краищата, всъщност клъстер, който се състои от три центъра за данни, всеки от които има пет възела, с приемливо ниво на запазване на данните (когато нищо не се губи), е в състояние напълно да преживее смъртта на един център за данни. И още два възела във всеки от останалите два. И едва след това започват проблемите. Това е доста добро резервиране, струва си няколко допълнителни SSD устройства и процесори. Следователно, за да използвате Cassandra, която никога не е SQL, в която няма връзки, външни ключове, трябва да знаете прости правила.

Ние проектираме всичко според вашето желание. Основното нещо не са данните, а как приложението ще работи с тях. Ако трябва да получава различни данни по различни начини или едни и същи данни по различни начини, трябва да го поставим по начин, който е удобен за приложението. В противен случай ще се провалим при пълно сканиране и Cassandra няма да ни даде никакво предимство.

Денормализиране на данни е норма. Забравяме за нормалните форми, вече нямаме релационни бази данни. Ако сложим нещо 100 пъти, то ще лежи 100 пъти. Пак излиза по-евтино от спиране.

Избираме ключовете за разделяне, така че да се разпределят нормално. Не искаме хешът на нашите ключове да попада в един тесен диапазон. Тоест годината на раждане в горния пример е лош пример. По-точно, добре е, ако нашите потребители са нормално разпределени по години на раждане, и лошо, ако говорим за ученици от 5 клас - там разделението няма да е много добро.

Сортирането се избира веднъж на етапа на създаване на клъстерен ключ. Ако трябва да се промени, ще трябва да актуализираме нашата таблица с различен ключ.

И най-важното: ако трябва да извлечем едни и същи данни по 100 различни начина, тогава ще имаме 100 различни таблици.

Източник: www.habr.com

Добавяне на нов коментар