Кога да се използва базирана на CRDT база данни

Рошан Кумар е старши продуктов мениджър в Redis Labs.

Огъването на последователността и наличността, както е описано от теоремата за ОСП, е голямо предизвикателство за архитектите на георазпределените приложения. Мрежовият дял е неизбежен. Високата латентност между центровете за данни винаги води до известно прекъсване на връзката между центровете за данни за кратък период от време. По този начин традиционните архитектури за георазпределени приложения са предназначени или да се откажат от последователността на данните, или да ударят наличността.

За съжаление не можете да си позволите да жертвате наличността за интерактивни потребителски приложения. В последно време архитектите са направили опит за последователност и са възприели евентуалния модел на последователност. В този модел приложенията зависят от системата за управление на базата данни, за да обединят всички локални копия на данните, за да ги направят в крайна сметка последователни.

Всичко изглежда добре с евентуалния модел на последователност, докато не възникнат конфликти на данни. Няколко евентуални модела на последователност обещават най-добрите усилия за разрешаване на конфликтите, но не успяват да гарантират силна последователност. Добрата новина е, че моделите, изградени около реплицирани типове данни без конфликти (CRDT), осигуряват силна евентуална последователност.

CRDT постигат силна евентуална последователност чрез предварително определен набор от правила за разрешаване на конфликти и семантика. Приложенията, изградени върху базирани на CRDT бази данни, трябва да бъдат проектирани така, че да отговарят на семантиката за разрешаване на конфликти. В тази статия ще проучим как да проектираме, разработваме и тестваме георазпределени приложения, използвайки CRDT-базирана база данни. Също така ще разгледаме четири примерни случая на използване: броячи, разпределено кеширане, споделени сесии и поглъщане на данни за много региони.

Моят работодател, Redis Labs, наскоро обяви CRDT поддръжка в Redis Enterprise, като реплицирани типове данни без конфликти се присъединиха към богатото портфолио от структури от данни - низове, хешове, списъци, набори, сортирани набори, битови полета, гео, хиперлоглог и потоци - в нашата база данни продукт. Следващата дискусия обаче се отнася не само за Redis Enterprise, но и за всички базирани на CRDT бази данни.

Бази данни за георазпределени приложения

За георазпределените приложения е обичайно да се изпълняват услуги, локални за клиентите. Това намалява мрежовия трафик и латентността, причинена от обратното пътуване. В много случаи архитектите проектират услугите, за да се свържат с локална база данни. След това идва въпросът как поддържате последователни данни във всички бази данни. Единият вариант е да се справите с това на ниво приложение - можете да напишете периодичен процес на работа, който ще синхронизира всички бази данни. Или можете да разчитате на база данни, която ще синхронизира данните между базите данни.

В останалата част на статията предполагаме, че ще се придържате към втората опция - нека базата данни свърши работата. Както е показано на фигура 1 по-долу, вашето георазпределено приложение изпълнява услуги в множество региони, като всяка услуга се свързва с локална база данни. Основната система за управление на база данни синхронизира данните между базите данни, разположени в регионите.

Redis Labs

Модели на последователност на данните

Моделът на съгласуваност е договор между разпределената база данни и приложението, който определя колко чисти са данните между операциите за запис и четене.

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

Силна последователност

Двуфазното фиксиране е често срещана техника за постигане на силна последователност. Тук, за всяка операция на запис (добавяне, актуализиране, изтриване) в локален възел на базата данни, възелът на базата данни разпространява промените във всички възли на базата данни и изчаква всички възли да потвърдят. След това локалният възел изпраща ангажимент към всички възли и чака друго потвърждение. Приложението ще може да чете данните само след втория ангажимент. Разпределената база данни няма да бъде достъпна за операции по запис, когато мрежата прекъсне връзката между базите данни.

Евентуална последователност

Основното предимство на евентуалния модел на последователност е, че базата данни ще ви бъде достъпна за извършване на операции по запис, дори когато мрежовата свързаност между разпределените реплики на база данни се развали. Като цяло този модел избягва времето за двупосочно пътуване, направено от двуфазен ангажимент, и следователно поддържа много повече операции за запис в секунда от останалите модели. Един проблем, който евентуалната последователност трябва да разреши, е конфликтите - едновременното писане на един и същ елемент на две различни места. Въз основа на това как те избягват или разрешават конфликти, евентуално последователните бази данни се класифицират допълнително в следните категории:

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

    Недостатъкът на тази техника е, че тя приема, че всички системни часовници са синхронизирани. На практика е трудно и скъпо да синхронизирате всички системни часовници.

  2. Евентуална последователност на базата на кворума: Тази техника е подобна на двуфазовия ангажимент. Локалната база данни обаче не чака потвърждението от всички бази данни; просто чака потвърждението от по-голямата част от базите данни. Потвърждението от мнозинството създава кворум. Ако има конфликт, операцията по запис, която е установила кворума, печели.

    От друга страна, тази техника добавя мрежова латентност към операциите по запис, което прави приложението по-малко мащабируемо. Освен това локалната база данни няма да бъде достъпна за запис, ако се изолира от другите реплики на базата данни в топологията.

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

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

  4. Реплициран тип данни без конфликти (CRDT): Ще научите подробно за CRDT в следващите няколко раздела. Накратко, базирани на CRDT бази данни поддържат типове данни и операции, които осигуряват безконфликтна евентуална последователност. Базите данни на базата на CRDT са налични, дори когато разпределените реплики на бази данни не могат да обменят данните. Те винаги доставят локална латентност на операциите за четене и запис.

    Ограничения? Не всички случаи на използване на база данни се възползват от CRDT. Също така семантиката за разрешаване на конфликти за бази данни, базирани на CRDT, е предварително дефинирана и не може да бъде заменена.

