Към съдържанието
wannacode

Как се избира база

Накратко: Базата се избира според данните и въпросите към тях: релационната база пази истината, а друг вид се добавя до нея само за въпроса, в който тя е слаба.

Проблем

Много видове бази на масата

Модулът показа key-value, документи, потоци от събития, графи, колони и времеви редове, търсене в текст, вектори и клъстери. Всяка от тези бази е отлична за нещо. Новият проект на магазина пита: коя да изберем?

Грешният начин е да тръгнеш от базата („ползваме MongoDB, защото е модерно“). Правилният е да тръгнеш от данните и от въпросите, които ще им задаваш, и да добавиш нова база чак когато има въпрос, на който основната не отговаря добре.

Идеята

Пет въпроса

  1. Каква е формата на данните? Редове с еднакви колони, цели документи с вложени части, връзки между нещата, записи по време, свободен текст.
  2. Какво питаш? Едно нещо по ключ, отчет върху всичко, „кой с кого е свързан“, „кои думи“, „кое е подобно“.
  3. Колко е важна консистентността? Пари и наличност искат транзакции и четене на последния запис. Брояч на харесвания може да закъснее с секунда.
  4. Колко са данните и натоварването? Хиляди или милиарди редове, десет или сто хиляди заявки в секунда. Повечето проекти са много по-малки, отколкото си мислят.
  5. Кой ще я поддържа? Всяка база иска копия, наблюдение, обновявания и човек, който знае какво прави, когато тя падне.
Въпросът Вид база
Пари, поръчки, наличност, всичко, което трябва да е вярно релационна (PostgreSQL, MySQL)
Едно и също по ключ хиляди пъти, сесии, колички key-value (Redis)
Цели обекти с различна структура документна (MongoDB) или JSONB
Много системи научават за едно и също събитие поток от събития (Kafka)
Препоръки, мрежи, измами през няколко стъпки графова (Neo4j)
Отчети върху милиони редове, сензори, метрики колонна, времеви редове (ClickHouse, TimescaleDB)
Поле за търсене, думи в текст пълнотекстово търсене (Elasticsearch)
„Подобно по смисъл“, чатбот върху документи векторна (pgvector, Qdrant)

Идеята

Започни с PostgreSQL

За повечето нови проекти разумното начало е една релационна база. PostgreSQL сама покрива голяма част от модула: JSONB колони за документи, tsvector за търсене в текст, pgvector за вектори, TimescaleDB за времеви редове, реплики за четене и разделяне на таблици по време. Не е най-добрата във всяко от тях, но е достатъчно добра, а една база е много по-лесна за поддръжка от пет.

Отделна база си струва, когато има конкретен въпрос, на който основната отговаря бавно или трудно, и си го измерил: кешът, защото една и съща заявка се пуска 2000 пъти в минута; търсачката, защото търсенето е главната работа на сайта; складът за данни, защото отчетите забавят касата.

По-точно, за любопитните

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

Виж го

Магазинът, когато порасне

Така може да изглежда магазинът след няколко години, като всяка част е дошла, когато е потрябвала:

  • PostgreSQL пази клиентите, продуктите, поръчките и плащанията. Това е истината. Има една синхронна и една асинхронна реплика.
  • Redis пази кеша на каталога, сесиите и количките.
  • Kafka носи събитията „поръчката е направена“, „платена“, „изпратена“ към склада, фактурите и пощата.
  • Elasticsearch държи копие на продуктите и отзивите за полето за търсене. Пълни се от събитията.
  • ClickHouse е складът за данни за отчетите. Пълни се всяка нощ или от потока.
  • pgvector в същата PostgreSQL дава „подобни продукти“.

Всички копия идват от PostgreSQL. Ако индексът в Elasticsearch се повреди, той се прави наново от базата. Обратното не е вярно.

Проблем

Двата записа

Поръчката се записва в PostgreSQL, а после програмата праща събитие в Kafka. Ако програмата падне между двете, поръчката е в базата, но събитието го няма: складът никога не приготвя пакета. Ако е обратното (първо събитието, после базата), складът може да приготви пакет за поръчка, която после се е провалила.

Двете системи нямат обща транзакция. Решението е outbox таблица: събитието се записва в таблица в същата база, в същата транзакция като поръчката. Или се записват и двете, или нито едно.

SQLбаза: магазин

published_at е NULL: събитието още не е пратено. Отделна програма (relay) чете непратените подред, праща ги в потока и чак после ги отбелязва:

SQLбаза: магазин

А ако нещо се провали преди COMMIT, няма нито промяна, нито събитие:

SQLбаза: магазин
По-точно, за любопитните

Програмата за препращане може да падне, след като е пратила събитието, но преди да го отбележи. Тогава при рестарта го праща пак. Затова потребителите на събитието трябва да са идемпотентни, като фактурите в урока за потоците. Вместо програма, която чете таблицата, често се ползва Debezium: той чете дневника на промените на PostgreSQL (WAL) и праща всеки нов ред от outbox в Kafka. Това се казва change data capture (CDC).

Пробвай

Отказ на поръчка

Клиентът отказва поръчка 42. В една транзакция смени статуса ѝ на cancelled и запиши в outbox събитие за темата orders с ключ order-42 и съдържание {"order":42,"event":"cancelled"}.

SQLбаза: магазин

Упражнение

Пет проекта

За всеки проект: коя база е основата или какво добавяш до нея?

1. Банка пази сметките и преводите между тях. Сборът от всички сметки никога не бива да се разминава. Какво е основата?
2. Приложение за доставки показва къде е куриерът. Всеки куриер праща координатите си на всеки 5 секунди, а графиката показва последния час. Какво пасва най-добре на тези данни?
3. Сайт за обяви иска „подобни обяви“ по текста и снимките, не по еднакви думи. Какво добавяш до основната база?
4. Платформа за обучение пази курсове с различна структура: глави, уроци, видеа, тестове, всички вложени и различни за всеки курс. Цял курс се чете и пише наведнъж. Кое пасва най-естествено?
5. Магазин с 300 поръчки на ден, един програмист и PostgreSQL. Шефът е чел, че големите ползват шардинг. Какво правиш?

Тест

Провери се

1. Програмата записва поръчката в PostgreSQL и после праща събитие в Kafka. Какво става, ако падне между двете?
2. Кое е вярно за всяка нова база в проекта?
3. Кешът в Redis, индексът в Elasticsearch и складът за данни имат копие на поръчките. Къде е истината?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·