Какво представляват CRDT?

CRDT са специални типове данни, които обединяват данни от всички реплики на база данни. Популярните CRDT са G-броячи (броячи само за растеж), PN-броячи (положително-отрицателни броячи), регистри, G-комплекти (само нарастващи комплекти), 2P-комплекти (двуфазни комплекти), OR-комплекти наблюдава-премахва набори) и др. Зад кулисите те разчитат на следните математически свойства за сближаване на данните:

  1. Комутативно свойство: a ☆ b = b ☆ a
  2. Асоциативно свойство: a ☆ (b ☆ c) = (a ☆ b) ☆ c
  3. Идемпотентност:  a ☆ a = a

G-броячът е идеален пример за работещ CRDT, който обединява операциите. Тук a + b = b + a и a + (b + c) = (a + b) + c. Репликите обменят само актуализациите (допълненията) помежду си. CRDT ще обедини актуализациите, като ги добави. G-набор, например, прилага идемпотентност ({a, b, c} U {c} = {a, b, c}), за да обедини всички елементи. Idempotence избягва дублирането на елементи, добавени към структурата на данните, докато те се движат и сближават по различни пътища.

CRDT типове данни и тяхната семантика за разрешаване на конфликти

Безконфликтни структури от данни: G-броячи, PN-броячи, G-комплекти

Всички тези структури от данни са без конфликти по дизайн. Таблиците по-долу показват как данните се синхронизират между репликите на базата данни.

Лаборатории Редис Лаборатории Редис

G-броячите и PN-броячите са популярни за случаи на употреба като глобално анкетиране, преброяване на потоци, проследяване на активността и т.н. G-наборите се използват широко за внедряване на блокчейн технология. Биткойните например използват само добавени блокчейн записи.

Регистри: Струни, Хешове

По своята същност регистрите не са безконфликтни. Те обикновено следват политиките на LWW или базирано на кворум разрешаване на конфликти. Фигура 4 показва пример за това как регистърът разрешава конфликта, следвайки политиката за LWW.

Redis Labs

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

2P-комплекти

Двуфазните комплекти поддържат два комплекта G-комплекти - един за добавени елементи, а другият за премахнати елементи. Репликите обменят добавките от G-set, когато се синхронизират. Конфликт възниква, когато се намери един и същ елемент и в двата набора. В някои базирани на CRDT бази данни, като Redis Enterprise, това се обработва от политиката „Добавяне на победи над изтриването“.

Redis Labs

Наборът 2P е добра структура от данни за съхраняване на споделени данни за сесии като колички за пазаруване, споделен документ или електронна таблица.

Как да създадете приложение за използване на база данни, базирана на CRDT

Свързването на вашето приложение с базирана на CRDT база данни не се различава от свързването на вашето приложение с друга база данни. Въпреки това, поради евентуалните политики за последователност, вашето приложение трябва да следва определен набор от правила, за да осигури последователно потребителско изживяване. Три ключа: 

  1. Направете приложението си без гражданство. Приложение без гражданство обикновено се управлява от API. Всяко извикване на API води до възстановяване на пълното съобщение от нулата. Това гарантира, че винаги извличате чисто копие на данни по всяко време. Ниската локална латентност, предлагана от базирана на CRDT база данни, прави възстановяването на съобщенията по-бързо и лесно. 

  2. Изберете правилния CRDT, който отговаря на вашия случай на употреба. Броячът е най-простият от CRDT. Може да се прилага за случаи на употреба като гласуване в глобален мащаб, проследяване на активни сесии, измерване и др. Ако обаче искате да обедините състоянието на разпределените обекти, трябва да вземете предвид и други структури от данни. Например за приложение, което позволява на потребителите да редактират споделен документ, може да искате да запазите не само редакциите, но и реда, в който са извършени. В този случай запазването на редакциите в CRDT-базиран списък или структура от данни на опашка би било по-добро решение от съхраняването им в регистър. Важно е също така да разбирате семантиката за разрешаване на конфликти, налагана от CRDT, и че вашето решение отговаря на правилата.
  3. CRDT не е универсално решение. Въпреки че CRDT наистина е чудесен инструмент за много случаи на употреба, той може да не е най-добрият за всички случаи на употреба (ACID транзакции например). Базите данни, базирани на CRDT, обикновено се вписват добре в архитектурата на микроуслуги, където имате специална база данни за всяка микроуслуга.

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

Тестване на приложения с разпределена мулти-главна база данни

За да постигнете по-бързо излизане на пазара, препоръчваме да имате последователна настройка за разработка, тестване, постановка и производство. Освен всичко друго, това означава, че настройката ви за разработка и тестване трябва да има миниатюризиран модел на вашата разпределена база данни. Проверете дали вашата база данни на базата на CRDT е налична като контейнер на Docker или виртуален уред. Разположете репликите на вашата база данни в различни подмрежи, за да можете да симулирате настройка на свързан и изключен клъстер.

Тестването на приложения с разпределена мулти-главна база данни може да звучи сложно. Но през повечето време всичко, за което ще тествате, е последователност на данните и наличност на приложения в две ситуации: Когато разпределените бази данни са свързани и когато има мрежов дял между базите данни.

Чрез настройване на разпределена база данни с три възли във вашата среда за разработка можете да покриете (и дори да автоматизирате) повечето сценарии за тестване в модулното тестване. Ето основните насоки за тестване на вашите приложения: